base64原理
一、 base64是什么?
按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符,等号“=”用来作为后缀用途。
二、 base64的作用及用途
作用:
- 实现简单的数据加密,使用户一眼望去完全看不出真实数据内容,base64算法的复杂程度要小,效率要高相对较高。
- 某些系统或应用,只能使用ASCII字符,例如Email,需使用base64对数据进行编码。
用途:
- 在MIME中,base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。在Email的传送过程中,由于历史原因,Email只被允许传送ASCII字符,即一个8位字节的低7位(0-127)。因此,如果用户发送了一封带有非ASCII字符(即字节的最高位是1)的Email通过有“历史问题”的网关时就可能会出现问题。网关可能会把最高位置为0。这个时候,问题出现了。
- Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java持久化系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。然而,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。为解决此问题,可采用一种用于URL的改进Base64编码,它不在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“*”和“-”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。另有一种用于正则表达式的改进Base64变种,它将“+”和“/”改成了“!”和“-”,因为“+”,“*”以及前面在IRCu中用到的“[”和“]”在正则表达式中都可能具有特殊含义。
三、 Base64的原理
将输入的二进制数据流以每次读取6个bit的方式读取,不足6位的后补0,将每3个8位二进制转换为4个6位二进制,也就是说每3个8位字节将编码为4个6位字节(3×8 → 4×6);不满4个字节的以“=”填充。其实这4个六位字节仍然是8位,只不过高两位被设置为0。当一个字节只有6位有效时,它的取值空间为0 到 2的6次方减1 即63,也就是说被转换的Base64编码的每一个编码的取值空间为(0-63)。事实上,0-63之间的ASCII码有许多不可见字符,所以应该再做一个映射,映射表(码表)为:
The Base64 Alphabet table
Value | Char | Value | Char | Value | Char | Value | Char | |||
---|---|---|---|---|---|---|---|---|---|---|
0 | A |
16 | Q |
32 | g |
48 | w |
|||
1 | B |
17 | R |
33 | h |
49 | x |
|||
2 | C |
18 | S |
34 | i |
50 | y |
|||
3 | D |
19 | T |
35 | j |
51 | z |
|||
4 | E |
20 | U |
36 | k |
52 | 0 |
|||
5 | F |
21 | V |
37 | l |
53 | 1 |
|||
6 | G |
22 | W |
38 | m |
54 | 2 |
|||
7 | H |
23 | X |
39 | n |
55 | 3 |
|||
8 | I |
24 | Y |
40 | o |
56 | 4 |
|||
9 | J |
25 | Z |
41 | p |
57 | 5 |
|||
10 | K |
26 | a |
42 | q |
58 | 6 |
|||
11 | L |
27 | b |
43 | r |
59 | 7 |
|||
12 | M |
28 | c |
44 | s |
60 | 8 |
|||
13 | N |
29 | d |
45 | t |
61 | 9 |
|||
14 | O |
30 | e |
46 | u |
62 | + |
|||
15 | P |
31 | f |
47 | v |
63 | / |
这样就可以将3个8位字节,转换为4个可见字符。也就是说,转换后的字符串要比原来的长1/3,扩张率为3:4。
例子:
- 当字符串字符个数为3的倍数时;比如字符串“ABC”,其在计算机内存中的十六进制表示为$41、$42、$43,十进制表示为“65”“66”“67”;二进制表示为01000001 01000010 01000011 将这三个二进制数依次取6bit, 010000/01 0100/0010 01/000011 就转换成了: 010000 010100 001001 000011 将这四个二进制数转换成十六制数为:$10,$14,$9,$3,十进制数位为16,20,9,3。对照上面的码表,分别查找出对应的字符为Q,U,J,D。也是就说字符串“ABC”经过BASE64编码后得出“QUJD”。 这是最简单的情况,即ASCII码字符数刚好可以被3整除。接着继续讨论余数为2、为1的情况。
- 当余数为2时,比如字符串“ce”,其在内存中十六进制表示为$63,$65;十进制表示表示99,101;二进制表示为 01100011 01100101 依次取6bit 011000/11 0110/0101 这时,第3个字符不足6位,在后面补零,也就是0101变成010100。转换结果为 011000 110110 010100 这3个二进制数转换成十六制数为$18,$36,$14;十进制数位为24,54,20。对照码表得出结果“Y2U”。编码后的字符个数不足4位,用“=”填充,最后编码得出“Y2U=”。
- 当余数为1时,比如字符串“{”,其在内存中的十六进制表示为$7B,十进制为123,二进制位表示为 01111011 依次取6bit 011110/11 补0后为 011110/110000 转换结果为011110和110000 这两个二进制数转换成十六进制数为$1E,$30,十进制数为30,48。对照码表得出结果为“ew”,补上“=”,最后编码得出“ew= =”。 解码也很简单,是编码的逆过程,即将每个字符对照码表换算成6bit的二进制数,然后重组起来,按8位进行截取,得出原码。