電腦編碼規則之: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個可列印的字元,如下所示:

ASCII碼 含義 ASCII碼 含義
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的基本含義和轉換規則,其實協議很簡單,將要轉換的數據變成二進位,然後對照轉換表格進行轉換和補全即可。

本文已收錄於 //www.flydean.com/18-base64-encoding/

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!