Base64 非常好,可是有些时候我们讨厌引入标点符号 +/=
。
Base32 每 5bits 转换成一个字符,数据膨胀至 8/5 = 1.6 倍(相比之下,Base64 膨胀至 4/3 = 1.33 倍)。
Base16 就更简单了,就是 16 进制编码(),最大优点是不存在补位的情况,缺点是每个字节转成两个字符,数据量翻一番。
参照前面 Base64 的例子,我们手算一遍 Base32 和 Base16 版本的 hello world 转换。
Base32
根据 RFC4648:
- Base32 字母表为:
A-Z, 2-7
PS: 0 和 1 因为和字母 O 和 I 容易混淆,所以跳过。 - 最后长度填充至 8 的倍数
bin dec hex char
-------- --- --- ----
01101000 104 68 h
01100101 101 65 e
01101100 108 6c l
01101100 108 6c l
01101111 111 6f o
00100000 32 20
01110111 119 77 w
01101111 111 6f o
01110010 114 72 r
01101100 108 6c l
01100100 100 64 d
按五位一个的话就是(PS: 后方须补两个 0: 8 x 11 = 88 = 5 x 18 - 2
):
bin dec hex b32
----- --- --- ----
01101 13 0d N
00001 1 01 B
10010 18 12 S
10110 22 16 W
11000 24 18 Y
11011 27 1b 3
00011 3 03 D
01111 15 0f P
00100 4 04 E
00001 1 01 B
11011 27 1b 3
10110 22 16 W
11110 30 1e 6
11100 28 1c 4
10011 19 13 T
01100 12 0c M
01100 12 0c M
10000 16 10 Q
得到 ceil(11 x 1.6) = 18
个字符,最后填充至 24 个字符,也就是加 6 个等于号:
NBSWY3DPEB3W64TMMQ======
Base32 验证
echo -n 'hello world' | base32
NBSWY3DPEB3W64TMMQ======
Base16
bin dec hex b16
---- --- --- ----
0110 6 06 6
1000 8 08 8
0110 6 06 6
0101 5 05 5
0110 6 06 6
1100 12 0c C
0110 6 06 6
1100 12 0c C
0110 6 06 6
1111 15 0f F
0010 2 02 2
0000 0 00 0
0111 7 07 7
0111 7 07 7
0110 6 06 6
1111 15 0f F
0111 7 07 7
0010 2 02 2
0110 6 06 6
1100 12 0c C
0110 6 06 6
0100 4 04 4
68656C6C6F20776F726C64
Base16 验证
echo -n 'hello world' | base16 -c
68656C6C6F20776F726C64
填充规则
直到研究 Base32 才发现我对 Base64 填充违规有一点误解。
Base64 6bits 一组,可能会有以下三种情况:
- 3n => 4n
- 3n + 1 => 4n + 1 + 2, 补 4 个 0,加两个等于号
- 3n + 2 => 4n + 3 + 1, 补 2 个 0,加一个等于号
我理解的填充规则是为了标记补 0 数,等于号数量乘以二。解析的时候计算等于号的数量,然后将前面的字符转换成字节,最后按照等于号数量乘以二去掉后缀 0。
没想到 RFC 规范中说的是对齐到 4 的倍数。
这两种理解在 Base64 中是一个效果,但是 Base32 中不一样。
Base32 5bits 一组,会有以下几种情况:
- 5n => 8n
- 5n + 1: 8n + 1, 多了 3bits (8 - 5),需补 2 个 0
- 5n + 2: 8n + 3, 还多了 1bit (8 x 2 - 5 x 3),需补 4 个 0
- 5n + 3: 8n + 4, 还多了 4bits (8 x 3 - 5 x 4),需补 1 个 0
- 5n + 4: 8n + 6, 还多了 2bits (8 x 4 - 5 x 6),需补 3 个 0
如果按照我的理解,那就分别加上 0,2, 4, 1, 3 个等于号,最终分别是 8n, 8n + 2, 8n + 4, 8n + 5, 8n + 7 个字符。
但是规范是要求对齐到 8 的倍数,那就是分别需要加上 0, 6, 4, 3, 2 个等于号,除了第一个,下面四种情况填充等于号之后都是 8(n+1) 个字符。
助记:字节数,除五取余,补零 2413,填充 6432。
其他的 Base32 方案
z-base-32
字母表: ybndrfg8ejkmcpqxot1uwisza345h769
crockford's base32
字母表: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
- 大小写不敏感
- 拿掉四个字母:
ILO
- 如果出现字母 o 当做 0 处理
- 如果出现字母 i, l, 当做 1 处理
手写友好。
base32hex
相当于沿着十六进制编码的思路拓展。
字母表: 0123456789ABCDEFGHIJKLMNOPQRSTUV
geohash
字母表: 0123456789bcdefghjkmnpqrstuvwxyz
拿掉四个字母: ailo
video games (nintendo)
字母表: 0123456789bcdfghjklmnpqrstvwxyz
拿掉 AEIOU
五个元音字母,补充一个标点符号,避免出现脏话。
word-safe base32
word-safe base20: 23456789CFGHJMPQRVWX
, 8digits+12uppers
word-safe base32: 23456789CFGHJMPQRVWXcfghjmpqrvwx
, 8digits+12uppers+12lowers
设计目标是避免形成单词。