-
-
Save markusfisch/2648733 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| # Fallback base64 en-/decoder for systems that lack a native implementation | |
| # | |
| # @param ... - flags | |
| which base64 &>/dev/null || { | |
| # if even od is missing | |
| which od &>/dev/null || od() | |
| { | |
| local C O=0 W=16 | |
| while IFS= read -r -d '' -n 1 C | |
| do | |
| (( O%W )) || printf '%07o' $O | |
| printf ' %02x' "'$C" | |
| (( ++O%W )) || echo | |
| done | |
| echo | |
| } | |
| if which awk &>/dev/null | |
| then | |
| base64() | |
| { | |
| # written by Danny Chouinard | |
| # https://sites.google.com/site/dannychouinard/Home/unix-linux-trinkets/little-utilities/base64-and-base85-encoding-awk-scripts | |
| awk \ | |
| 'function encode64() | |
| { | |
| while( "od -v -t x1" | getline ) | |
| { | |
| l = length( $0 ); | |
| for( c = 9; c <= l; ++c ) | |
| { | |
| d = index( "0123456789abcdef", substr( $0, c, 1 ) ); | |
| if( d-- ) | |
| { | |
| for( b = 1; b <= 4; ++b ) | |
| { | |
| o = o*2+int( d/8 ); | |
| d = (d*2)%16; | |
| if( ++obc == 6 ) | |
| { | |
| printf substr( b64, ++o, 1 ); | |
| if( ++rc > 75 ) | |
| { | |
| printf( "\n" ); | |
| rc = 0; | |
| } | |
| obc = 0; | |
| o = 0; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if( obc ) | |
| { | |
| while( obc++ < 6 ) | |
| { | |
| o = o*2; | |
| } | |
| printf "%c", substr( b64, ++o, 1 ); | |
| } | |
| print "=="; | |
| } | |
| function decode64() | |
| { | |
| while( getline < "/dev/stdin" ) | |
| { | |
| l = length( $0 ); | |
| for( i = 1; i <= l; ++i ) | |
| { | |
| c = index( b64, substr( $0, i, 1 ) ); | |
| if( c-- ) | |
| { | |
| for( b = 0; b < 6; ++b ) | |
| { | |
| o = o*2+int( c/32 ); | |
| c = (c*2)%64; | |
| if( ++obc == 8 ) | |
| { | |
| printf "%c", o; | |
| obc = 0; | |
| o = 0; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| BEGIN { | |
| b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" | |
| if( ARGV[1] == "-d" ) | |
| decode64(); | |
| else | |
| encode64(); | |
| }' "$@" | |
| } | |
| else | |
| cat <<EOF | |
| WARNING: your system is missing base64 AND awk! | |
| base64 encoding/decoding will be painfully slow! | |
| EOF | |
| base64() | |
| { | |
| local SET='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' | |
| [ "$1" == '-d' ] && { | |
| local N=0 V=0 C S IFS= | |
| while read -r -d '' -r -n1 C | |
| do | |
| [ "$C" == $'\n' ] && continue | |
| if [ "$C" == '=' ] | |
| then | |
| V=$(( V << 6 )) | |
| else | |
| C=${SET#*$C} | |
| C=$(( ${#SET}-${#C} )) | |
| (( C )) || continue | |
| V=$(( V << 6 | --C )) | |
| fi | |
| (( ++N == 4 )) && { | |
| for (( S=16; S > -1; S -= 8 )) | |
| do | |
| C=$(( V >> S & 255 )) | |
| # shellcheck disable=SC2059 | |
| printf "\\$(( C*100/64+C%64*10/8+C%8 ))" | |
| done | |
| V=0 | |
| N=0 | |
| } | |
| done | |
| return | |
| } | |
| od -v -t x1 | { | |
| local V=0 W=0 SH=16 A S N L | |
| while read -r -a A | |
| do | |
| for (( N=1, L=${#A[@]}; N < L; ++N )) | |
| do | |
| V=$(( 16#${A[$N]} << SH | V )) | |
| (( (SH -= 8) < 0 )) || continue | |
| for (( S=18; S > -1; S -= 6 )) | |
| do | |
| echo -n ${SET:$(( V >> S & 63 )):1} | |
| (( ++W > 75 )) && { | |
| echo | |
| W=0 | |
| } | |
| done | |
| SH=16 | |
| V=0 | |
| done | |
| done | |
| if (( SH == 8 )) | |
| then | |
| N=11 | |
| elif (( SH == 0 )) | |
| then | |
| N=5 | |
| else | |
| N=0 | |
| fi | |
| (( N )) && { | |
| for (( S=18; S > N; S -= 6 )) | |
| do | |
| echo -n ${SET:$(( V >> S & 63 )):1} | |
| (( ++W > 75 )) && { | |
| echo | |
| W=0 | |
| } | |
| done | |
| for (( S=N/5; S--; )) | |
| do | |
| echo -n '=' | |
| done | |
| } | |
| echo | |
| } | |
| } | |
| fi | |
| } | |
| base64 "$@" |
@markusfisch
Thanks for your sharing, in my recent disaster rescue case, I successfully apply your pure bash base64 decoder to transfer binary tool from survived ssh session. but your pure bash base64 decoder, has a bug when transforming decimal to octet in following line:
printf "\\$(( C*100/64+C%64*10/8+C%8 ))"
correct version should be:
printf "\\$(( C/64*100+C/8%8*10+C%8 ))"
BR
Grei
Thanks so much for sharing! I got some issues with od on non printable characters. I reworked the function, based on this answer on StackOverflow:
which od &>/dev/null || {
printf -v ascii \\%o {32..126}
printf -v ascii "$ascii"
printf -v cntrl %-20sE abtnvfr
od() {
local char val offset=0 width=16
while LANG=C IFS= read -r -d '' -n 1 char; do
# print current offset at the beginning
(( offset % width )) || printf '%07o' $offset
# decode the current char value
printf -v char "%q" "$char"
case ${#char} in
# printable char "g" or "\["
1|2 ) char=${ascii%$char*}; val=($((${#char}+32)));;
# octal form "$'\002'"
7 ) char=${char#*\'\\}; val=($((8#${char%\'})));;
# control char "$'\n'"
5 ) char=${char#*\'\\}; char=${cntrl%${char%\'}*}
val=($((${#char}+7)));;
# should no append
* ) echo >&2 "od: ERROR: could no decode $char";;
esac
printf ' %02x' "$val"
# end line after width chars
(( ++offset % width )) || echo
done
echo
}
}@markusfisch It would be great if there was a version of this without bash-isms that could run in older/simpler shells like Busybox Ash. Often in embedded environments (routers, IOT devices etc.) that have no base64 functions, bash isn't available either.
In my case dd-wrt router software lacks the base64 functions in it's old busybox version. I have a base64encoder shell script but not a decoder as yet. A modified version of your script would be perfect in these scenarios.
Edit
Found this shortly after writing:
https://github.com/mateusza/shellscripthttpd/blob/master/base64.sh
i tested the linked implementation and it failed with OOM , still i fixed the matesuza variant to support -w...
@markusfisch @Shkeats i also modified the above scripts to run with ash & awk (no od , no fold etc)
results are here : https://github.com/benchonaut/owrt-ash-b64-test-results
I gathered some list of possible bas64 solutions https://gist.github.com/stokito/18ce554bd53bdb6355670066d5ae9943
@markusfisch It would be great if there was a version of this without bash-isms that could run in older/simpler shells like Busybox Ash. Often in embedded environments (routers, IOT devices etc.) that have no base64 functions, bash isn't available either.
In my case dd-wrt router software lacks the base64 functions in it's old busybox version. I have a base64encoder shell script but not a decoder as yet. A modified version of your script would be perfect in these scenarios.
Edit
Found this shortly after writing:
https://github.com/mateusza/shellscripthttpd/blob/master/base64.sh