密碼學(xué) | 廬山真面!你認(rèn)為 Base64 是加密算法嗎?

前言

  • 對網(wǎng)絡(luò)通信有所了解的同學(xué),應(yīng)該都聽過 Base64 編碼。例如,我們一段數(shù)據(jù)通過 MD5 、SHA 等手段加密后,經(jīng)過 Base64 編碼為字符串就可以很方便地在網(wǎng)路上傳輸。那么 Base64 也算是一種加密算法嗎?
  • 在這篇文章里,我將帶你理解 Base64 的基本原理 & 實現(xiàn)。如果能幫上忙,請務(wù)必點贊加關(guān)注,這真的對我非常重要。

系列文章

相關(guān)文章


目錄


1. 基本原理

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

標(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ù)雜,我們用一張示意圖表示為:

Base64編碼 示意圖

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ù)字證書:

查看百度官網(wǎng)的數(shù)字證書
將證書保存到本地
證書以 Base64 編碼格式存儲

需要注意的是,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 CastleApache也提供了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》 —— 維基百科

推薦閱讀

感謝喜歡!你的點贊是對我最大的鼓勵!歡迎關(guān)注彭旭銳的簡書!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容