1. 简介
Base64,是一种二进制转可读字符的编码方式。简单来说,它提供了一种方式,将一系列二进制序列转换为 ASCII 的字符序列,以 64 进制的方式(这是它的名字的意义, 64-based,以64为基数)。
Base64 的主要用途是在无法方便地直接传递二进制形式的数据时候,可以通过转化为 ASCII 字符串来存储和传递这些数据。例如:
- 编码图片(然后在 HTML img 标签中内联、在文本文件中保存等等)
- 使用 SMTP 发送邮件附件
- JWT 令牌用于身份验证
- 等等很多很多…
2. 标准
Base 64 会将 6 个 bit 的二进制转换到 1 个 ASCII 字符。
因为是以 64 位基数,即 2⁶ 种可表示的状态,因此编码的最小单位是 6 位二进制(也就是 6 bit)。为了表示这些状态,就从 ASCII 中取出了 64 个字符用于编码。RFC 4648 中规定的编码对应表如下:
Index | Binary | Char | Index | Binary | Char | Index | Binary | Char | Index | Binary | 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 | / |
|||
Padding | = |
你也看到了,上面的表中除了 64 个字符以外,还有一个叫做 Padding 的字符。和它的字面意思一样,这个字符就是用来补齐的。为什么要补齐?因为规定 Base 64 编码的字符串需要是 4 个字符的整数。
具体怎么补齐呢?我们来看几个例子。
e.g. 1: 将 ASCII 表示的字符串 “Man” 使用 base64 编码
Source | Text (ASCII) | M | a | n | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Octets | 77 (0x4d) | 97 (0x61) | 110 (0x6e) | ||||||||||||||||||||||
Bits | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | |
Base64 encoded |
Sextets | 19 | 22 | 5 | 46 | ||||||||||||||||||||
Character | T | W | F | u | |||||||||||||||||||||
Octets | 84 (0x54) | 87 (0x57) | 70 (0x46) | 117 (0x75) |
一个 ASCII 字符占 1 字节 (也就是 8 位二进制),所以三个 ASCII 就是 24 位二进制,正好是整 6 bit 的。所以我们可以将它编码之后获得 “TWFu” 这个Base 64 字符串。
e.g. 2: 将 ASCII 表示的字符串 “Ma” 使用 base64 编码
Source | Text (ASCII) | M | a | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Octets | 77 (0x4d) | 97 (0x61) | |||||||||||||||||||||||
Bits | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | |||||||
Base64 encoded |
Sextets | 19 | 22 | 4 | Padding | ||||||||||||||||||||
Character | T | W | E | = | |||||||||||||||||||||
Octets | 84 (0x54) | 87 (0x57) | 69 (0x45) | 61 (0x3D) |
在不满 6 bit 的时候,最后的位数用 0 补齐,并且会在解码的时候被丢弃。然后加上 ‘=’ 来补齐到 4 个 ASCII 字符。
3. 使用和实现
是的,事实上在大多数时候,你并不需要手动编码和解码 Base 64 了。
有很多在线的 ASCII 转换器,比如:
Cryptii : 一个相当好用的实时 Base 64 转换器。支持文字、二进制和 Base 64 互相转换。
Base64.Guru : 提供了非常多种的文件格式对 Base 64 的编码解码支持。
以及,如果正在编程,你也可以放心。在大多数的高级程序语言中,都已经有现成的库可以帮你编码和解码 Base 64 了。比如这边是一个调用 Swift Foundation
库的的方法来编码和解码 Base 64 的例子。
import Foundation extension String { func base64Encode() -> String? { if let data = self.data(using: .utf8) { return data.base64EncodedString() } return nil } func base64Decode() -> String? { if let data = Data(base64Encoded: self, options: .ignoreUnknownCharacters) { return String(data: data, encoding: .utf8) } return nil } } let base64String = "SGVsbG8sIHdvcmxkIQ==" print("Encoded base64 string: \(base64String)") print("Decoded from base64 string: \( base64String.base64Decode() ?? "" )")
输出如下:
Encoded base64 string: SGVsbG8sIHdvcmxkIQ== Decoded from base64 string: Hello, world!
最后需要提醒的一点是:(重要的事情说三遍)
Base 64 不是加密算法!
Base 64 不是加密算法!
Base 64 不是加密算法!
Base 64 仅可用于编码。请勿将 Base 64 用于加密、散列用途。