🍱 Lunchbox Hands

Base32 Encode / Decode

Encode and decode Base32 (RFC 4648)

Encode and decode Base32 (RFC 4648) with padding. UTF-8 aware and case-insensitive on decode. Everything runs in your browser.

How the encoder works

Your text is first converted to UTF-8 bytes. Those bytes are treated as one long bit string and cut into 5-bit groups, and each group (a value from 0 to 31) picks a character from ABCDEFGHIJKLMNOPQRSTUVWXYZ234567. If the bits run out partway through a group, it is filled with zeros, and then = is appended until the output length is a multiple of 8.

Take the single letter f. It is byte 0x66, binary 01100110. The first five bits, 01100, are 12, which is M. Three bits remain, 110; padded with two zeros they become 11000, 24, which is Y. Two characters is not a multiple of 8, so six = follow: MY======.

Test vectors you can check

RFC 4648 lists test vectors for Base32. We ran the tool's encoder on each of them, and on two extra inputs, and got these results — type any of them in to confirm:

  • f → MY======
  • fo → MZXQ====
  • foo → MZXW6===
  • foob → MZXW6YQ=
  • fooba → MZXW6YTB (exactly 5 bytes, so no padding)
  • foobar → MZXW6YTBOI======
  • Hello World → JBSWY3DPEBLW64TMMQ======
  • héllo → NDB2S3DMN4====== (é is two bytes in UTF-8, so this is 6 bytes, not 5)

What the decoder accepts, and what it doesn't

The decoder is more forgiving than RFC 4648's strict mode, on purpose, because most strings pasted into a Base32 decoder are authenticator secrets copied out of a setup screen. Before decoding it removes all whitespace, then strips trailing =, then uppercases the input, so padding followed by a stray newline (MZXW6=== plus a line break) still decodes, here to foo. Likewise jbsw y3dp, JBSWY3DP and JBSWY3DP======== all decode to Hello.

A few limits are worth knowing:

  • Any character outside A–Z and 2–7 stops the decode with an error naming it, e.g. Invalid base32 character "0". That includes = in the middle of a string.
  • The decoder doesn't check the length. Leftover bits that don't make a full byte are dropped, so a truncated string like MZXW quietly decodes to fo instead of raising an error.
  • Output is always interpreted as UTF-8 text. Binary data (keys, hashes, TOTP secrets) will show up as replacement characters, and there's no hex or file output. If you need the raw bytes, decode with a command-line tool such as base32 -d from GNU coreutils.
  • Only the standard alphabet is supported — not base32hex, Crockford, or z-base-32.

Where you'll run into Base32

The place you are most likely to meet it is two-factor authentication. The secret behind an authenticator app's six-digit codes is often 20 random bytes (the RFC 4226 recommendation), which is exactly 32 Base32 characters with no padding (10-byte, 16-character secrets are also common). That's the string under the QR code when you choose "enter key manually". The TOTP generator takes such a secret and shows the live codes. Base32 also appears in Tor onion addresses and some magnet links, and generally anywhere a string has to survive case-insensitive systems or human retyping.

If you're choosing an encoding rather than decoding one, Base64 vs Base32 vs Base58 compares the trade-offs. For compact machine-to-machine text, the Base64 encoder is usually the better fit; for short strings that avoid look-alike characters but can stay case-sensitive, see the Base58 encoder.

Frequently asked questions

What characters does Base32 use?

The RFC 4648 alphabet is the 26 uppercase letters A-Z followed by the digits 2-7, 32 symbols in all, plus = for padding. The digits 0, 1, 8 and 9 are left out so they can't be confused with O, I/L and B. Each character carries 5 bits.

Why does Base32 output end in equals signs?

Base32 works in blocks of 5 bytes, which become 8 characters. When the input isn't a multiple of 5 bytes, the last block is padded with = until the output length is a multiple of 8. One leftover byte gives 2 characters plus 6 =, two give 4 plus 4, three give 5 plus 3, and four give 7 plus 1. This encoder always pads; the decoder accepts input with or without it.

Is Base32 decoding case-sensitive?

Not in this tool. The decoder uppercases everything before decoding, so nbswy3dp and NBSWY3DP both decode to hello. It also removes spaces and line breaks, which helps when a secret has been displayed in groups of four.

Why do I get strange characters when I decode a TOTP secret?

Because a TOTP secret is random bytes, not text. This tool decodes the bytes as UTF-8, and random bytes are almost never valid UTF-8, so you see replacement characters (�). The decode itself worked; there just isn't readable text inside. To use the secret, paste it into the TOTP generator instead.

How much bigger is Base32 than the original?

8 characters for every 5 bytes, so 60% larger before padding. Base64 is 33% larger. You pay the extra size for an alphabet that is case-insensitive and avoids look-alike characters, which matters when a person has to type the string.

Is this the same as Crockford Base32 or base32hex?

No. This tool uses the standard RFC 4648 alphabet only. Base32hex (also defined in RFC 4648) uses 0-9 then A-V, and Crockford's Base32, used by ULIDs, uses a different alphabet that drops I, L, O and U. Output from one won't decode correctly with another.

Get weekly dev tools and tips