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編碼