Skip to content

Instantly share code, notes, and snippets.

@shgeta
Last active December 14, 2023 11:55
Show Gist options
  • Save shgeta/f2501ab30fd8e10a5faf to your computer and use it in GitHub Desktop.
Save shgeta/f2501ab30fd8e10a5faf to your computer and use it in GitHub Desktop.
shell でバイナリを扱う。進数変換する。osx

shell でバイナリを扱う。進数変換する。osx

概要

shell でバイナリを扱う。進数変換する。 なるべく分かりやすい単純なコードで。

決め事

コードを単純にするために決め事を使う

  • hexの指定は大文字で 例 ok: 0A, FF, 1A ( ng: 0a, ff, fa )

進数変換

  • HEXの指定は大文字で
  • ibaseを先に指定したばあいは、obaseはその進数で
  • 桁数の大きいものを扱うときは、適宜 export BC_LINE_LENGTH="100000000000"などとする。そうしないとbcが勝手に適当に改行を入れる。

10進数 > 2進数の文字列

num=123
echo "obase=2;ibase=10;$num" | bc

2進数の文字列 > 10進数

bits="1010"
echo "obase=10;ibase=2;$bits" | bc

10進数 > 16進数の文字列

num=123
echo "obase=16;ibase=10;$num" | bc

16進数の文字列 > 10進数

hex="FF"
echo "obase=10;ibase=16;$hex" | bc

2進数の文字列 > 16進数の文字列

bits="1010"
echo "obase=16;ibase=2;$bits" | bc

16進数の文字列 > 2進数の文字列

hex="0A"
echo "obase=2;ibase=16;$hex" | bc

バイナリ出力

  • バイナリをパイプに通すときは注意。不安ならファイルに落とすこと。

1バイト

16進数の文字列(1バイト) > バイナリ

hex="A0"
printf "%b" "\x$hex"
#確認 printf "%b" "\x$hex" | od -tx1

10進数(256未満) > バイナリ

num="200"
printf "%b" "\x$(echo "obase=16;ibase=10;$num" | bc)"
#確認 printf "%b" "\x$(echo "obase=16;ibase=10;$num" | bc)" | od -tx1

0埋め パディング

fff > 0fff 16進数の文字列をバイト単位になるように0埋め

hex="aaa"
length_of_hex=${#hex}
if test $(expr $length_of_hex % 2 ) -eq 0
then
printf "$hex"
else
printf "0$hex"
fi
#if test $(expr $length_of_hex % 2 ) -eq 0; then printf "$hex"; else printf "0$hex"; fi

16進数の文字列をネットワークバイトオーダー(ひっくり返したりしないで)でバイナリ出力

バイト数指定

hex=FFF
size=4
hex_padded=$(printf "%0"$( expr $size "*" 2)"s" $hex)
(
for byte in $(echo $hex_padded | fold -w2 -b)
do
printf "%b" "\x$byte"
done
)

#| od -tx1

可変長 (最短のバイト数)

  • 「16進数の文字列をバイト単位になるように0埋め」及び上の「バイト数指定」の後半部分をfunctionにして使う。
function hex_string_padding ()
{
(
hex="$1"
length_of_hex=${#hex}
if test $(expr $length_of_hex % 2 ) -eq 0; then printf "$hex"; else printf "0$hex"; fi
)
}

function print_bin_padded_hex ()
{
( 
hex_padded="$1"
for byte in $(echo $hex_padded | fold -w2 -b); do printf "%b" "\x$byte"; done
)
}

hex=FFF
hex_padded=$(hex_string_padding $hex)
print_bin_padded_hex $hex_padded

バイナリ読み込み

  • バイナリをパイプに通すときは注意。不安ならファイルに落とすこと。

バイナリファイルから、頭、バイト数を指定して切り出し、16進数文字列へ (ネットワークバイトオーダー (何もしないで順番に) )

file_bin=/tmp/binfile
head=0
size=4
cat $file_bin | dd bs=1 skip=$head count=$size | od -An -tx1 | tr -d "\n "| dd conv=ucase

バイナリファイルから、頭、バイト数を指定して切り出し、10進数へ (ネットワークバイトオーダー (何もしないで順番に) )

file_bin=/tmp/binfile
head=0
size=4
hex=$(cat $file_bin | dd bs=1 skip=$head count=$size | od -An -tx1 | tr -d "\n "| dd conv=ucase)
echo "obase=10;ibase=16;$hex" | bc

利用例

バイナリ読み込み ssh-rsa の公開鍵を分解する。

  • 「バイナリファイルから、頭、バイト数を指定して切り出し、10進数へ」をfunctionにして使う。
(
SSH_RSA_PUB_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNckEuuAeiPesx99s/ivWoXQGdJIMKRl0I0HiSLMCdK/dUrXy5ycyy51cEtv0t/AGQCkAxqiYBCWiVhLV/1qpZuONL9UT8cTa4TO749lFVaucxLNN7nvUtbtA4InKqRjsjqK27vCzyWxiMVIMX0jNpD0rPCwkTK2Ja6knCRN7kA2c3UyNmX4IoQ0xqT0vaUNuxtOe9SkmT3DLizDMbYByzJWVgotbZfOu1QbbClpLt/TbDd5l3fcGNsRzT8Cnd8zdvXk5ZsiUDKKhynvA4Tt/LN9LjZgxTyoEYJewYzf51E8gH057A9zXguBTTAiHMgD8xgeGzh4AVEEFJ1ZO6oCft [email protected]"
function hex_from_bin_file()
{
  (
  file_bin="$1"
  head="$2"
  size="$3"
  hex=$(cat $file_bin | dd bs=1 skip=$head count=$size | od -An -tx1 | tr -d "\n "| dd conv=ucase)
  export BC_LINE_LENGTH="100000000000"
  echo $hex
  ) 2>/dev/null
}
function num_from_bin_file()
{
  (
  file_bin="$1"
  head="$2"
  size="$3"
  hex=$(cat $file_bin | dd bs=1 skip=$head count=$size | od -An -tx1 | tr -d "\n "| dd conv=ucase)
  export BC_LINE_LENGTH="100000000000"
  echo "obase=10;ibase=16;$hex" | bc
  ) 2>/dev/null
}
file_bin=$(mktemp -t convrsa)
echo $SSH_RSA_PUB_KEY | cut -d" " -f2 | base64 -D >>$file_bin

head=0

length=$(num_from_bin_file $file_bin $head 4)
head=$(expr 4  + $head)
value_string=$(cat $file_bin | dd bs=1 skip=$head count=$length 2>/dev/null)
head=$(expr $length + $head)

echo "type:"
echo "length : $length bytes"
echo $value_string

length=$(num_from_bin_file $file_bin $head 4)
head=$(expr 4  + $head)
value_num=$(num_from_bin_file $file_bin $head $length)
head=$(expr $length + $head)

echo "e:"
echo "length : $length bytes"
echo $value_num

length=$(num_from_bin_file $file_bin $head 4)
head=$(expr 4  + $head)
value_hex=$(hex_from_bin_file $file_bin $head $length)
value_num=$(num_from_bin_file $file_bin $head $length)
head=$(expr $length + $head)

echo "n:"
echo "length : $length bytes"
echo $value_num
echo "-"
echo $value_hex
)

test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment