Base32 编码详解:RFC 4648 标准与 Crockford 变体的差异、校验和与应用场景

Base32 是什么

Base32 是一种将二进制数据编码为可打印 ASCII 字符的方案,每 5 字节(40 位)数据编码为 8 个字符。与 Base64 相比,Base32 字符集更小(32 vs 64),编码后体积更大(约 60% 膨胀 vs 33%),但具有以下独特优势:

  • 不区分大小写:适合口述、电话、手写场景
  • 字符集仅含字母与数字:无 +///= 等特殊符号,URL 友好
  • 易被二维码、OCR 系统识别:纯字母数字的识别率高于含特殊符号的编码
  • 无障碍友好:屏幕阅读器对字母数字的朗读更清晰

Base32 有两个主流变体:RFC 4648 标准Crockford Base32,两者在字符集、填充规则、校验机制上有显著差异。

RFC 4648 标准 Base32

RFC 4648 是 IETF 制定的 Base16/Base32/Base64 编码规范。标准 Base32 字符集为 A-Z(26 字母)与 2-7(6 数字),共 32 字符。选择 2-7 而非 0-9 是为了避开 0(与字母 O 易混)与 1(与字母 I/L 易混)。

编码原理

每 5 字节(40 位)数据拆分为 8 个 5 位段,每个 5 位段(0-31)映射到字符表:

字节:  H        e        l        l        o
二进制:01001000 01100101 01101100 01101100 01101111
5位段: 01001 00001 10010 10110 11000 11011 00011 01111
字符:  J      B      S      W      Y      3      D      P

「Hello」编码结果为 JBSWY3DP。不足 5 字节的尾部用 = 填充至 8 字符的倍数。

填充规则

原始字节数编码字符数填充 =总长度
1268
2448
3538
4718
5808

应用场景

  • TOTP 共享密钥:Google Authenticator、RFC 6238 TOTP 标准要求密钥以 Base32 编码
  • DNS 主机名编码:DNS 协议中主机名不区分大小写,Base32 是天然适配
  • P2P 协议握手:BitTorrent、磁力链接的 info hash 常用 Base32
  • 二维码短链:纯字母数字的二维码编码效率更高

Crockford Base32

Douglas Crockford 设计的 Base32 变体,专为人工输入场景优化。核心设计理念是「让人类输入错误尽可能少」。

字符集差异

Crockford 字符集为 0-9(10 数字)与 A-Z 去除 I/L/O/U(22 字母),共 32 字符:

字符集字符排除原因
RFC 4648ABCDEFGHIJKLMNOPQRSTUVWXYZ234567无(标准字符集)
Crockford0123456789ABCDEFGHJKMNPQRSTVWXYZI/L(与1混)、O(与0混)、U(意外脏话)

易混字符归一化

Crockford 解码时自动归一化易混字符:

  • I/i/L/l → 数字 1
  • O/o → 数字 0

这意味着用户输入 O0O00000 解码结果相同。这种容错设计让口述、手写场景的输入错误率大幅降低。

不使用填充

Crockford 规范不使用 = 填充。编码结果长度直接反映原始数据长度,更紧凑。

校验和机制

Crockford 规范支持在编码末尾附加 1 个校验字符,用于识别输入错误:

  1. 将原始字节序列视为大整数
  2. 计算 value mod 37(37 是大于 32 的最小质数)
  3. 映射到字符表 0-9A-Z*~$=U(共 37 字符)

校验和可识别大部分单字符替换错误部分换位错误。例如:

  • 用户输入 91B7(正确)→ 校验通过
  • 误输为 91B8(末位错)→ 校验失败,提示「数据可能被误输入」
  • 误输为 19B7(换位)→ 校验失败(mod 37 对换位敏感)

校验和不能纠错,但能提示用户重新核对,避免静默错误。

RFC 4648 vs Crockford 对比

维度RFC 4648Crockford
字符集A-Z + 2-70-9 + A-Z 去除 I/L/O/U
大小写敏感否(解码自动归一化)否(解码自动归一化)
易混字符处理I/L→1, O→0
填充= 填充至 8 倍数不填充
校验和可选附加 1 字符(mod 37)
主要场景机器间传输(TOTP、DNS)人工输入(账号、密钥指纹)
标准文档RFC 4648Crockford 个人规范

与 Base64 的选型决策

场景推荐理由
JWT、Data URL、图片内联Base64体积最小(33% 膨胀),机器处理
TOTP 共享密钥Base32RFC 6238 标准要求
账号号码、订单号Crockford人工输入容错 + 校验和识别错误
二维码短链Base32纯字母数字二维码效率更高
DNS 编码Base32DNS 不区分大小写
屏幕阅读器朗读Base32字母数字朗读清晰,符号易歧义
OCR 自动识别Base32纯字母数字识别率更高

JavaScript 实现要点

编码流程

function encodeBase32(bytes, alphabet, padding) {
  let output = '';
  let buffer = 0;  // 累积位
  let bits = 0;    // 当前累积位数
  for (const byte of bytes) {
    buffer = (buffer << 8) | byte;
    bits += 8;
    while (bits >= 5) {
      bits -= 5;
      output += alphabet[(buffer >> bits) & 0x1f];
    }
  }
  // 处理剩余不足 5 位的尾部
  if (bits > 0) {
    output += alphabet[(buffer << (5 - bits)) & 0x1f];
  }
  // RFC 4648 标准要求填充 = 至 8 的倍数
  if (padding) {
    while (output.length % 8 !== 0) output += '=';
  }
  return output;
}

Crockford 校验和实现

function crockfordChecksumChar(bytes) {
  // 用大数取模算法避免精度问题
  let mod = 0;
  for (const byte of bytes) {
    mod = (mod * 256 + byte) % 37;
  }
  return '0123456789ABCDEFGHJKMNPQRSTVWXYZ*~$=U'[mod];
}

注意:直接用 Number 计算 value mod 37 会因 Number.MAX_SAFE_INTEGER(2^53-1)限制丢失精度。逐字节累积取模可避免此问题。

解码时的易混字符归一化

function decodeCrockfordChar(ch) {
  const table = buildCrockfordDecodeTable(); // 0-9A-Z + 归一化映射
  const val = table[ch];
  if (val === undefined) throw new Error(`非法字符 "${ch}"`);
  return val;
}
// I/i/L/l → 1, O/o → 0 已在 table 中预置

真实应用场景

TOTP 共享密钥

Google Authenticator、Authy 等 TOTP 应用要求用户扫描二维码或手动输入 Base32 编码的共享密钥:

密钥(Base32):JBSWY3DPEHPK3PXP
密钥(Hex):  48656c6c6f48656c6c6f

手动输入时,用户通过「J-B-S-W-Y-3-D-P」逐字符输入,无需区分大小写。Base32 的字符集设计让口述(电话支持场景)也变得可行。

账号号码

银行账号、订单号、会员卡号等需要人工输入的标识符,Crockford Base32 + 校验和是理想选择:

  • 去除 I/L/O/U 避免最常见混淆
  • 校验和识别单字符输入错误
  • 不区分大小写降低输入门槛
  • = 填充更紧凑

密钥指纹

SSH 公钥指纹、PGP 密钥 ID 等场景,Crockford Base32 让用户在核对指纹时更不容易出错:

SSH 指纹(Base32):9KM8X1X5P3Q7Y2R6
                   ^^^^^^^^^^^^^^^^^^^
用户核对时即使误输 I 当 1 也能正确识别

工具矩阵联动

本站的 Base32 编解码工具与以下工具形成「编码体系」闭环:

用户可:①Hash 工具计算摘要后用 Base32 工具编码为 Crockford 格式便于口述核对;②Base64 工具解码 JWT 后用 Base32 工具重新编码用于 DNS 场景;③Base64 图片工具生成 Data URL 后用 Base32 工具转换为二维码友好格式。

总结

Base32 不是 Base64 的替代品,而是互补品。RFC 4648 标准 Base32 适合机器间传输(TOTP、DNS),Crockford Base32 适合人工输入场景(账号、密钥指纹)。两者结合,覆盖了从机器处理到人工交互的全场景编码需求。

选择 Base32 还是 Base64 的核心决策点:数据是否需要人工输入或口述? 如果是,Base32(特别是 Crockford 变体)是更好的选择;如果纯机器处理且追求体积最小,Base64 仍是首选。