Base64

**Base64**（基底 64）是一種基於 64 個可列印字元來表示二進位資料的表示方法。由於 $\log _{2}64=6$ ，所以每 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 索引表

## 範例

舉例來說，一段參照自托馬斯・霍布斯《利維坦》的文句：

經過 Base64 編碼之後變成：

編碼「Man」的結果為 `TWFu`，詳細原理如下：

在此例中，Base64 演算法將 3 個位元組編碼為 4 個字元。

如果要編碼的位元組數不能被 3 整除，最後會多出 1 個或 2 個位元組，那麼可以使用下面的方法進行處理：先使用 0 位元組值在末尾補足，使其能夠被 3 整除，然後再進行 Base64 的編碼。在編碼後的 Base64 文字後加上一個或兩個 `=` 號，代表補足的位元組數。也就是說，當最後剩餘兩個八位 (待補足) 位元組（2 個 byte）時，最後一個 6 位的 Base64 位元組塊有四位是 0 值，最後附加上兩個等號；如果最後剩餘一個八位 (待補足) 位元組（1 個 byte）時，最後一個 6 位的 base 位元組塊有兩位是 0 值，最後附加一個等號。
參考下表： 

## 應用

### 變種

base64 編碼對應的 64 個可列印字元在一些特定的程式或協定中可能不適合使用，特別是字元表第 62 位（`+`）、63 位（`/`）和填充字元（`=`），因此存在一些如下的變種：

### MIME

在 MIME 格式的電子郵件中，Base64 可以用來將 binary 的位元組序列資料編碼成 ASCII 字元序列構成的文字。使用時，在傳輸編碼方式中指定 Base64。使用的字元包括大小寫拉丁字母各 26 個、數字 10 個、加號 `+` 和斜槓 `/`，共 64 個字元，等號 `=` 用來作為填充用途。

完整的 Base64 定義可見 RFC 1421 和 RFC 2045。編碼後的資料比原始資料略長，為原來的 ${\frac {4}{3}}$ 。在電子郵件中，根據 RFC 822 規定，每 76 個字元，還需要加上一個 Enter 換行。可以估算編碼後資料長度大約為原長的 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 月電子郵件程式 Exim 發現重大漏洞，編號為 CVE-2018-6789 （頁面存檔備份，存於網際網路檔案館） 的緩衝區溢位漏洞允許攻擊者在伺服器上遠端執行惡意代碼。漏洞位於 base64 解碼函式中，影響 Exim v4.90.1 之前的所有版本，多達 40 萬伺服器受到影響。

## 參見

* Base58
* Radix-64
* Ascii85
* Quoted-printable
* uuencode
* yEnc
* 8BITMIME
* URL

## 參考資料

## 外部連結

* RFC 1421（Privacy Enhancement for Electronic Internet Mail）
* RFC 2045（MIME）
* RFC 3548（The Base16, Base32, and Base64 Data Encodings）在 RFC 4648 中被替代
* Home of the Base64 specification, with an online decoder and C99 implementation（頁面存檔備份，存於網際網路檔案館）