Base64

Base64（基底64）是一种基于64个可打印字符来表示二进制数据的表示方法。由于log(2,64)，所以每6个位元为一个单元，对应某个可打印字符。3个字节相当于24个位元，对应于4个Base64单元，即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母`A-Z`、`a-z`、数字`0-9`，这样共有62个字符，此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法，和之后BinHex的版本使用不同的64字符集来代表6个二进制数字，但是不被称为Base64。

Base64常用于在通常处理文本数据的场合，表示、传输、存储一些二进制数据，包括MIME的电子邮件及XML的一些复杂数据。

## RFC 4648 标准的 Base64 索引表

十进制｜二进制｜字符｜ ｜十进制｜二进制｜字符｜ ｜十进制｜二进制｜字符｜ ｜十进制｜二进制｜字符

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 is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.
```

经过Base64编码之后变成：

编码“Man”的结果为`Man`，详细原理如下：

文本｜M｜a｜n

ASCII编码｜77｜97｜110

二进制位｜0｜1｜0｜0｜1｜1｜0｜1｜0｜1｜1｜0｜0｜0｜0｜1｜0｜1｜1｜0｜1｜1｜1｜0

索引｜19｜22｜5｜46

Base64编码｜T｜W｜F｜u

在此例中，Base64算法将3个字节编码为4个字符。

如果要编码的字节数不能被3整除，最后会多出1个或2个字节，那么可以使用下面的方法进行处理：先使用0字节值在末尾补足，使其能够被3整除，然后再进行Base64的编码。在编码后的Base64文本后加上一个或两个`=`号，代表补足的字节数。也就是说，当最后剩余两个八位(待补足)字节（2个byte）时，最后一个6位的Base64字节块有四位是0值，最后附加上两个等号；如果最后剩余一个八位(待补足)字节（1个byte）时，最后一个6位的base字节块有两位是0值，最后附加一个等号。

参考下表：

文本（1 Byte）｜A

二进制位｜0｜1｜0｜0｜0｜0｜0｜1｜0｜0｜0｜0

二进制位（补0）｜0｜1｜0｜0｜0｜0｜0｜1｜0｜0｜0｜0｜留空填充｜留空填充

Base64编码｜Q｜Q｜=｜=

文本（2 Byte）｜B｜C

二进制位｜0｜1｜0｜0｜0｜0｜1｜0｜0｜1｜0｜0｜0｜0｜1｜1｜0｜0

二进制位（补0）｜0｜1｜0｜0｜0｜0｜1｜0｜0｜1｜0｜0｜0｜0｜1｜1｜0｜0｜留空填充

Base64编码｜Q｜k｜M｜=

## 应用

### 变种

base64编码对应的64个可打印字符在一些特定的程序或协议中可能不适合使用，特别是字符表第62位（`+`）、63位（`/`）和填充字符（`=`），因此存在一些如下的变种：

编码｜编码字符｜换行的处理｜是否解码非编码字符

第62位｜第63位｜填充｜分隔符｜行字符数｜校验和

RFC 1421：用于隐私增强电邮的Base64（已弃用）｜`+`｜`/`｜强制｜CR+LF｜64，末尾行可少于64｜否｜否

RFC 2045：用于MIME的Base64｜`+`｜`/`｜强制｜CR+LF｜上限 76｜否｜弃用

RFC 2152: 用于UTF-7的Base64｜`+`｜`/`｜否｜否

RFC 3501：用于IMAP协议邮箱命名的Base64｜`+`｜`,`｜否｜否

RFC 4648 §4：标准base64｜`+`｜`/`｜可选｜否

RFC 4648 §5：base64url（URL和文件名安全标准）｜`-`｜`_`｜可选｜否

RFC 4880：用于OpenPGP的Radix-64｜`+`｜`/`｜强制｜CR+LF｜上限 76｜Radix-64编码24位CRC｜否

### MIME

在MIME格式的电子邮件中，Base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时，在传输编码方式中指定Base64。使用的字符包括大小写拉丁字母各26个、数字10个、加号`+`和斜杠`/`，共64个字符，等号`=`用来作为填充用途。

完整的Base64定义可见RFC 1421和RFC 2045。编码后的数据比原始数据略长，为原来的$\frac{4}{3}$。在电子邮件中，根据RFC 822规定，每76个字符，还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。

转换的时候，将3字节的数据，先后放入一个24位元的缓冲区中，先来的字节占高位。数据不足3字节的话，于缓冲区中剩下的位元用0补足。每次取出6位元（因为$2 ^ 6 = 64$），按照其值选择`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`中的字符作为编码后的输出，直到全部输入数据转换完成。

若原数据长度不是3的倍数时且剩下1个输入数据，则在编码结果后加2个`=`；若剩下2个输入数据，则在编码结果后加1个`=`。

### IRCu

在IRCu等软件所使用的P10 IRC服务器间协议中，对客户与服务器的消息类型号（client/server numerics）和二进制IP地址采用了Base64编码。消息类型号的长度固定为3字节，故可直接编码为4个字节而不需要加填充。对IP地址进行编码时，则需要在地址前添加一些0比特，使之可以编码为整数个字节。这里所用的符号集与前述MIME的也有所不同，将`+/`改成了`[]`。

### UTF-7

UTF-7是一个修改版Base64（Modified Base64）。主要是将UTF-16的数据，用Base64的方法编码为可打印的ASCII字符序列。目的是传输Unicode数据。主要的区别在于不用等号`=`补余，因为该字符通常需要大量的转译。

标准可见 RFC 2152，《A Mail-Safe Transformation Format of Unicode》。

### URL

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中用到的`[`和`]`在正则表达式中都可能具有特殊含义。

此外还有一些变种，它们将`+/`改为`_-`或`._`（用作编程语言中的标识符名称）或`.-`（用于XML中的Nmtoken）甚至`_:`（用于XML中的Name）。

### 其他

- 垃圾讯息传播者用Base64来避过反垃圾邮件工具，因为那些工具通常都不会翻译Base64的讯息。
- 在LDIF档案，Base64用作编码字串。

## 相关事件

- 2018年2月电子邮件程序 发现重大漏洞，编号为 CVE-2018-6789 的缓冲区溢位漏洞允许攻击者在服务器上远程执行恶意代码。漏洞位于 base64 解码函数中，影响 Exim v4.90.1 之前的所有版本，多达 40 万服务器受到影响。

## 外部链接

- RFC 1421（Privacy Enhancement for Electronic Internet Mail）
- RFC 2045（MIME）
- RFC 3548（The Base16, Base32, and Base64 Data Encodings）在 RFC 4648 中被替代
- Online Base64 Encoding
- Online Base64 Decoding
- 在线Base64编码
- 在线Base64解码

在线Base64编码