天天看點

Base64 原理

Base64

Base64 是什麼?是将位元組流轉換成可列印字元、将可列印字元轉換為位元組流的一種算法。Base64 使用 64 個可列印字元來表示轉換後的資料。

準确的來說,Base64 不算是一種加、解密的算法,它是一種編碼、解碼的算法。這也是為什麼我的用詞是編碼、解碼,而不是加密、解密。

編碼原理

這裡的讨論的前提是使用 UTF-8 編碼

Base64 算法的原理,是将輸入流中的位元組按每 3 個分為一組,然後每次取 6 個比特,将其轉換成表格中對應的資料,一直重複到沒有剩餘的字元為止,轉換表格如下:

Index Character
A 1 B 2 C 3 D
4 E 5 F 6 G 7 H
8 I 9 J 10 K 11 L
12 M 13 N 14 O 15 P
16 Q 17 R 18 S 19 T
20 U 21 V 22 W 23 X
24 Y 25 Z 26 a 27 b
28 c 29 d 30 e 31 f
32 g 33 h 34 i 35 j
36 k 37 l 38 m 39 n
40 o 41 p 42 q 43 r
44 s 45 t 46 u 47 v
48 w 49 x 50 y 51 z
52 53 54 55
56 57 58 59
60 61 62 + 63 /

編碼過程

舉個例子,假設我們要對字元串

S.H

進行編碼:

  1. 将其轉換成十六進制為 53、2e、48
  2. 再将十六進制轉換成二進制,分别為

    01010011

    00101110

    01001000

    。這裡不足 8 個比特的高位補 0 即可。
  3. 将其每6個比特分為一組,分别為

    010100

    110010

    111001

    001000

  4. 将其轉換成十進制得到,20、50、57、8
  5. 再根據表格中的轉換關系轉換可得,U、y、5、I

換句話說,字元串

S.H

通過 Base64 算法編碼之後的結果為

Uy5I

編碼圖解

如果覺得文字較難了解,我把上面的流程用圖的形式畫了出來,可以結合着一起看。
Base64 原理

為什麼要 每三個 分為一組,因為 3

8 = 24,24 = 4

​ 6,這樣子可以剛好可以均分完。

那如果我輸入的位元組不足三個呢?

例如

SH

?按照上述的做法:

首先将其轉換成十六進制

53

48

,再将其轉換成二進制

01010011

01001000

,再按照每 6 個比特分為一組,就會變成

010100

110100

1000

,再轉換成十進制得到 20、52、8,最後得到

U0I

.

然而這個結果是不正确的,随便去找一個工具輸入轉換看看都知道,最終結果為

U0g=

. 這也說明在輸入的字元不足 3 個時,就不是按照之前的方式來處理了。

不足三個位元組如何處理?

假設需要編碼的字元串還是

SH

将其轉換成二進制為,

01010011

01001000

010100

110100

1000

但是可以看到最後一組的比特位不足 6 個,在這種情況下,會進行末尾(低位)補0的操作。補完之後就會變成

010100

110100

100000

。但是你會發現,這裡總共也隻有18個比特,不滿足 3 個位元組一組的原則。在這種情況下,前三組會按照正常的 Base64 進行編碼,而缺失的一組則會使用

=

來進行填充。

這樣一來,就會變成

20

52

32

,再根據表格轉換可得

U0g

,再加上最後填充的

=

,最終結果就是

U0g=

以下是圖解。

Base64 原理
隻有一個位元組如何處理?

那同理,如果隻有一個字元,最後在二進制分組的時候,不足 6 位的低位補 0,分組不滿 4 的,直接以

=

号填充。舉個例子,假設需要編碼的是字元串

S

S

的二進制為

01010011

,按照 6 個比特分為一組,

010100

11

。第二組明顯不滿 6 個比特,進行低位補0操作。

低位補0之後結果變成了

010100

110000

,這裡隻有 2 組,不滿四組,是以這裡需要填充 2 個

=

。将前面的兩組轉換成字元,結果為

Uw

,再結合填充字元,最終的結果為

Uw==

關于編碼,有人可能會說,你這都是英文,英文轉換成十進制再到十六進制很友善,對比 ASCII 碼就行,那要是中文呢?實際上,這個跟采取的編碼類别有關系。對同樣的中文采用不同的編碼,最後得到的結果可能都不同。是以我們這裡隻讨論采用

UTF-8

的場景。

如果是中文,就采用

UTF-8

将中文進行編碼,而如果是英文,其轉換結果和 ASCII 編碼是一樣的。

解碼原理

因為最終的編碼産物中,如果 6 個比特的分組不滿 4 組,會有

=

作為填充物,是以一個 base64 完後的産物總是能夠被 4 整除。

是以,在解密中,我們每次需要處理 4 個字元,将這 4 個字元編碼之後轉換成十進制,再轉換成二進制,不足 6 位的高位補0,然後将 6 個比特一組的二進制數按原順序重新分成每 8 個比特一組,也就是一個位元組一組。然後将其轉換成十六進制,再轉換成對應的字元。

解碼過程

假設我們需要解密的字元為

Uy5I

解密過程就會像:

  1. 按照每次處理4個字元的原理,根據表格将其分别轉換成十進制

    20

    50

    57

    8

  2. 再将其轉換成二進制,不足六位的高位補0,再将其分成每 8 個比特一組
  3. 将分組好的比特轉換成十六進制,得到

    53

    2e

    48

  4. 最後将十六進制轉換成字母得到

    S

    .

    H

    ,也就是

    S.H

解碼圖解

換成圖檔來說就是如下這樣
Base64 原理

這裡我們處理的是一個比較理想的情況,因為所有的比特位剛好被填充完,那如果帶有

=

padding 的 base64 是如何進行解密的呢?

這裡拿

SH

編碼之後的 base64 字元串

U0g=

來做例子
  1. 首先根據表格,将其轉換成十進制

    20

    50

    32

  2. 再将其轉換成二進制,不足 6 個比特的高位補0,

    010100

    110100

    100000

  3. 再将其分成每 8 個比特位一組,

    01010011

    01001000

  4. 然後再轉換成十六進制得

    53

    48

  5. 轉換成字元串可得

    SH

Base64 原理

本篇文章已放到我的 Github github.com/sh-blog 中,歡迎 Star。微信搜尋關注【SH的全棧筆記】,回複【隊列】擷取MQ學習資料,包含基礎概念解析和RocketMQ詳細的源碼解析,持續更新中。

如果你覺得這篇文章對你有幫助,還麻煩點個贊,關個注,分個享,留個言。

繼續閱讀