toolhq.io

All posts
5 min readby Jameel Haider

Base32 vs Base64: alphabets, padding, and why TOTP secrets use base32

Base32 and base64 solve the same problem, representing binary data as printable text, and most developers reach for base64 by habit. But base32 exists for good reasons, and TOTP secrets, some DNS uses, and anything a person has to read or type usually pick it on purpose.

The alphabets

Both schemes are defined in RFC 4648. The difference is how many bits each output character carries.

Base64 encodes 6 bits per character using 64 symbols: A-Z, a-z, 0-9, and two extras, usually + and /. Base32 encodes 5 bits per character using 32 symbols: A-Z and the digits 2 through 7. Note what base32 leaves out: it is uppercase only, and it drops 0, 1, 8, and 9 precisely because they are easy to confuse with O, I, B, and so on.

PropertyBase64Base32
Bits per character65
Alphabet size6432
Case sensitiveYesNo, uppercase
Confusable charactersPresentRemoved
Padding character==
Size overheadAbout 33%About 60%

Padding

Both pad output to a fixed block boundary with =. Base64 works in 4 character groups encoding 3 bytes, so it pads to a multiple of 4. Base32 works in 8 character groups encoding 5 bytes, so it pads to a multiple of 8, which means base32 padding can run to several = characters where base64 rarely needs more than two. Padding is often stripped in practice and re-added by the decoder, but a strict decoder will reject input with the wrong padding, so do not assume it is optional.

Size overhead

Base64 expands data by roughly one third: three bytes become four characters. Base32 is less efficient because each character only carries 5 bits, expanding data by roughly 60 percent: five bytes become eight characters. If output size is what you care about, base64 wins clearly.

Why TOTP secrets use base32

The shared secret behind an authenticator app is almost always base32, and the reason is human factors, not bytes. When a service shows you a secret as a fallback to the QR code, you may have to read it aloud or type it into a second device. Base32 is uppercase only, has no characters that collide visually, and is case insensitive, so abc and ABC decode the same and a user cannot get it wrong by holding shift. Base64 would be a poor fit here: it is case sensitive, and + and / are awkward to communicate and easy to mistype.

TOTP secret (base32):  JBSWY3DPEHPK3PXP
same bytes (base64):   SGVsbG8h

The same logic drives other base32 uses. Case insensitivity matters for DNS labels, which are not case sensitive, and the lack of confusable characters matters for anything printed on a label, read over the phone, or shown to a person as an identifier.

Choosing between them

Pick base64 when the output is consumed by machines and size matters: embedding binary in JSON, data URIs, or HTTP headers. Pick base32 when a human touches the value, when the surrounding system is case insensitive, or when transcription errors are costly. And in both cases watch which variant you are using, because the URL safe base64 alphabet swaps + and / for - and _, and mixing variants is a common decode failure.

Encode and decode either way, including the URL safe variant, with the Base64 Encoder / Decoder.