徹底弄懂Base64的編碼與解碼原理
本文轉(zhuǎn)載自微信公眾號(hào)「大轉(zhuǎn)轉(zhuǎn)FE」,作者大轉(zhuǎn)轉(zhuǎn)FE。轉(zhuǎn)載本文請(qǐng)聯(lián)系大轉(zhuǎn)轉(zhuǎn)FE公眾號(hào)。
背景
base64的編碼原理網(wǎng)上講解較多,但解碼原理講解較少,并且沒(méi)有對(duì)其中的內(nèi)部實(shí)現(xiàn)原理進(jìn)行剖析。想要徹底了解base64的編碼與解碼原理,請(qǐng)耐心看完此文,你一定會(huì)有所收獲。
涉及算法與邏輯運(yùn)算概念
在探究base64編碼原理和解碼原理的過(guò)程中,我們首先需要了解下面會(huì)用到的算法和邏輯運(yùn)算的概念,這樣才能真正的吃透base64的編碼原理和解碼原理,體會(huì)到其中算法的精妙,甚至是在思考的過(guò)程中得到意想不到的收獲。不清楚base64編碼表和ascII編碼表的同學(xué)可直接前往文末查看。
短除法
短除法運(yùn)算方法是先用一個(gè)除數(shù)除以能被它除盡的一個(gè)質(zhì)數(shù),以此類(lèi)推,除到商是質(zhì)數(shù)為止。
通過(guò)短除法,十進(jìn)制數(shù)可以不斷除以2得到多個(gè)余數(shù)。最后,將余數(shù)從下到上進(jìn)行排列組合,得到二進(jìn)制數(shù),我們以字符n對(duì)應(yīng)的ascII編碼110為例。
- 110 / 2 = 55...0
- 55 / 2 = 27...1
- 27 / 2 = 13...1
- 13 / 2 = 6...1
- 6 / 2 = 3...0
- 3 / 2 = 1...1
- 1 / 2 = 0...1
將余數(shù)從下到上進(jìn)行排列組合,得到字符n對(duì)應(yīng)的ascII編碼110轉(zhuǎn)二進(jìn)制為1101110,因?yàn)橐蛔止?jié)對(duì)應(yīng)8位(bit), 所以需要向前補(bǔ)0補(bǔ)足8位,得到01101110。其余字符同理可得。
按權(quán)展開(kāi)求和
按權(quán)展開(kāi)求和, 8位二進(jìn)制數(shù)從右到左,次數(shù)是0到7依次遞增, 基數(shù)*底數(shù)次數(shù),從左到右依次累加,相加結(jié)果為對(duì)應(yīng)十進(jìn)制數(shù)。我們以二進(jìn)制數(shù)01101110轉(zhuǎn)10進(jìn)制為例:
(01101110)2 = 0 * 20 + 1 * 21 + 1 * 22 + 1 * 23 + 0 * 24 + 1 * 25 + 1 * 26 + 0 * 27
位概念
二進(jìn)制數(shù)系統(tǒng)中,每個(gè)0或1就是一個(gè)位(bit,比特),也叫存儲(chǔ)單元,位是數(shù)據(jù)存儲(chǔ)的最小單位。其中8bit就稱(chēng)為一個(gè)字節(jié)(Byte)。
移位運(yùn)算符
移位運(yùn)算符在程序設(shè)計(jì)中,是位操作運(yùn)算符的一種。移位運(yùn)算符可以在二進(jìn)制的基礎(chǔ)上對(duì)數(shù)字進(jìn)行平移。按照平移的方向和填充數(shù)字的規(guī)則分為三種:<<(左移)、>>(帶符號(hào)右移)和>>>(無(wú)符號(hào)右移)。我們?cè)赽ase64的編碼和解碼過(guò)程中操作的又是正數(shù),所以?xún)H使用<<(左移)、>>(帶符號(hào)右移)兩種運(yùn)算符。
- 左移運(yùn)算:是將一個(gè)二進(jìn)制位的操作數(shù)按指定移動(dòng)的位數(shù)向左移動(dòng),移出位被丟棄,右邊移出的空位一律補(bǔ)0。
- 右移運(yùn)算:是將一個(gè)二進(jìn)制位的操作數(shù)按指定移動(dòng)的位數(shù)向右移動(dòng),移出位被丟棄,左邊移出的空位一律補(bǔ)0,或者補(bǔ)符號(hào)位,這由不同的機(jī)器而定。在使用補(bǔ)碼作為機(jī)器數(shù)的機(jī)器中,正數(shù)的符號(hào)位為0,負(fù)數(shù)的符號(hào)位為1。
我們用大白話(huà)來(lái)描述左移位,一共有8個(gè)座位,坐了8個(gè)人,在8個(gè)座位不動(dòng)的情況下,現(xiàn)在我讓這8個(gè)人往左挪2個(gè)座位,于是最左邊的兩個(gè)人站了起來(lái),沒(méi)有座位坐,而最右邊空出來(lái)了兩個(gè)座位。移位操作就相當(dāng)于站起來(lái)的人出局,留出來(lái)的空位補(bǔ)0.
- // 左移
- 01101000 << 2 -> 101000(左側(cè)移出位被丟棄) -> 10100000(右側(cè)空位一律補(bǔ)0)
- // 右移
- 01101000 >> 2 -> 011010(右側(cè)移出位被丟棄) -> 00011010(左側(cè)空位一律補(bǔ)0)
與運(yùn)算、或運(yùn)算
與運(yùn)算、或運(yùn)算都是計(jì)算機(jī)中一種基本的邏輯運(yùn)算方式。
- 與運(yùn)算:符號(hào)表示為&。運(yùn)算規(guī)則:兩位同時(shí)為“1”,結(jié)果才為“1”,否則為0
- 或運(yùn)算:符號(hào)表示為|。運(yùn)算規(guī)則:兩位只要有一位為“1”,結(jié)果就為“1”,否則為0
什么是base64編碼
Base64編碼是將字符串以每3個(gè)8比特(bit)的字節(jié)子序列拆分成4個(gè)6比特(bit)的字節(jié)(6比特有效字節(jié),最左邊兩個(gè)永遠(yuǎn)為0,其實(shí)也是8比特的字節(jié))子序列,再將得到的子序列查找Base64的編碼索引表,得到對(duì)應(yīng)的字符拼接成新的字符串的一種編碼方式。
每3個(gè)8比特(bit)的字節(jié)子序列拆分成4個(gè)6比特(bit)的字節(jié)的拆分過(guò)程如下圖所示:
base64
為什么base64編碼后的大小是原來(lái)的4/3倍
因?yàn)?和8的最大公倍數(shù)是24,所以3個(gè)8比特的字節(jié)剛好可以拆分成4個(gè)6比特的字節(jié),38 = 64。計(jì)算機(jī)中,因?yàn)橐粋€(gè)字節(jié)需要8個(gè)存儲(chǔ)單元存儲(chǔ),所以我們要把6個(gè)比特往前面補(bǔ)兩位0,補(bǔ)足8個(gè)比特。如下圖所示:
很明顯,補(bǔ)足后所需的存儲(chǔ)單元為32個(gè),是原來(lái)所需的24個(gè)的4/3倍。現(xiàn)在大家明白為什么base64編碼后的大小是原來(lái)的4/3倍了吧。
為什么命名為base64呢?
因?yàn)?位(bit)的二進(jìn)制數(shù)有2的6次方個(gè),也就是二進(jìn)制數(shù)(00000000-00111111)之間的代表0-63的64個(gè)二進(jìn)制數(shù)。
不是說(shuō)一個(gè)字節(jié)是用8位二進(jìn)制表示的嗎,為什么不是2的8次方?
因?yàn)槲覀兊玫降?位二進(jìn)制數(shù)的前兩位永遠(yuǎn)是0,真正的有效位只有6位,所以我們所能夠得到的二進(jìn)制數(shù)只有2的6次方個(gè)。
Base64字符是哪64個(gè)?
Base64的編碼索引表,字符選用了"A-Z、a-z、0-9、+、/" 64個(gè)可打印字符來(lái)代表(00000000-00111111)這64個(gè)二進(jìn)制數(shù)。即
let base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
編碼原理
我們不妨自己先思考一下,要把3個(gè)字節(jié)拆分成4個(gè)字節(jié)可以怎么做?你的實(shí)現(xiàn)思路和我的實(shí)現(xiàn)思路有哪個(gè)不同,我們之間又會(huì)碰出怎樣的火花?
流程圖
流程圖
思路
分析映射關(guān)系:abc -> xyzi。我們從高位到低位添加索引來(lái)分析這個(gè)過(guò)程
- x: (前面補(bǔ)兩個(gè)0)a的前六位 => 00a7a6a5a4a3a2
- y: (前面補(bǔ)兩個(gè)0)a的后兩位 + b的前四位 => 00a1a0b7b6b5b4
- z: (前面補(bǔ)兩個(gè)0)b的后四位 + c的前兩位 => 00b3b2b1b0c7c6
- i: (前面補(bǔ)兩個(gè)0)c的后六位 => 00c5c4c3c2c1c0通過(guò)上述的映射關(guān)系,我們很容易得到下面的實(shí)現(xiàn)思路:
1.將字符對(duì)應(yīng)的ascII編碼轉(zhuǎn)為8位二進(jìn)制數(shù)
2.將每三個(gè)8位二進(jìn)制數(shù)進(jìn)行以下操作
- 將第一個(gè)數(shù)右移位2位,得到第一個(gè)6位有效位二進(jìn)制數(shù)
- 將第一個(gè)數(shù) & 0x3之后左移位4位,得到第二個(gè)6位有效位二進(jìn)制數(shù)的第一個(gè)和第二個(gè)有效位,將第二個(gè)數(shù) & 0xf0之后右移位4位,得到第二個(gè)6位有效位二進(jìn)制數(shù)的后四位有效位,兩者取且得到第二個(gè)6位有效位二進(jìn)制
- 將第二個(gè)數(shù) & 0xf之后左移位2位,得到第三個(gè)6位有效位二進(jìn)制數(shù)的前四位有效位,將第三個(gè)數(shù) & 0xC0之后右移位6位,得到第三個(gè)6位有效位二進(jìn)制數(shù)的后兩位有效位,兩者取且得到第三個(gè)6位有效位二進(jìn)制
- 將第三個(gè)數(shù) & 0x3f,得到第四個(gè)6位有效位二進(jìn)制數(shù)
3.將獲得的6位有效位二進(jìn)制數(shù)轉(zhuǎn)十進(jìn)制,查找對(duì)應(yīng)base64字符
我們以hao字符串為例,觀察base64編碼的過(guò)程,我們將上面轉(zhuǎn)換通過(guò)代碼邏輯分析實(shí)現(xiàn)吧。
代碼實(shí)現(xiàn)
- // 輸入字符串
- let str = 'hao'
- // base64字符串
- let base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
- // 定義輸入、輸出字節(jié)的二進(jìn)制數(shù)
- let char1, char2, char3, out1, out2, out3, out4, out
- // 將字符對(duì)應(yīng)的ascII編碼轉(zhuǎn)為8位二進(jìn)制數(shù)
- char1 = str.charCodeAt(0) & 0xff // 104 01101000
- char2 = str.charCodeAt(1) & 0xff // 97 01100001
- char3 = str.charCodeAt(2) & 0xff // 111 01101111
- // 輸出6位有效字節(jié)二進(jìn)制數(shù)
- 6out1 = char1 >> 2 // 26 011010
- out2 = (char1 & 0x3) << 4 | (char2 & 0xf0) >> 4 // 6 000110
- out3 = (char2 & 0xf) << 2 | (char3 & 0xc0) >> 6 // 5 000101
- out4 = char3 & 0x3f // 47 101111
- out = base64EncodeChars[out1] + base64EncodeChars[out2] + base64EncodeChars[out3] + base64EncodeChars[out4] // aGFv
算法剖析
1.out1: char1 >> 2
- 01101000 -> 00011010
2.out2 = (char1 & 0x3) << 4 | (char2 & 0xf0) >> 4
- // 且運(yùn)算
- 01101000 01100001
- 00000011 11110000
- -------- --------
- 00000000 01100000
- // 移位運(yùn)算后得
- 00000000 00000110
- // 或運(yùn)算
- 00000000
- 00000110
- --------
- 00000110
第三個(gè)字符第四個(gè)字符同理
整理上述代碼,擴(kuò)展至多字符字符串
- // 輸入字符串
- let str = 'haohaohao'
- // base64字符串
- let base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
- // 獲取字符串長(zhǎng)度
- let len = str.length
- // 當(dāng)前字符索引
- let index = 0
- // 輸出字符串
- let out = ''
- while(index < len) {
- // 定義輸入、輸出字節(jié)的二進(jìn)制數(shù)
- let char1, char2, char3, out1, out2, out3, out4
- // 將字符對(duì)應(yīng)的ascII編碼轉(zhuǎn)為8位二進(jìn)制數(shù)
- char1 = str.charCodeAt(index++) & 0xff // 104 01101000
- char2 = str.charCodeAt(index++) & 0xff // 97 01100001
- char3 = str.charCodeAt(index++) & 0xff // 111 01101111
- // 輸出6位有效字節(jié)二進(jìn)制數(shù)
- out1 = char1 >> 2 // 26 011010
- out2 = (char1 & 0x3) << 4 | (char2 & 0xf0) >> 4 // 6 000110
- out3 = (char2 & 0xf) << 2 | (char3 & 0xc0) >> 6 // 5 000101
- out4 = char3 & 0x3f // 47 101111
- out = out + base64EncodeChars[out1] + base64EncodeChars[out2] + base64EncodeChars[out3] + base64EncodeChars[out4] // aGFv
- }
原字符串長(zhǎng)度不是3的整倍數(shù)的情況,需要特殊處理
- ...
- char1 = str.charCodeAt(index++) & 0xff // 104 01101000
- if (index == len) {
- out2 = (char1 & 0x3) << 4
- out = out + base64EncodeChars[out1] + base64EncodeChars[out2] + '=='
- return out
- }
- char2 = str.charCodeAt(index++) & 0xff // 97 01100001
- if (index == len) {
- out1 = char1 >> 2 // 26 011010
- out2 = (char1 & 0x3) << 4 | (char2 & 0xf0) >> 4 // 6 000110
- out3 = (char2 & 0xf) << 2
- out = out + base64EncodeChars[out1] + base64EncodeChars[out2] + base64EncodeChars[out3] + '='
- return out
- }
- ...
全部代碼
- function base64Encode(str) {
- // base64字符串
- let base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
- // 獲取字符串長(zhǎng)度
- let len = str.length
- // 當(dāng)前字符索引
- let index = 0
- // 輸出字符串
- let out = ''
- while(index < len) {
- // 定義輸入、輸出字節(jié)的二進(jìn)制數(shù)
- let char1, char2, char3, out1, out2, out3, out4
- // 將字符對(duì)應(yīng)的ascII編碼轉(zhuǎn)為8位二進(jìn)制數(shù)
- char1 = str.charCodeAt(index++) & 0xff
- out1 = char1 >> 2
- if (index == len) {
- out2 = (char1 & 0x3) << 4
- out = out + base64EncodeChars[out1] + base64EncodeChars[out2] + '=='
- return out
- }
- char2 = str.charCodeAt(index++) & 0xff
- out2 = (char1 & 0x3) << 4 | (char2 & 0xf0) >> 4
- if (index == len) {
- out3 = (char2 & 0xf) << 2
- out = out + base64EncodeChars[out1] + base64EncodeChars[out2] + base64EncodeChars[out3] + '='
- return out
- }
- char3 = str.charCodeAt(index++) & 0xff
- // 輸出6位有效字節(jié)二進(jìn)制數(shù)
- out3 = (char2 & 0xf) << 2 | (char3 & 0xc0) >> 6
- out4 = char3 & 0x3f
- out = out + base64EncodeChars[out1] + base64EncodeChars[out2] + base64EncodeChars[out3] + base64EncodeChars[out4]
- }
- return out
- }
- base64Encode('haohao') // aGFvaGFv
- base64Encode('haoha') // aGFvaGE=
- base64Encode('haoh') // aGFvaA==
解碼原理
逆向推導(dǎo),由每4個(gè)6位有效位的二進(jìn)制數(shù)合并成3個(gè)8位二進(jìn)制數(shù),根據(jù)ascII編碼映射到對(duì)應(yīng)字符后拼接字符串
思路
- 分析映射關(guān)系 xyzi -> abc
- a: x后六位 + y第三、四位 => x5x4x3x2x1x0y5y4
- b: y后四位 + z第三、四、五、六位 => y3y2y1y0z5z4z3z2
1.c: z后兩位 + i后六位 => z1z0i5i4i3i2i1i0
2.將字符對(duì)應(yīng)的base64字符集的索引轉(zhuǎn)為6位有效位二進(jìn)制數(shù)
將每四個(gè)6位有效位二進(jìn)制數(shù)進(jìn)行以下操作
第一個(gè)二進(jìn)制數(shù)左移位2位,得到新二進(jìn)制數(shù)的前6位,第二個(gè)二進(jìn)制數(shù) & 0x30之后右移位4位,或運(yùn)算后得到第一個(gè)新二進(jìn)制數(shù)
第二個(gè)二進(jìn)制數(shù) & 0xf之后左移位4位,第三個(gè)二進(jìn)制數(shù) & 0x3c之后右移位2位,或運(yùn)算后得到第二個(gè)新二進(jìn)制數(shù)
第二個(gè)二進(jìn)制數(shù) & 0x3之后左移位6位,與第四個(gè)二進(jìn)制數(shù)或運(yùn)算后得到第二個(gè)新二進(jìn)制數(shù)
3.根據(jù)ascII編碼映射到對(duì)應(yīng)字符后拼接字符串
代碼實(shí)現(xiàn)
- // base64字符串
- let str = 'aGFv'
- // base64字符集
- let base64CharsArr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('')
- // 獲取索引值
- let char1 = base64CharsArr.findIndex(char => char==str[0]) & 0xff // 26 011010
- let char2 = base64CharsArr.findIndex(char => char==str[1]) & 0xff // 6 000110
- let char3 = base64CharsArr.findIndex(char => char==str[2]) & 0xff // 5 000101
- let char4 = base64CharsArr.findIndex(char => char==str[3]) & 0xff // 47 101111
- let out1, out2, out3, out
- // 位運(yùn)算
- out1 = char1 << 2 | (char2 & 0x30) >> 4
- out2 = (char2 & 0xf) << 4 | (char3 & 0x3c) >> 2
- out3 = (char3 & 0x3) << 6 | char4
- console.log(out1, out2, out3)
- out = String.fromCharCode(out1) + String.fromCharCode(out2) + String.fromCharCode(out3)
遇到有用'='補(bǔ)過(guò)位的情況時(shí)
- function base64decode(str) {
- // base64字符集
- let base64CharsArr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('')
- let char1 = base64CharsArr.findIndex(char => char==str[0])
- let char2 = base64CharsArr.findIndex(char => char==str[1])
- let out1, out2, out3, out
- if (char1 == -1 || char2 == -1) return out
- char1 = char1 & 0xff
- char2 = char2 & 0xff
- let char3 = base64CharsArr.findIndex(char => char==str[2])
- // 第三位不在base64對(duì)照表中時(shí),只拼接第一個(gè)字符串
- if (char3 == -1) {
- out1 = char1 << 2 | (char2 & 0x30) >> 4
- out = String.fromCharCode(out1)
- return out
- }
- let char4 = base64CharsArr.findIndex(char => char==str[3])
- // 第三位不在base64對(duì)照表中時(shí),只拼接第一個(gè)和第二個(gè)字符串
- if (char4 == -1) {
- out1 = char1 << 2 | (char2 & 0x30) >> 4
- out2 = (char2 & 0xf) << 4 | (char3 & 0x3c) >> 2
- out = String.fromCharCode(out1) + String.fromCharCode(out2)
- return out
- }
- // 位運(yùn)算
- out1 = char1 << 2 | (char2 & 0x30) >> 4
- out2 = (char2 & 0xf) << 4 | (char3 & 0x3c) >> 2
- out3 = (char3 & 0x3) << 6 | char4
- console.log(out1, out2, out3)
- out = String.fromCharCode(out1) + String.fromCharCode(out2) + String.fromCharCode(out3)
- return out
- }
解碼整個(gè)字符串,整理代碼后
- function base64decode(str) {
- // base64字符集
- let base64CharsArr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('')
- let i = 0
- let len = str.length
- let out = ''
- while(i < len) {
- let char1 = base64CharsArr.findIndex(char => char==str[i])
- i++
- let char2 = base64CharsArr.findIndex(char => char==str[i])
- i++
- let out1, out2, out3
- if (char1 == -1 || char2 == -1) return out
- char1 = char1 & 0xff
- char2 = char2 & 0xff
- let char3 = base64CharsArr.findIndex(char => char==str[i])
- i++
- // 第三位不在base64對(duì)照表中時(shí),只拼接第一個(gè)字符串
- out1 = char1 << 2 | (char2 & 0x30) >> 4
- if (char3 == -1) {
- out = out + String.fromCharCode(out1)
- return out
- }
- let char4 = base64CharsArr.findIndex(char => char==str[i])
- i++
- // 第三位不在base64對(duì)照表中時(shí),只拼接第一個(gè)和第二個(gè)字符串
- out2 = (char2 & 0xf) << 4 | (char3 & 0x3c) >> 2
- if (char4 == -1) {
- out = out + String.fromCharCode(out1) + String.fromCharCode(out2)
- return out
- }
- // 位運(yùn)算
- out3 = (char3 & 0x3) << 6 | char4
- console.log(out1, out2, out3)
- out = out + String.fromCharCode(out1) + String.fromCharCode(out2) + String.fromCharCode(out3)
- }
- return out
- }
- base64decode('aGFvaGFv') // haohao
- base64decode('aGFvaGE=') // haoha
- base64decode('aGFvaA==') // haoh
上述解碼核心是字符與base64字符集索引的映射,網(wǎng)上看到過(guò)使用AccII編碼索引映射base64字符索引的方法
- let base64DecodeChars = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1]
- //
- let char1 = 'hao'.charCodeAt(0) // h -> 104
- base64DecodeChars[char1] // 33 -> base64編碼表中的h
由此可見(jiàn),base64DecodeChars對(duì)照accII編碼表的索引存放的是base64編碼表的對(duì)應(yīng)字符的索引。
總結(jié)
說(shuō)起B(yǎng)ase64編碼可能有些奇怪,因?yàn)榇蠖鄶?shù)的編碼都是由字符轉(zhuǎn)化成二進(jìn)制的過(guò)程,而從二進(jìn)制轉(zhuǎn)成字符的過(guò)程稱(chēng)為解碼。而B(niǎo)ase64的概念就恰好反了,由二進(jìn)制轉(zhuǎn)到字符稱(chēng)為編碼,由字符到二進(jìn)制稱(chēng)為解碼。Base64 是一種數(shù)據(jù)編碼方式,可做簡(jiǎn)單加密使用,我們可以改變base64編碼映射順序來(lái)形成自己獨(dú)特的加密算法進(jìn)行加密解密。
編碼表

































