------------------------------------------------------------------------------- Numerical base conversions ------------------------------------------------------------------------------- About Perl pack/unpack Perl pack/unpack is for pack/unpack to/from raw binary. As such pack 'H*' will pack a Hexadecimal String to Raw Data while unpack 'H*' will convert a rawdata into a hexadecmal string similarly pack 'N' converts a number, 4 byte / 16 bit network number. These are all equivelent... hexadecimal: DEADBEEF Decimal: 3735928559 IP (dot quad): 222.173.190.239 Binary: 11011110 10101101 10111110 11101111 Octal: 33653337357 Raw Data: {unprintable) Decimal to Hexidecimal printf '%08X\n' 3735928559 # uppercase perl -le 'print unpack("H*", pack("N", 3735928559))' # lowercase perl -le 'printf("%08X\n", 3735928559)' # uppercase # => DEADBEEF or deadbeef python -c 'print(f"{3735928559:#x}")' # 0xdeadbeef Hexadecimal to Decimal echo $((16#DEADBEEF)) # shell number base conversion perl -le 'print unpack("N", pack("H8",substr("0"x8 . "DEADBEEF",-8)));' perl -le 'print hex("DEADBEEF")' python -c 'print(f"{0xDeadBeef}")' # => 3735928559 Hexadecimal to IP (dot quad) perl -MSocket -le 'print inet_ntoa(pack("N",hex("DEADBEEF")));' perl -le 'print join(".", unpack("C*", pack("H*", "DEADBEEF")));' Decimal to Binary perl -le 'print unpack("B*", pack("N", 3735928559))' # 32bit perl -le 'printf("%b\n", 3735928559)' # variable length # => 11011110101011011011111011101111 perl -le 'printf("%08b\n", 123)' # fixed length # => 01111011 python -c 'print(f"{3735928559:#b}")' # => 0b11011110101011011011111011101111 Binary to Decimal perl -le 'print ord(pack('B8', '10110110'))' # single character only perl -le 'print oct( "0b11011110101011011011111011101111" )' # up to 32bit but can do larger (with warning) Raw binary STDIN to Hexadecimal string (more in hexidecmial below) perl -0777 -e 'print unpack("H*",<>), "\n"' Decimal to Octal printf "%o\n" 3735928559 # -> 33653337357 IP to binary (for subneting) perl -e 'print join(" ", map substr(unpack("B32",pack("N",$_)),-8), split(/\./,shift)), "\n"' 222.173.190.239 # -> 11011110 10101101 10111110 11101111 # perl printf makes it easier... perl -e 'print join(" ", map sprintf("%08b",$_), split(/\./,shift)), "\n" ' 222.173.190.239 # -> 11011110 10101101 10111110 11101111 Example: The subnets 10.250.0.0/15 PLUS 10.251.0.0/15 is NOT the same as 10.250.0.0/14 Pure BASH binary-to-hex and hex-to-binary # USAGE: hex_repr=$(str2hex_echo "ABC") # returns "0x41 0x42 0x43" str2hex_echo() { local str=${1:-""} local fmt="0x%x" local chr local -i i for i in $( seq 0 $((${#str}-1)) ); do chr=${str:i:1} printf "${fmt} " "'${chr}" done } # To be revised - not working # hex2str_echo() { # # USAGE: ASCII_repr=$(hex2str_echo "0x41 0x42 0x43") # # returns "ABC" # echo -en "'${1:-""//0x/\\x}'" # } ------------------------------------------------------------------------------- Using DC You must specify input base after output base, otherwise you need to specify the output base, using the input base! Defaults are base 10 for both (of course). Hexadecimal to Binary hex=81 echo "2o 16i ${hex} p" | dc 10000001 Binary to Hexadecimal binary=00111100 echo "16o 2i ${binary} p" | dc 3C You get the idea See.. http://wiki.bash-hackers.org/howto/calculate-dc Also http://en.wikipedia.org/wiki/Dc_%28Unix%29 =============================================================================== Hexadecimal Hexadecimal to Decimal echo $((0xdeadbeef)) # -> 3735928559 echo $((0xBadC0ffee)) # -> 50159747054 echo $((16#deadbeef)) # -> 3735928559 echo $((16#BadC0ffee)) # -> 50159747054 Decimal to Hexadecimal printf "0x%X\n" 3735928559 # -> 0xDEADBEEF printf "0x%X\n" 50159747054 # -> 0xBADC0FFEE Hexadecimal to Raw binary (with cleanup) echo deadbeef | perl -pe 'y/A-Fa-f0-9//dc; $_= pack("H*",$_);' basenc -d --base16 # input must be capitals, and no spaces Raw binary to Hexadecimal (For viewing) echo deadbeef | perl -pe 'y/A-Fa-f0-9//dc; $_= pack("H*",$_);' | basenc --base16 # only linebreaks at 76 chars (-w option) # => DEADBEEF od -t x1 # index and individual hex chars # (like hexdump below but no ASCI block) hexdump -C /dev/stdin # includes index, and ASCII output block # => 00000000 de ad be ef |....| # WARNING without -C for hexdump, result is in little-endian (LSB) pairs) hexdump /dev/stdin # => 0000000 adde efbe |....| # You can reformat Hexadecimal line lengths (to 64) using... perl -0777 -pe 's/^\s+//gm; s/^(.{80})\n/\1/gm; 1 while s/^(.{64})(.)/\1\n\2/m;' Raw binary string to Hexadecimal Lines of 64 hexchars perl -0777 -pe '$_=unpack("H*",$_); s/.{64}/$&\n/g; s/\n?$/\n/;' # Example output: # echo -n "ABC" | perl ... # # => 414243 In C, From hex void hex_to_binary(unsigned char *buf, unsigned char *hex) { for( ; sscanf( hex, "%2x", buf++ ) == 1 ; hex+=2 ); *buf = 0; // null terminate -- precaution though may contain nulls } In C, To Hex void print_hex(unsigned char *buf, int len) { int i; int n; for(i=0,n=0;i 31){ // printf("\n"); // N = 0; // } printf("%02x",buf[i]); // n++; } printf("\n"); } Python2 # hex to raw binary iv = 'a2a8a78be66075c94ca5be53c8865251'.decode('hex') # binary to hex iv.encode('hex') Python3 # hex to raw binary iv = bytes.fromhex('a2a8a78be66075c94ca5be53c8865251') # binary to hex bytes.hex(iv) ------------------------------------------------------------------------------- Base64 Note that uuencode is almost exact substitution coding of Base64 as such the perl pack for uuencode can be used for conversion. This is detailed in the document "binary_encoding.txt" Simple base64 is a standard 'coreutils' filter on linux systems But will not pass/ignore non-base64 characters (aborts instead). Binary -> base64 openssl enc -base64 base64 [-e] basenc --base64 python3 -m base64 -e perl -MMIME::Base64 -e 'print encode_base64("string")' b64decode # personal perl4 using uuencode mimencode # not very common gmime-uuencode --base64 uuencode -m - # from sharutils package Base64 -> binary openssl enc -base64 -d -A # The '-A' is important (see below) base64 -d basenc -d --base64 python3 -m base64 -d perl -MMIME::Base64 -0777 -ne 'print decode_base64($_)' file b64encode # personal perl4 using uuencode mmencode -u [file...] # not very common gmime-uudecode --base64 WARNING: OpenSSL base64 decoding silently ignores part and sometimes all of a line with a non-base64 characters. This lets OpenSSL read PEM-format files while ignoring the headers. Before v1.1.0 OpenSSL also silently ignores lines longer than the 76-character limit as specified by MIME, unless you add an "-A" option. Later version do not require "-A". NOTE its zlib-compression is related but not the same as gzip compression. Python script from base64 import b64decode string = b64decode(encoded) Reformat Base64 line lengths (to 64) using... perl -0777 -pe 's/^\s+//gm; s/^(.{80})\n/\1/gm; 1 while s/^(.{64})(.)/\1\n\2/m;' ------------------------------------------------------------------------------- Base32 Binary -> base32 base32 basenc --base32 Base32 -> binary base32 -d basenc -d --base32 ------------------------------------------------------------------------------- ModHex (used by Yubikey's) Modified Hexadecimal (character substitutions) Reason... Keyboards do not know its keymaps! It only sends scancodes However in general keyboards map certain keys to certain scancodes and these are what yubikeys use. Basically as it can only transmit certain keys so a modified hexadecimal is used to send the Yubikey hexadecimal output. Hexadecimal: 0123 4567 89ab cdef ModHex Code: cbde fghi jkln rtuv Further 'c' is most ambigious in keyboards, so any other key should map to '0' when reading a yubikey As such bde fghi jkln rtuv will map to hex values -> 1 - f And all other characters (especially 'c') maps to 0 -------------------------------------------------------------------------------