How to generate a Base32 TOTP secret string on a Mac
I needed a way to generate a TOTP secret using a fairly locked-down Mac. No Brew. No NPM. No Python. No Prolog, COBOL, or FORTRAN. No Internet connection. Just whatever software is native to MacOS.
As I've mentioned before, the TOTP specification is a stagnant wasteland. But it does have this to say about the secret:
The
secret
parameter is an arbitrary key value encoded in Base32 according to RFC 3548.
The Base32 alphabet is pretty simple. The upper-case letters A - Z, and the numbers 3 - 7.
But that's only half the problem.
How long should the secret be?
This is an area where the official spec is silent. Around the web, you'll find people saying things like:
The length in bytes of generated shared secrets. The minimum is 20 (or 160 bits), and the default is 32 (or 256 bits). In most use cases 32 is sufficient. Though some authenticators may have issues with more than the minimum. Our minimum is the recommended value in RFC4226, though technically according to the specification 16 bytes (or 128 bits) is the minimum. Authelia
Although that's for the HOTP algorithm, rather than TOTP.
Looking through my 49(!) different TOTP codes, the shared secret ranges from 16 characters to 52 characters. No consistency whatsoever.
The Code
Run this on your command line.
cat /dev/urandom | LC_ALL=C tr -dc 'A-Z3-7' | fold -w 24 | head -n 1
That generates a random-enough0 string using the correct alphabet and truncated to a sensible length.
Let's go through each part of it.
cat /dev/urandom
spits out random data from your machine. You may wish to use /dev/random
if you feel like it.
LC_ALL=C
sets the Locale to by ANSI bytes.
tr
is "Translate, squeeze, and/or delete characters.".
-dc 'A-Z3-7'
is delete the complement (i.e. delete anything which isn't in the following string).
fold -w 24
is wrap the input text with a line length of 24.
head -n 1
displays the first line of the file.
Next Steps
Now... How do I locally generate a QR code without anything else being installed...?
-
This is a shared secret. It doesn't need an infinite supply of high-quality entropy. Any decent login protection service should throttle incorrect attempts long before someone can brute-force it. Remember, TOTP codes are not random - they're deterministic product of the secret. Your adversary isn't someone who can crack your secure vault - it's someone who already has your username as password, but doesn't have your token generating device. ↩︎
More comments on Mastodon.