Base32 is a binary-to-text encoding scheme that represents binary data using a set of 32 characters. Each Base32 character encodes exactly 5 bits of data (since 2⁵ = 32), making it efficient for certain applications while remaining human-readable and less error-prone than hexadecimal in some contexts.
Standard Base32 (RFC 4648)
Defined in RFC 4648 (which also covers Base16 and Base64), the most common variant uses this alphabet:
Alphabet: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 2 3 4 5 6 7
- Values 0–25 → A–Z (uppercase)
- Values 26–31 → 2–7
- Skips 0, 1, 8, 9 to avoid visual confusion (0/O, 1/I/l, 8/B)
Key properties:
- Case-insensitive in decoding (most implementations accept lowercase input)
- Uses
=padding to make output length a multiple of 8 characters (each group of 8 chars = 40 bits = 5 bytes) - Padding is often optional or omitted in some applications (e.g., when length is known)
- Output is longer than Base64 (~1.6× vs. 1.33× the binary size)
Python Standard Library Example (base64 module)
import base64
# Example binary data
data = b"Hello, Base32 world!"
# Encode → returns bytes
encoded = base64.b32encode(data)
print(encoded.decode('ascii'))
# → JBSWY3DPEBLW64TMMQQQ====
# Decode back
decoded = base64.b32decode(encoded)
print(decoded.decode('utf-8'))
# → Hello, Base32 world!
# Without padding (common in URLs/keys)
encoded_no_pad = base64.b32encode(data).rstrip(b'=')
print(encoded_no_pad.decode('ascii'))
# → JBSWY3DPEBLW64TMMQQQ
Decoding tolerates missing padding automatically in Python:
base64.b32decode("JBSWY3DPEBLW64TMMQQQ") # works fine
Other Popular Variants
| Variant | Alphabet | Skips confusing chars? | Checksum? | Common Use Cases | Case-sensitive? |
|---|---|---|---|---|---|
| RFC 4648 Base32 | A–Z 2–7 | Yes (0,1,8,9) | No | TOTP (Google Authenticator), some keys | No (decoding) |
| base32hex (RFC 4648 §7) | 0–9 A–V | No | No | Hex-like ordering, sorted values | No |
| Crockford’s Base32 | 0–9 A–H J–K M–N P–T V–Z (no I,L,O,U) | Yes (I,L,O,U) | Optional (mod 37) | Human-readable IDs, UUIDs, short links | No (normalizes) |
| z-base-32 | y b n d r f g 8 e 2 t 3 w s q j k x c p m v h 7 4 z 6 5 | Yes + phonetic ordering | No | Flickr short URLs, short IDs | No |
Crockford’s Base32 Example (most human-friendly)
Douglas Crockford designed this variant to maximize readability and minimize transcription errors:
- Excludes: I, L, O, U (avoids confusion + prevents “FU” substrings)
- Accepts: 0–9 A–H J–K M–N P–T V–Z (case-insensitive)
- Optional: checksum character (mod 37 using * ~ $ = U etc.)
Python library: pip install base32-crockford (not in stdlib)
# pip install base32-crockford
import base32_crockford
print(base32_crockford.encode(123456789)) # → 3N7K9
print(base32_crockford.encode(123456789, checksum=True)) # → 3N7K95
print(base32_crockford.decode("3n7k9")) # → 123456789
print(base32_crockford.decode("3N7K95", checksum=True)) # → 123456789
When to Use Base32
| Use Case | Recommended Variant | Why Base32? |
|---|---|---|
| TOTP / 2FA secrets | RFC 4648 | Google Authenticator standard |
| Human-readable short IDs | Crockford | Fewer transcription errors |
| Sorted / lexicographic IDs | base32hex | 0–9 A–V sorts naturally |
| Compact binary in URLs/paths | RFC 4648 (no pad) | Safer than Base64 in some contexts |
| Legacy systems / OTP | RFC 4648 | Very common |
Base32 sits between hex (very readable, but long) and Base64 (compact, but more error-prone visually).