AES 背景
AES 全稱 Advanced Encryption Standard(高級加密標準)。它的出現主要是為了取代 DES 加密算法的,因為 DES 算法的密鑰長度是 56 位,因此算法的理論安全強度是 2^56。但二十世紀中后期正是計算機飛速發展的階段,元器件制造工藝的進步使得計算機的處理能力越來越強,所以還是不能滿足人們對安全性的要求。于是 1997 年 1 月 2 號,美國國家標準技術研究所宣布希望征集高級加密標準,用以取代 DES。AES 也得到了全世界很多密碼工作者的響應,先后有很多人提交了自己設計的算法。最終有5個候選算法進入最后一輪:Rijndael,Serpent,Twofish,RC6 和 MARS。最終經過安全性分析、軟硬件性能評估等嚴格的步驟,Rijndael 算法獲勝。
AES 密碼與分組密碼 Rijndael 基本上完全一致,Rijndael 分組大小和密鑰大小都可以為 128 位、192 位和 256 位。然而 AES 只要求分組大小為 128 位,因此只有分組長度為 128 位的 Rijndael 才稱為 AES 算法。本文只對分組大小 128 位,密鑰長度也為 128 位的 Rijndael 算法進行分析。密鑰長度為 192 位和 256 位的處理方式和 128 位的處理方式類似,只不過密鑰長度每增加 64 位,算法的循環次數就增加 2 輪,128 位循環 10 輪、192 位循環 12 輪、256 位循環 14 輪。
AES 功能
給定一個 128 位的明文和一個 128 位的密鑰,輸出一個 128 位的密文。這個密文可以用相同的密鑰解密。雖然 AES 一次只能加密 16 個字節,但我們只需要把明文劃分成每 16 個字節一組的塊,就可以實現任意長度明文的加密。如果明文長度不是 16 個字節的倍數,則需要填充,目前填充方式主要是 PKCS7 / PKCS5。
AES 加密原理
下來主要分析 16 個字節的加解密過程,下圖是 AES 算法框架。
密鑰生成
密鑰生成流程
- 將初始 128 位密鑰,按每 8 位一個字節組成 16 個字節,得到 k1、k2、……、k16;
- 把 16 個字節按順序從上到下、從左到右進行排列,得到 4 * 4 的矩陣;
- 把矩陣每一列合成一個 32 位的值,得到 w[0]、w[1]、w[2]、w[3];
- 依次求解 w[j], j 屬于 [4, 43] 中的整數,若 j%4=0,則 w[j]=w[j-4] ⊕ g(w[j-1]),否則 w[j]=w[j-4] ⊕ w[j-1];
- 在生成 w 數組中,每 4 個為一個子密鑰一共 11 個,分別是 子密鑰k0、子密鑰k1、…… 、子密鑰k10。
G 函數
- 將 w 循環左移 1 個字節(w 是一個 4 個字節的數組);
- 分別對每個字節做 S 盒置換(字節代換層的 S 盒,下文會介紹);
- 將 w 的第一個字節與輪常量 RC 進行異或運算。
RC = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36}
關于輪常量的生成下文會介紹。
主要作用:一是增加密鑰編排中的非線性;二是消除AES中的對稱性。這兩種屬性都是抵抗某些分組密碼攻擊必要的。
AES 加密流程
- 把 128 位的明文,按照每 8 位一個字節,組成 16 個字節;
- 把 16 個字節按順序從上到下、從左到右進行排列,得到 4 * 4 的明文矩陣;
- 把 4 * 4 的明文矩陣和第一個 4 * 4 的子密鑰矩陣進行異或運算,得到新的矩陣 P(密鑰加法層);
- 對矩陣 P 進行 S 盒置換得到矩陣 P1,具體規則:S 盒是一個 16 * 16 的矩陣,依次遍歷 P 中元素,元素高四位值為行號,低四位值為列號,然后在 S 盒中取出對應的值。(字節代換層);
- 對 4 * 4 的矩陣 P1 進行行位移得到矩陣 P2,具體規則:第一行不變,第二行向左移 1 位,第三行向左移 2 位,第四行向左移 3 位(Shift Rows 層);
- 把矩陣 P2 和一個固定的 4 * 4 的矩陣 GF,進行伽羅瓦域的乘法得到矩陣 P3(Mix Column 層,下文會介紹伽羅瓦域的乘法);
- 把矩陣 P3 和當前輪次的密鑰矩陣進行異或運算得到矩陣 P4(密鑰加法層);
- 重復步驟 4、5、6、7,注意最后一輪不需要 步驟 6 ,最后輸出密鑰。
接下來詳細解釋一下幾個關鍵步驟。
密鑰加法層
明文矩陣和當前回次的子密鑰矩陣進行異或運算。
字節代換層
字節代換層的主要功能是通過 S 盒完成一個字節到另外一個字節的映射。
依次遍歷 4 * 4 的明文矩陣 P 中元素,元素高四位值為行號,低四位值為列號,然后在 S 盒中取出對應的值。
tmp = P[i][j];
P'[i][j] = S[tmp & 0xf0][tmp & 0x0f]
Shift Rows 層(行位移)
行位移操作最為簡單,它是用來將輸入數據作為一個 4 * 4 的字節矩陣進行處理的,然后將這個矩陣的字節進行位置上的置換。ShiftRows 子層屬于 AES 手動的擴散層,目的是將單個位上的變換擴散到影響整個狀態當,從而達到雪崩效應。它之所以稱作行位移,是因為它只在 4 * 4 矩陣的行間進行操作,每行 4 字節的數據。在加密時,保持矩陣的第一行不變,第二行向左移動 1 個字節、第三行向左移動 2 個字節、第四行向左移動 3 個字節。
Mix Column 層(列混淆)
列混淆層是 AES 算法中最為復雜的部分,屬于擴散層,列混淆操作是 AES 算法中主要的擴散元素,它混淆了輸入矩陣的每一列,使輸入的每個字節都會影響到 4 個輸出字節。行位移層和列混淆層的組合使得經過三輪處理以后,矩陣的每個字節都依賴于 16 個明文字節成可能。其實質是在有限域 GF(2^8) 上的多項式乘法運算,也稱伽羅瓦域上的乘法。
伽羅瓦域
伽羅瓦域上的乘法在包括加/解密編碼和存儲編碼中經常使用,AES 算法就使用了伽羅瓦域 GF(2^8) 中的運算。以 2^n 形式的伽羅瓦域來說,加減法都是異或運算,乘法相對較復雜一些,下面介紹 GF(2^n) 上有限域的乘法運算。
本原多項式: 域中不可約多項式,是不能夠進行因子分解的多項式,本原多項式是一種特殊的不可約多項式。當一個域上的本原多項式確定了,這個域上的運算也就確定了,本原多項式一般通過查表可得,同一個域往往有多個本原多項式。通過將域中的元素化為多項式的形式,可以將域上的乘法運算轉化為普通的多項式乘法模以本原多項式的計算。比如 g(x) = x^3+x+1 是 GF(2^3) 上的本原多項式,那么 GF(2^3) 域上的元素 3*7 可以轉化為多項式乘法:
3*7(in GF(2^3)) → (x+1)*(x^2+x+1) mod g(x) = x^3+1 mod x^3+x+1 = x → 3*7 = 2
乘二運算: 無論是普通計算還是伽羅瓦域上運算,乘二計算是一種非常特殊的運算。普通計算在計算機上通過向高位的移位計算即可實現,伽羅瓦域上乘二也不復雜,一次移位和一次異或即可。從多項式的角度來看,伽羅瓦域上乘二對應的是一個多項式乘以 x,如果這個多項式最高指數沒有超過本原多項式最高指數,那么相當于一次普通計算的乘二計算,如果結果最高指數等于本原多項式最高指數,那么需要將除去本原多項式最高項的其他項和結果進行異或。
比如:GF(2^8)(g(x) = x^8 + x^4 + x^3 + x^2 + 1)上 15*15 = 85 計算過程。
15 寫成生成元指數和異或的形式 2^3 + 2^2 + 2^1 + 1,那么:
15*15 = 15*(2^3 + 2^2 + 2^1 + 1) = 2*(2*(2*15 + 15) + 15) + 15 = 85
乘二運算計算過程:
有限域內數 | 操作 | 二進制值 | 十進制值 |
---|---|---|---|
0 | 0 0 0 0 0 0 0 0 | 0 | |
15 | 0 0 0 0 1 1 1 1 | 15 | |
2*15 | 移位 | 0 0 0 1 1 1 1 0 | 30 |
2*15+15 | 異或 | 0 0 0 1 0 0 0 1 | 17 |
2(215+15) | 移位 | 0 0 1 0 0 0 1 0 | 34 |
2(215+15)+15 | 異或 | 0 0 1 0 1 1 0 1 | 45 |
2(2(2*15+15)+15) | 移位 | 0 1 0 1 1 0 1 0 | 90 |
2(2(2*15+15)+15)+15 | 異或 | 0 1 0 1 0 1 0 1 | 85 |
列混淆:就是把兩個矩陣的相乘,里面的運算,加法對應異或運算,乘法對應伽羅瓦域 GF(2^8) 上的乘法(本原多項式為:x^8 + x^4 + x^3 + x^1 + 1)。
unsigned char MixArray[4][4] =
{
0x02, 0x03, 0x01, 0x01,
0x01, 0x02, 0x03, 0x01,
0x01, 0x01, 0x02, 0x03,
0x03, 0x01, 0x01, 0x02
};
unsigned char PlainArray[4][4] =
{
p1, p5, p9, p13,
p2, p6, p10, p14,
p3, p7, p11, p15,
p4, p8, p12, p16
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
result[i][j] =
Galois(MixArray[i][0], PlainArray[0][j]) ^
Galois(MixArray[i][1], PlainArray[1][j]) ^
Galois(MixArray[i][2], PlainArray[2][j]) ^
Galois(MixArray[i][3], PlainArray[3][j]);
}
}
Galois
函數為伽羅瓦域上的乘法。
AES 解碼原理
解碼過程和 DES 解碼類似,也是一個逆過程。基本的數學原理也是:一個數進行兩次異或運算就能恢復,S ^ e ^ e = S。
密鑰加法層
通過異或的特性,再次異或就能恢復原數。
逆Shift Rows層
恢復Shift Rows層的移動。
逆Mix Column層
通過乘上正矩陣的逆矩陣進行矩陣恢復。
一個矩陣先乘上一個正矩陣,然后再乘上他的逆矩陣,相當于沒有操作。
逆字節代換層
通過再次代換恢復字節代換層的代換操作。
比如:0x00 字節的置換過程
- 加密:0x00 通過 S 盒置換得到 0x63;
- 解密:0x63 通過逆 S 盒置換得到 0x00。
關于輪常量 RC 的計算
輪常量生成規則如下:
RC[0] = 1;
RC[i] = 2 * RC[i - 1] //在域 GF(2^8) 上的乘法,本原多項式:x^8 + x^4 + x^3 + x^1 + 1
RC[8] = 2 * RC[7] = 2 * 0x80 = x * x^7 mod x^8 + x^4 + x^3 + x^1 + 1
= x^4 + x^3 + x^1 + 1 = 11011 = 27
= 0x1B
RC[9] = 2 * RC[8] = 2 * 0x1B = x * (x^4 + x^3 + x^1 + 1) mod x^8 + x^4 + x^3 + x^1 + 1
= x^5 + x^4 + x^2 + x = 110110 = 54
= 0x36
關于 AES192 和 AES256
算法原理和 AES128 一樣,只是每次加解密的數據和密鑰大小為 192 位和 256 位。加解密過程幾乎是一樣的,只是循環輪數增加,所以子密鑰個數也要增加,最后輪常量 RC 長度增加。
加密名稱 | 密鑰和分組大小 | 輪次 | 子密鑰個數 |
---|---|---|---|
AES128 | 128位 | 10 | 11 |
AES192 | 192位 | 12 | 13 |
AES256 | 256位 | 14 | 15 |