密碼算法詳解——AES



0 AES簡介

  我們知道數據加密標準(Data Encryption Standard: DES)的**長度是56比特,因此算法的理論安全強度是256。但二十世紀中後期正是計算機飛速發展的階段,元器件製造工藝的進步使得計算機的處理能力越來越強,DES將不能提供足夠的安全性。1997年1月2號,美國國家標準技術研究所(National Institute of Standards and Technology: NIST)宣佈希望徵集高級加密標準(Advanced Encryption Standard: AES)[3],用以取代DES。AES得到了全世界很多密碼工作者的響應,先後有很多人提交了自己設計的算法。最終有5個候選算法進入最後一輪:RijndaelSerpentTwofishRC6和MARS,下圖分別爲其中的5位作者。最終經過安全性分析、軟硬件性能評估等嚴格的步驟,Rijndael算法獲勝。

  Rijndael由比利時兩位非常著名的密碼學家Joan DaemenVincent Rijmen設計。Rijndael是一個分組密碼算法族,其分組長度包括128比特、160比特、192比特、224比特、256比特,**長度也包括這五種長度,但是最終AES只選取了分組長度爲128比特,**長度爲128比特、192比特和256比特的三個版本。本文主要結合AES-128進行介紹,AES-196和AES-256的思路基本一樣,只是**擴展算法的過程會稍有不同,加解密的輪數會適當增加,但加解密的操作都是一樣的。另外,本文只對AES算法的各個模塊、基本原理進行介紹,旨在加深對算法流程、密碼算法實現的瞭解。在正式軟件運用中並不推薦自己編寫代碼,很多開源項目如Linux,OPENSSL,SRTP等都有非常高效的實現。由於數學知識的缺陷,本文不介紹算法安全性分析相關的知識,有興趣的讀者可以自行閱讀相關文獻。

  AES是一個分組密碼,屬於對稱密碼範疇,AES算法的模塊在對稱密碼領域特別是分組密碼領域常有使用。

1 算法流程

  AES加密算法涉及4種操作:字節替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和輪**加(AddRoundKey)。下圖給出了AES加解密的流程,從圖中可以看出:1)解密算法的每一步分別對應加密算法的逆操作,2)加解密所有操作的順序正好是相反的。正是由於這幾點(再加上加密算法與解密算法每步的操作互逆)保證了算法的正確性。加解密中每輪的**分別由種子**經過**擴展算法得到。算法中16字節的明文、密文和輪子**都以一個4x4的矩陣表示。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1 字節替代

  字節代替的主要功能是通過S盒完成一個字節到另外一個字節的映射。S盒的詳細構造方法可以參考文獻[4]。這裏直接給出構造好的結果,下圖(a)爲S盒,圖(b)爲S-1(S盒的逆)。S盒用於提供密碼算法的混淆性

  S和S-1分別爲16x16的矩陣,完成一個8比特輸入到8比特輸出的映射,輸入的高4-bit對應的值作爲行標,低4-bit對應的值作爲列標。假設輸入字節的值爲a=a7a6a5a4a3a2a1a0,則輸出值爲S[a7a6a5a4][a3a2a1a0],S-1的變換也同理。

  例如:字節00000000B替換後的值爲(S[0][0]=)63H,再通過S-1即可得到替換前的值,(S-1 [6][3]=)00H。

1.2 行移位

  行移位是一個4x4的矩陣內部字節之間的置換,用於提供算法的擴散性

  1) 正向行移位

  正向行移位用於加密,其原理圖如下。其中:第一行保持不變,第二行循環左移8比特,第三行循環左移16比特,第四行循環左移24比特。

  假設矩陣的名字爲state,用公式表示如下:state’[i][j] = state[i][(j+i)%4];其中i、j屬於[0,3]。

  2) 逆向行移位

  逆向行移位即是相反的操作,即:第一行保持不變,第二行循環右移8比特,第三行循環右移16比特,第四行循環右移24比特。

  用公式表示如下:state’[i][j] = state[i][(4+j-i)%4];其中i、j屬於[0,3]。

1.3 列混淆

  列混淆:利用GF(28)域上算術特性的一個代替,同樣用於提供算法的擴散性

  1) 正向列混淆

  正向列混淆的原理圖如下:

  根據矩陣的乘法可知,在列混淆的過程中,每個字節對應的值只與該列的4個值有關係。此處的乘法和加法都是定義在GF(28)上的,需要注意如下幾點:

    1) 將某個字節所對應的值乘以2,其結果就是將該值的二進制位左移一位,如果原始值的最高位爲1,則還需要將移位後的結果異或00011011;[1]

      英文原文描述如下:In particular, multiplication of a value by x (i.e., by {02}) can be implemented as a 1-bit left shift followed by a conditional bitwise XOR with (0001 1011) if the leftmost bit of the original value (prior to the shift) is 1.

    2) 乘法對加法滿足分配率,例如:07·S0,0=(01⊕02⊕04)·S0,0= S0,0⊕(02·S0,0)(04·S0,0)

    3) 此處的矩陣乘法與一般意義上矩陣的乘法有所不同,各個值在相加時使用的是模28加法(異或運算)。

  下面舉一個例子,假設某一列的值如下圖,運算過程如下:

    

  

  在計算02與C9的乘積時,由於C9對應最左邊的比特爲1,因此需要將C9左移一位後的值與(0001 1011)求異或。同理可以求出另外幾個值。

  2) 逆向列混淆

  逆向列混淆的原理圖如下:

 

  由於:

 

  說明兩個矩陣互逆,經過一次逆向列混淆後即可恢復原文。

1.4 輪**加

  這個操作相對簡單,其依據的原理是「任何數和自身的異或結果爲0」。加密過程中,每輪的輸入與輪子**異或一次;因此,解密時再異或上該輪的輪子**即可恢復。

1.5 **擴展算法

  **擴展的原理圖如下:

 

  **擴展過程說明:

    1)  將種子**按圖(a)的格式排列,其中k0、k1、……、k15依次表示種子**的一個字節;排列後用4個32比特的字表示,分別記爲w[0]、w[1]、w[2]、w[3];

    2)  按照如下方式,依次求解w[j],其中j是整數並且屬於[4,43];

    3)  若j%4=0,則w[j]=w[j-4]⊕g(w[j-1]),否則w[j]=w[j-4]⊕w[j-1];

  函數g的流程說明:

    a)  將w循環左移8比特;

    b)  分別對每個字節做S盒置換;

    c)  與32比特的常量(RC[j/4],0,0,0)進行異或,RC是一個一維數組,其值如下。(RC的值只需要有10個,而此處用了11個,實際上RC[0]在運算中沒有用到,增加RC[0]是爲了便於程序中用數組表示。由於j的最小取值是4,j/4的最小取值則是1,因此不會產生錯誤。)

      RC = {0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36}

1.6 小結

  密碼算法要求是可逆的,這樣解密算法才能正確的恢復明文。拿AES來說,在**固定的情況下,明文和密文在整個輸入空間是一一對應的。因此算法的各個部件也都是可逆的,再將各個部件的操作順序設計成可逆的,密文就能正確的解密了。

2 源碼

  自己寫了一份AES-128的實現代碼,放在Github上;另外一份AES代碼實現了3種**長度的算法,和標準文檔完全保存一致,沒有做任何優化,有興趣可以看看。

  AES中列混淆部分設計有限域乘法操作,在運行中需要消耗較多的時間。現在的計算平臺都擁有豐富的軟件資源(RAM、Flash等),因此AES的軟件實現一般都會採用查表的方式,將字節替代、行移位、列混淆合在一起查表,大概消耗8-10K字節的存儲空間,但效率非常之高。

  在硬件上,爲了減少實現面積,可以通過對解密的操作進行適當調換,這樣解密操作可以複用加密的電路。

3 擴展

SIMD [10]:單指令流多數據流指令,最常用的包括SSE、SSE2、AVX、AVX512 [5] 等,現在很多Intel和AMD的處理器都支持。SIMD操作能夠很大地提高效率,一些項目中都有用到,比如libsodium [6](A modern and easy-to-use crypto library)、FastMemcpy [7] (Speed-up over 50% in average vs traditional memcpy in gcc 4.9 or vc2012 )、hamming_weight [8] (C library to compute the Hamming weight of arrays)等。

AES-NI [9]:AES硬件指令,能夠很快地實現AES加解密,大部分Intel處理器、AMD處理器支持。

4 參考文獻

[1] William Stallings著;王張宜等譯. 密碼編碼學與網絡安全——原理與實踐(第五版)[M]. 北京:電子工業出版社,2012.1.

[2] Daemen J, Rijmen V. AES proposal: Rijndael[J]. 1998.

[3] Advanced Encryption Standard, https://en.wikipedia.org/wiki/Advanced_Encryption_Standard, 2017年3月獲取.

[4] Joan Daemen and Vincent Rijmen, The Design of Rijndael, AES - The Advanced Encryption Standard, Springer-Verlag 2002 (238 pp.)

[5] SSE, SSE2, AVX, AVX512等, https://software.intel.com/sites/landingpage/IntrinsicsGuide/, 2017年6月獲取.

[6] Libsodium, https://github.com/jedisct1/libsodium, 2017年6月獲取.

[7] FastMemcpy, https://github.com/skywind3000/FastMemcpy, 2017年6月獲取.

[8] Hamming_weight, https://github.com/CountOnes/hamming_weight, 2017年6月獲取.

[9] AES-NI, https://en.wikipedia.org/wiki/AES_instruction_set, 2017年6月獲取.

[10] SIMD, https://en.wikipedia.org/wiki/SIMD, 2017年6月獲取.

更新說明

2017.11.19

    a) 完善了評選指標的說明;

2017.06.03

    a) 列混淆中加法是模28,不是模2;

    b) 增加了SIMD和AES-NI的介紹;

2017.03.15

    a) 增加了Rijndael和AES的區別;b) 增加了參考文獻;c) 提到AES查表的實現;d) 循環移位不以字節爲單位,統一改成比特;

    e) 修復了Rijndael算法鏈接的錯誤;f) 更正了錯別字;