Skip to content

Instantly share code, notes, and snippets.

@FrancoisCapon
Last active December 14, 2023 15:11
Show Gist options
  • Save FrancoisCapon/d313c5e83dffc8716913944735a4d190 to your computer and use it in GitHub Desktop.
Save FrancoisCapon/d313c5e83dffc8716913944735a4d190 to your computer and use it in GitHub Desktop.
Url Safe Wrapper of the GNU Base64 Util
# author: François Capon
# version 1.0
# urlsafe wrapper of the gnu base64 util
# warning:
# -d option must be the first argument (if it is used)
# -i option must be the second argument (if it is used)
# input: file or stdin
if [ "$#" -gt 0 ] # arguments ?
then # yes
last_argument="${@: -1}"
if [ -f $last_argument ] # handle a file ?
then # yes
input=$(cat $last_argument)
set -- "${@:1:$#-1}" # remove filename (last argument)
else # no
input="$(< /dev/stdin)"
fi
else # no filemame
input="$(< /dev/stdin)"
fi
# decode or encode
if [[ $1 = '-d' ]]
then # clean the input (i option), add the pad and decode
if [[ $2 = '-i' ]]
then
input=$(echo -n $input | tr -cd [:alnum:]_- )
fi
pad[0]=""; pad[2]="=="; pad[3]="="
padindex=$(( ${#input} % 4 ))
input=$input${pad[padindex]}
echo $(echo -n $input | tr _- /+ | base64 $@ )
else # encode
echo $(echo -n $input | base64 $@ | tr /+ _- | tr -d = )
fi
# author: François Capon
# version 1.0
# https://datatracker.ietf.org/doc/html/rfc4648#section-5
# https://www.gnu.org/software/coreutils/manual/html_node/base64-invocation.html#base64-invocation
# https://www.gnu.org/software/coreutils/manual/html_node/Translating.html#Translating
function test_cases
{
for i in ${!input[*]}
do
output=$(echo -n "${input[i]}" | ./base64url $options)
testindex=$([ ${expected[i]} = $output ] ; echo $?)
echo -e "$options \t\t ${input[i]} \t ${expected[i]} \t $output \t ${test[testindex]}"
done
}
test=(ok KO)
input=(123456 1234567 12345678 012ts?a "012ts>a")
expected=(MTIzNDU2 MTIzNDU2Nw MTIzNDU2Nzg MDEydHM_YQ MDEydHM-YQ)
echo -e "\noption \t\t input \t\t expected \t output \t test\n"
# encode
options=""
test_cases
#decode
tmp=("${input[@]}")
input=("${expected[@]}")
expected=("${tmp[@]}")
unset tmp
options="-d"
test_cases:heavy_check_mark:
#files and options
options="-d 01.txt"
unset input
input[0]=""
expected[0]="012ts?a"
test_cases
options=" 02.txt "
unset input
input[0]=""
expected[0]="MDEydHM-YQ"
test_cases
options="-d -i 03.txt"
unset input
input[0]=""
expected[0]="012ts?a"
test_cases
# end
echo ""

Url Safe Wrapper of the GNU Base64 Util

The gnu base64 util has no option to handle the URL and Filename Safe Alphabet version (RFC 4648 / section 5) and basenc (was introduce in coreutils v8.31) is not installed on all hosts.

So just for training, I writed this wrapper in bash!

Wrapping Principle

This script is a wrapper that:

  • in encoding process:
    1. encode with the gnu base64 util
    2. translate the base64 gnu encoding result to base64url
  • in decoding processus:
    1. translate the base64url encoding to a standard base64
    2. decode with the gnu base64 util

Options

All the standard options can be set but:

  • ⚠️ the -d option must be the first argument (if it is used)
  • ⚠️ the -i option must be the second argument (if it is used)

Test Cases

Test Files Content

01.txt
MDEydHM_YQ
02.txt
012ts>a
03.txt
MDEy#
dHM_YQ!

Results

$ ./test_base64url 

option          input           expected        output          test
                123456          MTIzNDU2        MTIzNDU2        ok
                1234567         MTIzNDU2Nw      MTIzNDU2Nw      ok
                12345678        MTIzNDU2Nzg     MTIzNDU2Nzg     ok
                012ts?a         MDEydHM_YQ      MDEydHM_YQ      ok
                012ts>a         MDEydHM-YQ      MDEydHM-YQ      ok
-d              MTIzNDU2        123456          123456          ok
-d              MTIzNDU2Nw      1234567         1234567         ok
-d              MTIzNDU2Nzg     12345678        12345678        ok
-d              MDEydHM_YQ      012ts?a         012ts?a         ok
-d              MDEydHM-YQ      012ts>a         012ts>a         ok
-d 01.txt                       012ts?a         012ts?a         ok
 02.txt                         MDEydHM-YQ      MDEydHM-YQ      ok
-d -i 03.txt                    012ts?a         012ts?a         ok

✔️ All test cases are okay!

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