你应该知道的Base64内容传输编码

Base64 内容传输编码是什么?

用较官方的说法来讲,Base64编码被设计用来表示任意长度的8bit字节序列,它进行编码和解码的算法都很简单,编码后的数据不需要可读性,并且编码后的数据比未编码的数据始终大33%。简言之,Base64就是使用64个可打印字符来表示任意的二进制数据。

请参考RFC2045第6.8小节关于Base64编码的描述
RFC2045 Base64 Content Transfer Encoding

Base64编码原理

Base64的编码原理并不复杂,首先我们从US-ASCII编码表中取了65个可打印字符用作Base64的编码表,这样就允许我们只使用6bit(6位二进制数据)来表示这些字符,即2^6=64个。那么还有多出来的一个’=’字符当填充字符(后面解释我们为什么需要一个填充字符)来做补位,那么下面我先给出Base64的编码表,然后我们在看看怎么进行编码。

  • The Base64 Alphabet Table
bin hex dec character bin hex dec character bin hex dec character
0000 0000 0x00 0 A 0001 1010 0x1A 26 a 0011 0100 0x34 52 0
0000 0001 0x01 1 B 0001 1011 0x1B 27 b 0011 0101 0x35 53 1
0000 0010 0x02 2 C 0001 1100 0x1C 28 c 0011 0110 0x36 54 2
0000 0011 0x03 3 D 0001 1101 0x1D 29 d 0011 0111 0x37 55 3
0000 0100 0x04 4 E 0001 1110 0x1E 30 e 0011 1000 0x38 56 4
0000 0101 0x05 5 F 0001 1111 0x1F 31 f 0011 1001 0x39 57 5
0000 0110 0x06 6 G 0010 0000 0x20 32 g 0011 1010 0x3A 58 6
0000 0111 0x07 7 H 0010 0001 0x21 33 h 0011 1011 0x3B 59 7
0000 1000 0x08 8 I 0010 0020 0x22 34 i 0011 1100 0x3C 60 8
0000 1001 0x09 9 J 0010 0011 0x23 35 j 0011 1101 0x3D 61 9
0000 1010 0x0A 10 K 0010 0100 0x24 36 k 0011 1110 0x3E 62 +
0000 1011 0x0B 11 L 0010 0101 0x25 37 l 0011 1111 0x3F 63 /
0000 1100 0x0C 12 M 0010 0110 0x26 38 m pad pad pad =
0000 1101 0x0D 13 N 0010 0111 0x27 39 n
0000 1110 0x0E 14 O 0010 1000 0x28 40 o
0000 1111 0x0F 15 P 0010 1001 0x29 41 p
0001 0000 0x10 16 Q 0010 1010 0x2A 42 q
0001 0001 0x11 17 R 0010 1011 0x2B 43 r
0001 0010 0x12 18 S 0010 1100 0x2C 44 s
0001 0011 0x13 19 T 0010 1101 0x2D 45 t
0001 0100 0x14 20 U 0010 1110 0x2E 46 u
0001 0101 0x15 21 V 0010 1111 0x2F 47 v
0001 0110 0x16 22 W 0011 0000 0x30 48 w
0001 0111 0x17 23 X 0011 0001 0x31 49 x
0001 1000 0x18 24 Y 0011 0010 0x32 50 y
0001 1001 0x19 25 Z 0011 0011 0x33 51 z

有了上面的编码表,我们就可以开始处理数据呢,对于输入的数据来讲,我们以24-bit(3个连续的8-bit字节)为一组作为输入,将输入的24-bit数据,按照从左到右的顺序,分成连续的4组6-bit的数据,每组6-bit数据可以看作是Base64编码表中的索引,查表后我们可以得到4个可打印字符作为输出。下面以”cat”字符串为例示范。
假设当前字符串编码集是单字节的ascii编码,我们以字符串’cat’为例。

那么我们可以得到字符串’cat’的base64编码结果是’Y2F0’,把一个24-bit的数据编码成了4个字符。各种编程语言都提供了Base64编码的实现。你可以在浏览器控制台中用JS验证下结果是否正确。

1
2
btoa('cat') //output: Y2F0
atob('Y2F0') // output: cat
  • 特殊的情况
    当然,我们不可能所有的数据的长度都是24的整数倍,如果我们按照规则进行编码操作,剩下的最后一组数据长度是小于24-bit的话,我们应该如何处理呢?
    一般我们是直接在右边补上0bit位来组成一个完整的24-bit的输入组,这样我们还是可以按前面定义的规则划分成4个6-bit的组来进行编码,那么就剩下两种需要填充字符串补位的情况:
    (1)如果最后一个输入长度是8-bit的话,那相当于我们要补16-bit才能凑成一组24-bit一组的输入,最后编码完成后的输出是2个正常的编码字符,2个’=’填充字符。这样我们在解码时就知道我们填充了多少位的数据。
    (2)如果最后一个输入长度是16-bit的话,那就是说我们需要补充8-bit的来凑一组24-bit的输入,最后编码完成后的输出是3个正常的编码字符和1个’=’填充字符。

基于上面描述的两种情况,我们继续在浏览器中验证一下

1
2
3
4
5
6
// last input 8-bit fewer than 24-bit, need two pad character
btoa('catt') //output: Y2F0dA==
atob('Y2F0dA==') // output: catt
// last input 16-bit fewer than 24-bit, need one pad character
btoa('catty') //output: Y2F0dHk=
atob('Y2F0dHk=') // output: catty