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. ↩︎
Mⱺ℠ said on troet.cafe:
@Edent one minor note: tr takes an input file so you could drop the cat & pipe, i think?
Toby said on risc.social:
@Edent
Neat article, definitely bookmarking this because I know it'll come in handy having worked with TOTP stuff before, so thanks for sharing! One question:
What version of macOS? Python 3 has been bundled with macOS by default for some time now - unless you mean that it's been removed/disabled by some policy on your machine, in which case, fair enough, forgive me!
Toby said on risc.social:
@Edent Never mind. Just occurred to me that you need the command line development tools installed to get python3, which didn't occur to me until just now. My bad!
Eva Lauren Kelly says:
You can generate a QR Code using a Shortcut — in fact, you could probably include your secret generation command as a part of that, so you have an all in one button in the Shortcuts app to if that suits you 🙂
More comments on Mastodon.