totp.sh
totp.sh copied to clipboard
Remove dependency on base32 utility
Converting base32 input to a sequence of byte values is doable in pure shell, and should be done because the base32 utility is not universally available (it's part of GNU coreutils that Busybox does not implement, so not available on Alpine Linux, etc., unless you also install coreutils and replace the lighter versions of everything with them). The only reason I didn't just write it as a shell function is that it'd take a little bit more time to write an test. I've opened this issue as a reminder to go back and fix it sometime.
Hideously, I think this can be done with bc: first using tr to translate RFC 4648 base32 alphabet to 0-9A-V, then running bc with ibase=32 and obase=16. Something has to be done with padding to make sure the result of aligned/truncated correctly but that doesn't seem to be a blocker.
This would make it possible to run your script on macOS too, since it doesn't have base32 out of the box. Thanks for a great work!
this would be great, don't want to install gnu coreutils on openbsd - bc and tr is in the base installation
Anyone want to test this patch and confirm that it works?
diff --git a/totp.sh b/totp.sh
index 47ac757..32c41cc 100755
--- a/totp.sh
+++ b/totp.sh
@@ -16,7 +16,9 @@
#
t=$(($(date +%s)/30))
-k="$(tr 0189a-z OLBGA-Z | base32 -d | od -v -An -tx1 | tr -d ' \n')"
+k="$( ( printf 'obase=16\nibase=32\n' ; tr 0189a-z OLBGA-Z |
+ tr ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 0123456789ABCDEFGHIJKLMNOPQRSTUV |
+ sed -e s@======@/4@ -e s@====@/G@ -e s@===@/2@ -e s@=@/8@ ) | bc )"
h=$(
printf '%b' $(printf '\\x%.2x' $(
@richfelker i get the following on openbsd -current:
$ ./totp.sh < secret
bc: input base must be a number between 2 and 16 (inclusive)
bc: stdin:3: illegal character: U unexpected
bc: stdin:3: illegal character: I unexpected
bc: stdin:3: illegal character: H unexpected
bc: stdin:3: syntax error: MTK7BHQSF
unexpected
bc: stdin:3: illegal character: M unexpected
bc: stdin:3: illegal character: T unexpected
bc: stdin:3: illegal character: K unexpected
bc: stdin:3: illegal character: H unexpected
bc: stdin:3: illegal character: Q unexpected
bc: stdin:3: illegal character: S unexpected
351957
the code at the bottom isn't the correct one
Is it something wrong with how I'm invoking bc with the piped input, or is OpenBSD's bc just nonconforming and not supporting ibase=32?
Also you should probably change your TOTP secret since you just pasted part of it into a bug tracker thread.
from the man page:
ibase or obase set the input and output number radix respectively
thanks, i already changed the secret code
edit: here the man page for openbsd bc: https://man.openbsd.org/bc.1
Yes, that's what they're supposed to do. What happens if in interactive bc, you type:
ibase=32
G
You should see 16 output.
i get bc: input base must be a number between 2 and 16 (inclusive) and when I type G then bc: stdin:5: illegal character: G unexpected
OK so this is OpenBSD being broken.
The value of obase shall be limited to:
2 <= obase <= {BC_BASE_MAX}
and
{BC_BASE_MAX} Maximum obase values allowed by the bc utility. Minimum Acceptable Value: {_POSIX2_BC_BASE_MAX}
and
{_POSIX2_BC_BASE_MAX} Maximum obase values allowed by the bc utility. Value: 99
ok thanks for you efforts, will see if i can get this to some openbsd devs
Uhg that's obase. ibase apparently is not required to support values above 16.
So, short of some clever trick I'm not thinking of, I don't see any way to salvage this portably. Probably would have to fall back to doing the full base32->base16 conversion in shell script, peeling off one digit at a time, and using bc at most for the padding shift at the end.