
前言
- 對網(wǎng)絡(luò)通信有所了解的同學(xué),應(yīng)該都聽過 Base64 編碼。例如,我們一段數(shù)據(jù)通過 MD5 、SHA 等手段加密后,經(jīng)過 Base64 編碼為字符串就可以很方便地在網(wǎng)路上傳輸。那么 Base64 也算是一種加密算法嗎?
- 在這篇文章里,我將帶你理解 Base64 的基本原理 & 實現(xiàn)。如果能幫上忙,請務(wù)必點贊加關(guān)注,這真的對我非常重要。
系列文章
- 《密碼學(xué) | 廬山真面!你認(rèn)為 Base64 是加密算法嗎?》
- 《密碼學(xué) | 蓄勢待發(fā)!說說什么是散列算法?》
- 《密碼學(xué) | 高屋建瓴!摘要、簽名與數(shù)字證書都是什么?》
相關(guān)文章
目錄

1. 基本原理
Base64是一種將二進(jìn)制流表示為 64 個字符的編碼方式。標(biāo)準(zhǔn)的 Base64 使用的索引表為:

舉個例子,字符串"Base64 編碼"經(jīng)過編碼后的結(jié)果為:QmFzZTY0IOe8lueggQ==。當(dāng)然,這里隱含了以UTF-8作為字符編碼的前提,如果使用了其他的字符編碼方式,用Base64編碼后就不是這個結(jié)果了。很多在線編解碼的網(wǎng)站其實也是默認(rèn)使用了UTF-8,但是沒有明確說明。
1.1 標(biāo)準(zhǔn) Base64 編碼步驟
下面解釋一下Base64的編碼步驟:
步驟1:數(shù)據(jù)輸入
在這一步驟,需要將原數(shù)據(jù)(字符串、圖片、音頻等任何數(shù)據(jù))轉(zhuǎn)換為二進(jìn)制流。例如前面舉的字符串的例子,則需要經(jīng)過字符編碼轉(zhuǎn)換為二進(jìn)制流。-
步驟2:分組轉(zhuǎn)換
- 從二進(jìn)制流頭部開始,每 6 位為一組,若不足 6 位,則低位補0
- 每 6 位組成一個新的字節(jié),高位 2 位補 0 ,此時已經(jīng)獲得二進(jìn)制的
Base64編碼
步驟3:轉(zhuǎn)換為字符串
將二進(jìn)制的Base64編碼每個字節(jié)映射為一個字符,例如0000 0000映射為A,0011 1111映射為/,此時已經(jīng)獲得Base64編碼字符串步驟4:末尾補位
標(biāo)準(zhǔn)Base64編碼字符串的長度為 4 的倍數(shù),否則,在末尾補充=。例如前面的QmFzZTY0IOe8lueggQ==長度就是補充了兩個=后,長度為 20。
整個編碼步驟并不復(fù)雜,我們用一張示意圖表示為:

1.2 非標(biāo)準(zhǔn) Base64
Url Base 64
標(biāo)準(zhǔn)Base 64中使用了'/',這在URL和文件系統(tǒng)中存在沖突,因此延伸出 Url Base64 算法,主要就是將'+'和'/'符號替換成了'-'和'_'符號。MIME Base 64
這是一種MIME友好格式,它輸出每行為 76 個字符,每行末需追加回車換行符\r\n,不論每行是否夠 76 個字符,都要添加一個回車換行符
1.3 意義
Base64能夠?qū)⑷魏螖?shù)據(jù)轉(zhuǎn)換為易移植的字符串,避免了傳輸過程中失真問題。最初,Base64是為了解決電子郵件中無法直接使用非ASCII字符的問題。一段數(shù)據(jù)先經(jīng)過Base64編碼為ASCII字符串后,可以在接收端,通過Base64解碼還原為原數(shù)據(jù)后,而無需擔(dān)心傳輸過程中失真。
很多時候,我們都將Base64編碼作為數(shù)據(jù)加密后的傳輸 / 存儲格式。例如,一段明文數(shù)據(jù)通過MD5 、SHA等手段加密后,經(jīng)過Base64編碼為字符串,就可以很方便地進(jìn)行傳輸 & 存儲。再比如,網(wǎng)絡(luò)上的數(shù)字證書其實也是使用Base64編碼的形式傳輸?shù)?,我們可以在瀏覽器上查看百度官網(wǎng)的數(shù)字證書:



需要注意的是,Base64并不是一種加密方式,明文使用Base64編碼后的字符串通過索引表可以直接還原為明文。因此,Base64只能作為一種數(shù)據(jù)的存儲格式。
2. 算法實現(xiàn)
2.1 Java 環(huán)境
在Java 8之前,JDK中并沒有提供Base64的算法實現(xiàn),這其實挺讓人納悶的。雖然源碼中sun.misc.BASE64Encoder,但是它其實并不是公有 API,而是 sun 團(tuán)隊內(nèi)部使用的 API,最好不要在生產(chǎn)中使用。從Java 8,JDK 總算是補充了Base64的實現(xiàn),例如:
import java.util.Base64;
標(biāo)準(zhǔn) Base 64
System.out.println(Base64.getEncoder().encodeToString("".getBytes()));
Url Base 64
System.out.println(Base64.getUrlEncoder().encodeToString("".getBytes()));
MIME Base 64
System.out.println(Base64.getMimeEncoder().encodeToString("".getBytes()));
在Java 8之前,Bouncy Castle和Apache也提供了Base64的算法實現(xiàn)。
2.2 Android環(huán)境
Android SDK提供了Base64的算法實現(xiàn),例如:
import android.util.Base64;
System.out.println(Base64.encodeToString("".getBytes(),Base64.DEFAULT));
相對于Java 8的算法實現(xiàn),Android提供的 API 更為靈活,可以通過flag自定義控制算法的輸出。
3. 總結(jié)
-
Base 64能夠?qū)⑷魏螖?shù)據(jù)轉(zhuǎn)換為易移植的字符串,避免了傳輸過程中失真問題。 - 需要注意的是,
Base 64不是一種加密方式,只是一種編碼方式。很多時候,我們都將Base64編碼作為數(shù)據(jù)加密后的傳輸 / 存儲格式
參考資料
- 《Java加密與解密的藝術(shù)》(第5章) —— 梁棟 著
- 《HTTP權(quán)威指南》 —— [美] David Gourley,Brian Totty等 著
- 《Base64》 —— 維基百科
推薦閱讀
- Java | 帶你理解 ServiceLoader 的原理與設(shè)計思想
- Java | 請概述一下 Class 文件的結(jié)構(gòu)
- Java | 聊一聊編譯過程(編譯前端 & 編譯后端)
- Java | 為什么 Java 實現(xiàn)了平臺無關(guān)性?
- Android | 一個進(jìn)程有多少個 Context 對象(答對的不多)
- Android | 帶你理解 NativeAllocationRegistry 的原理與設(shè)計思想
- Android | 一文帶你全面了解 AspectJ 框架
- 計算機組成原理 | Unicode 和 UTF-8是什么關(guān)系?
- 計算機組成原理 | 為什么浮點數(shù)運算不精確?(阿里筆試)
感謝喜歡!你的點贊是對我最大的鼓勵!歡迎關(guān)注彭旭銳的簡書!
