18-base64-encoding
18. 计算机编码规则之:Base64编码
简介
我们知道计算机中的文件可以分为两种,一种是人肉眼可读的文本类文件,一种是肉眼不可读的二进制文件。一般来说二进制文件如果用文本编辑器打开的话会显示乱码,并且二进制文件和文本文件的存储和传输方式是不一样的,那么有没有什么办法将二进制文件转换成为文本文件进行传输或者存储呢?答案是肯定的。
这种编码方式就是我们今天要讲到的Base64编码。
Base64和它的编码原理
Base64是一种将二进制编码格式转换为text编码的一种形式。我们知道二进制编码是0和1的形式,它的单位通常是一个字节,也就是8bits,每个bit表示的是0或者1。
而文本编码的格式有很多种,最早也就是最简单的编码格式就是ASCII编码,ASCII编码的全称是American Standard Code for Information Interchange,也就是美国信息交换标准代码,它主要表示的是常用的一些西欧字符。
ASCII的编码范围是0x00-0x7F,用十进制来表示就是0-127,总共128个字符,刚好是7bits表示的范围。
ASCII编码中包含了33个控制字符和95个可打印的字符,如下所示:
16进制
10进制
2进制
16进制
10进制
2进制
0x00
0
0
NUL 空
0x40
64
1000000
@
0x01
1
1
SOH 标题开始
0x41
65
1000001
A
0x02
2
10
STX 正文开始
0x42
66
1000010
B
0x03
3
11
ETX 正文结束
0x43
67
1000011
C
0x04
4
100
EOT 传输结束
0x44
68
1000100
D
0x05
5
101
ENQ 询问字符
0x45
69
1000101
E
0x06
6
110
ACK 承认
0x46
70
1000110
F
0x07
7
111
BEL 报警
0x47
71
1000111
G
0x08
8
1000
BS 退一格
0x48
72
1001000
H
0x09
9
1001
HT 横向制表
0x49
73
1001001
I
0x0A
10
1010
LF 换行
0x4A
74
1001010
J
0x0B
11
1011
VT 垂直制表
0x4B
75
1001011
K
0x0C
12
1100
FF 走纸控制
0x4C
76
1001100
L
0x0D
13
1101
CR 回车
0x4D
77
1001101
M
0x0E
14
1110
SO 移位输出
0x4E
78
1001110
N
0x0F
15
1111
SI 移位输入
0x4F
79
1001111
O
0x10
16
10000
DLE 数据链路转义
0x50
80
1010000
P
0x11
17
10001
DC1 设备控制1
0x51
81
1010001
Q
0x12
18
10010
DC2 设备控制2
0x52
82
1010010
R
0x13
19
10011
DC3 设备控制3
0x53
83
1010011
S
0x14
20
10100
DC4 设备控制4
0x54
84
1010100
T
0x15
21
10101
NAK 否定
0x55
85
1010101
U
0x16
22
10110
SYN 空转同步
0x56
86
1010110
V
0x17
23
10111
ETB 信息组传送结束
0x57
87
1010111
W
0x18
24
11000
CAN 作废
0x58
88
1011000
X
0x19
25
11001
EM 纸尽
0x59
89
1011001
Y
0x1A
26
11010
SUB 换置
0x5A
90
1011010
Z
0x1B
27
11011
ESC 换码
0x5B
91
1011011
[
0x1C
28
11100
FS 文字分隔符
0x5C
92
1011100
\
0x1D
29
11101
GS 组分隔符
0x5D
93
1011101
]
0x1E
30
11110
RS 记录分隔符
0x5E
94
1011110
^
0x1F
31
11111
US 单元分隔符
0x5F
95
1011111
_
0x20
32
100000
(space)
0x60
96
1100000
`
0x21
33
100001
!
0x61
97
1100001
a
0x22
34
100010
”
0x62
98
1100010
b
0x23
35
100011
#
0x63
99
1100011
c
0x24
36
100100
$
0x64
100
1100100
d
0x25
37
100101
%
0x65
101
1100101
e
0x26
38
100110
&
0x66
102
1100110
f
0x27
39
100111
'
0x67
103
1100111
g
0x28
40
101000
(
0x68
104
1101000
h
0x29
41
101001
)
0x69
105
1101001
i
0x2A
42
101010
*
0x6A
106
1101010
j
0x2B
43
101011
+
0x6B
107
1101011
k
0x2C
44
101100
,
0x6C
108
1101100
l
0x2D
45
101101
-
0x6D
109
1101101
m
0x2E
46
101110
.
0x6E
110
1101110
n
0x2F
47
101111
/
0x6F
111
1101111
o
0x30
48
110000
0
0x70
112
1110000
p
0x31
49
110001
1
0x71
113
1110001
q
0x32
50
110010
2
0x72
114
1110010
r
0x33
51
110011
3
0x73
115
1110011
s
0x34
52
110100
4
0x74
116
1110100
t
0x35
53
110101
5
0x75
117
1110101
u
36
54
110110
6
0x76
118
1110110
v
0x37
55
110111
7
0x77
119
1110111
w
0x38
56
111000
8
0x78
120
1111000
x
0x39
57
111001
9
0x79
121
1111001
y
0x3A
58
111010
:
0x7A
122
1111010
z
0x3B
59
111011
;
0x7B
123
1111011
{
0x3C
60
111100
<
0x7C
124
1111100
|
0x3D
61
111101
=
0x7D
125
1111101
}
0x3E
62
111110
>
0x7E
126
1111110
~
0x3F
63
111111
?
0x7F
127
1111111
DEL 删除
Base64就是从ASCII编码中挑选出64个字符和二进制一个字节8bits进行映射,这也就是Base64中64的含义。为什么要选择ASCII编码呢?这是因为ASCII编码是最早出现的编码形式,几乎所有的计算机应用都对其完全支持,不会出现数据传输过程中的内容转换,非常的安全。
当然Base64编码也有多种编码形式,比如在MIME中,Base64选择的是A-Z, a-z, 和 0-9 总共62个字符,再加上其他自选的两个字符组成了64个编码字符。
64个字符用二进制表示是6bits,而常用的二进制使用一个字节来表示,也就是8bits,那么问题来了,怎么将8bits的二进制用6bits的Base64字符来表示呢?
很简单,我们只需要将3个8bits连接起来,变成24bits,这样就可以用4个Base64来表示了。
为什么必须对二进制进行转换呢?这是因为互联网中的某些传输协议只支持某些特定的字符集,如果是其他的字符集是不支持的。比如说常用的发送电子邮件的附件。因为SMTP协议最开始设计的时候是支持7 位 ASCII 字符,所以如果要传输文件的话,我们需要对文件进行编码之后再进行传输。
另外Base64的一种用法就是在HTML中将图片嵌入到网页中,从而实现图片的展示。
虽然Base64很好用,但是因为其只能使用6bits的字符映射集,所以会造成数据映射的损失,从而导致二进制文件编码过后文件体积变大的缺点。
Base64的变体
Base64简单点说就是bit到bit之间的映射,那么肯定不止一种映射方式,我们来看下Base64编码方式的各种变体,通常来说前62位基本上是一样的,不同之处在后面两个字符,以及用于填充的字符(这在某些协议中可能是强制性的,或者在其他协议中可能被删除)。
下表是常见的Base64编码的变体:
第62位
第63位
补全符
RFC 1421: Base64 for Privacy-Enhanced Mail (deprecated)
+
/
=
mandatory
RFC 2045: Base64 transfer encoding for MIME
+
/
=
mandatory
RFC 2152: Base64 for UTF-7
+
/
No
RFC 3501: Base64 encoding for IMAP mailbox names
+
,
No
RFC 4648: base64 (standard)
+
/
=
optional
RFC 4648: base64url (URL- and filename-safe standard)
-
_
=
optional
RFC 4880: Radix-64 for OpenPGP
+
/
=
mandatory
Base64的编码细节
上一节我们讲到了Base64编码的基本原则和一些常见的变体,那么到底是如何进行映射的呢?
本节我们会以Base64的标准形式RFC 4648为例来进行详细的讲解。
RFC 4648选择+和/这两个字符作为编码中的第62位和63位,并且选择=作为补全字符。
首先来观察一下RFC 4648的映射表:
索引
二进制
字符
索引
二进制
Char
索引
二进制
Char
索引
二进制
Char
0
000000
A
16
010000
Q
32
100000
g
48
110000
w
1
000001
B
17
010001
R
33
100001
h
49
110001
x
2
000010
C
18
010010
S
34
100010
i
50
110010
y
3
000011
D
19
010011
T
35
100011
j
51
110011
z
4
000100
E
20
010100
U
36
100100
k
52
110100
0
5
000101
F
21
010101
V
37
100101
l
53
110101
1
6
000110
G
22
010110
W
38
100110
m
54
110110
2
7
000111
H
23
010111
X
39
100111
n
55
110111
3
8
001000
I
24
011000
Y
40
101000
o
56
111000
4
9
001001
J
25
011001
Z
41
101001
p
57
111001
5
10
001010
K
26
011010
a
42
101010
q
58
111010
6
11
001011
L
27
011011
b
43
101011
r
59
111011
7
12
001100
M
28
011100
c
44
101100
s
60
111100
8
13
001101
N
29
011101
d
45
101101
t
61
111101
9
14
001110
O
30
011110
e
46
101110
u
62
111110
+
15
001111
P
31
011111
f
47
101111
v
63
111111
/
补全符
=
我们来以单词man为例,来观察一下Base64的编码流程。
man这个单词在ASCII中分别用77, 97和110表示,转换成为二进制就是01001101, 01100001 和 01101110。
将上面的三个二进制合并在一起就成了:010011010110000101101110, 总共24-bit,从上面的表中选择出对应的字符,所以我们可以得到man经过base64编码之后得到:TWFu。
上面的例子中,man刚好是3个字符,也就是24个bits,可以用base64完整的表示。如果我们只有ma这两个字符,应该怎么进行编码呢?
和上面一样,ma的二进制分别是01001101, 01100001,合并起来就是0100110101100001。
但是上面的bits只有16位,因为一个base64是6bits,所以可以用3个base64来表示,因为原始的bits少了两位,所以用0来补全:
0100110101100001+00 = 010011010110000100。
010011010110000100转换成为base64就是TWE,因为base64编码需要4个字符,所以最后的字符用=来补全,也就是说me经过base64之后变成TWE=。
总结
以上就是Base64的基本含义和转换规则,其实协议很简单,将要转换的数据变成二进制,然后对照转换表格进行转换和补全即可。
最后更新于