Base32 Encoding

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

VariantAlphabetSkips confusing chars?Checksum?Common Use CasesCase-sensitive?
RFC 4648 Base32A–Z 2–7Yes (0,1,8,9)NoTOTP (Google Authenticator), some keysNo (decoding)
base32hex (RFC 4648 §7)0–9 A–VNoNoHex-like ordering, sorted valuesNo
Crockford’s Base320–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 linksNo (normalizes)
z-base-32y 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 5Yes + phonetic orderingNoFlickr short URLs, short IDsNo

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 CaseRecommended VariantWhy Base32?
TOTP / 2FA secretsRFC 4648Google Authenticator standard
Human-readable short IDsCrockfordFewer transcription errors
Sorted / lexicographic IDsbase32hex0–9 A–V sorts naturally
Compact binary in URLs/pathsRFC 4648 (no pad)Safer than Base64 in some contexts
Legacy systems / OTPRFC 4648Very common

Base32 sits between hex (very readable, but long) and Base64 (compact, but more error-prone visually).