By Docify

RFC 4648 Base32 vs Base32hex: Alphabet and Sort Order

• 6 min read

RFC 4648 defines two 5-bit alphabets for the same bit stream. §6 Base32 is A–Z2–7. §7 base32hex is 0–9A–V. Encoding foobar writes MZXW6YTBOI====== on /base32/. The same bytes write CPNMUOJ1E8====== on /base32hex/. Decoding those strings writes foobar. f is MY====== on /base32/ and CO====== on /base32hex/. Neither page is Crockford Base32 (ULID), a TOTP verifier, or NSEC3.

“Base32” is not one alphabet. RFC 4648 §6 and §7 encode the same 5-bit groups with different characters, so the same UTF-8 bytes print two different strings. This page names those outputs on the live Base32 encoder and Base32hex encoder. It is not Crockford Base32, not a TOTP app, and not DNSSEC.

Two alphabets, same 5-bit groups

A–Z2–7 versus 0–9A–V

RFC 4648 §6 Base32 is ABCDEFGHIJKLMNOPQRSTUVWXYZ234567. RFC 4648 §7 base32hex is 0123456789ABCDEFGHIJKLMNOPQRSTUV. The hex alphabet puts a digit before a letter so an encoded value sorts closer to its binary order. Both use = padding. Decode on both live pages strips whitespace, accepts optional trailing =, and is case-insensitive (RFC 4648 §3.2 / §3.3).

§6 A–Z 2–7 · §7 0–9 A–V · both pad with =

The same bytes are not interchangeable

RFC 4648 §10 vector foobar is MZXW6YTBOI====== on /base32/ and CPNMUOJ1E8====== on /base32hex/. f is MY====== versus CO======. Pasting a §6 string into the §7 decoder fails on W, X, Y, or Z. Pasting a §7 string that uses 0, 1, 8, or 9 fails on /base32/. The same UTF-8 bytes on /base64/ are Zm9vYmFy and on /base16/ are 666F6F626172.

Encode does not normalize first

NFC é and NFD e + U+0301 are different outputs

Encode turns UTF-8 bytes into 5-bit characters and never calls String.prototype.normalize. Canonically equivalent e + U+0301 and é (U+00E9) are different UTF-8 sequences (65 CC 81 vs C3 A9). Base32 output of NFC é is YOUQ====. Base32 output of NFD é is MXGIC===. Base32hex output of NFC é is OEKG====. Base32hex output of NFD é is CN682===. The same UTF-8 bytes on /base64/ are w6k= and ZcyB. The same bytes on /base16/ are C3A9 for NFC é. Decode of YOUQ==== or OEKG==== writes NFC é. Try it withfoobar. UAX #15 output e + U+0301 → é (U+00E9) as normalized.txt lives on /unicode-normalize/.

Not Crockford, TOTP, or NSEC3

ULID uses a third Base32 alphabet

Crockford Base32 is 0123456789ABCDEFGHJKMNPQRSTVWXYZ — no I, L, O, or U. That is the 26-character ULID alphabet on /ulid-generator/, not RFC 4648 §6 or §7. The live Base32 pages do not mint or check RFC 6238 TOTP secrets, hash an NSEC3 owner name, or restore a typed image or PDF. RFC 4648 notes NSEC3 uses the §7 alphabet; /base32hex/ does not implement DNSSEC. Download is encoded.txt or decoded.txt as text/plain. Encode and Decode are buttons.

Encode the same bytes with either alphabet

RFC 4648 §6 or §7 in the browser. Nothing is uploaded.

FAQ

What is the difference between Base32 and Base32hex?
Base32 uses A-Z and 2-7. Base32hex uses 0-9 and A-V, preserving sort order of the underlying bytes.
Which should I use?
Use standard Base32 for readability. Use Base32hex when sort order matters.
Is padding required?
RFC 4648 includes = padding. Some implementations omit it since length is computable.
Does this tool upload my data?
No. All encoding runs in your browser using JavaScript. Nothing is sent to a server.

Related