BASE64编码详解

base64编码是将任意二进制序列编码成ASCII字符(可打印字符)序列的编码方案

在base64编码中,每3个二进制字节编码为4个ASCII字符,也就是将3个字节(24位二进制位)拆分成4个(6个二进制位的)数,再将这4个数根据base64的编码表来映射为4个ASCII字符;对于二进制序列的字节数不是3的倍数的,需要在序列最后补充1个或2个字节0 来对齐3个字节再转换

编码时,以3个字节为单位,转换为4个字符;解码时,以4个字符为单位,转换为3个字节

base64编码表

0x0  0x1  0x2  0x3  0x4  0x5  0x6  0x7  0x8  0x9  0xa  0xb  0xc  0xd  0xe  0xf  0x10  0x11  0x12  0x13  0x14  0x15  0x16  0x17  0x18  0x19  0x1a  0x1b  0x1c  0x1d  0x1e  0x1f  0x20  0x21  0x22  0x23  0x24  0x25  0x26  0x27  0x28  0x29  0x2a  0x2b  0x2c  0x2d  0x2e  0x2f  0x30  0x31  0x32  0x33  0x34  0x35  0x36  0x37  0x38  0x39  0x3a  0x3b  0x3c  0x3d  0x3e  0x3f
0    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15   16    17    18    19    20    21    22    23    24    25    26    27    28    29    30    31    32    33    34    35    36    37    38    39    40    41    42    43    44    45    46    47    48    49    50    51    52    53    54    55    56    57    58    59    60    61    62    63
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     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     0     1     2     3     4     5     6     7     8     9     +     /

写成C语言数组是这样的

char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

拆分过程详解

下图中,BINARY一列i1-i3表示的是转换前的字节,小方格里的数字表示二进制位的位置(大数字表示高位),BEFORE和AFTER分别表示拆分前后的二进制数,o1-o4表示的是拆分后的4个数字

        +---------------+---------------+---------------+
BINARY   |i1             |i2             |i3             |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
BEFORE   |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
AFTER    |5|4|3|2|1|0|5|4|3|2|1|0|5|4|3|2|1|0|5|4|3|2|1|0|
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         |o1         |o2         |o3         |o4         |
         +-----------+-----------+-----------+-----------+
BASE64   |table[o1]  |table[o2]  |table[o3]  |table[o4]  |
         +-----------+-----------+-----------+-----------+

需要注意的是,从左往右,字节顺序是从低到高的,而二进制数位的顺序是从高到低的

二进制序列"\x01\x02\x03" 将编码成AQID ,过程如下:

        +---------------+---------------+---------------+
BINARY   |\x01           |\x02           |\x03           |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
BEFORE   |0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|1|
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
AFTER    |0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|1|
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         |0          |16         |8          |3          |
         +-----------+-----------+-----------+-----------+
BASE64   |A          |Q          |I          |D          |
         +-----------+-----------+-----------+-----------+

需要注意的是,字节顺序是从低到高的,而二进制数位的顺序是从高到低的

字节数不是3的倍数

上面提到,假如要编码的二进制序列的字节数不是3的倍数,那么需要用字节0 将此序列补齐为3的倍数。

设序列长度为n,如果n % 3 == 1 ,最后一组则只有一个字节,需要补充两个字节0 再转换。 这样,最后一组转换后的ASCII字符只有前两个是有效的,有效是指编码后的数据使用了二进制序列补充前的数据,在这也就是说余下的一个字节至少需要两个ASCII字符编码,后两个必为A -- 0 。为了表明后两个字节是补充的,需要将最后两个A替换为= 。

同样的道理,如果n % 3 == 2 ,需要将最后一个A 替换为=

比如,编码"\x01\x02\x03\x04"

BINARY  \x01      \x02      \x03      \x04
        \x01      \x02      \x03      \x04      0         0
BEFORE  00000001  00000010  00000011  00000100  00000000  00000000
AFTER   000000 010000 001000 000011 000001 000000 000000 000000
        0      16     8      3      1      0      0      0
BASE64  A      Q      I      D      B      A      =      =

编码与解码的实现(C++)

github.com/luzhlon/algo

编辑于 2017-07-12

文章被以下专栏收录