天天看點

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

原文出處:http://blog.csdn.net/qq_28205153/article/details/55798628

AES簡介

進階加密标準(AES,Advanced Encryption Standard)為最常見的對稱加密算法(微信小程式加密傳輸就是用這個加密算法的)。對稱加密算法也就是加密和解密用相同的密鑰,具體的加密流程如下圖: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

下面簡單介紹下各個部分的作用與意義:

  • 明文P
    沒有經過加密的資料。
  • 密鑰K
    用來加密明文的密碼,在對稱加密算法中,加密與解密的密鑰是相同的。密鑰為接收方與發送方協商産生,但不可以直接在網絡上傳輸,否則會導緻密鑰洩漏,通常是通過非對稱加密算法加密密鑰,然後再通過網絡傳輸給對方,或者直接面對面商量密鑰。密鑰是絕對不可以洩漏的,否則會被攻擊者還原密文,竊取機密資料。
  • AES加密函數
    設AES加密函數為E,則 C = E(K, P),其中P為明文,K為密鑰,C為密文。也就是說,把明文P和密鑰K作為加密函數的參數輸入,則加密函數E會輸出密文C。
  • 密文C
    經加密函數處理後的資料
  • AES解密函數
    設AES解密函數為D,則 P = D(K, C),其中C為密文,K為密鑰,P為明文。也就是說,把密文C和密鑰K作為解密函數的參數輸入,則解密函數會輸出明文P。

在這裡簡單介紹下對稱加密算法與非對稱加密算法的差別。

  • 對稱加密算法
    加密和解密用到的密鑰是相同的,這種加密方式加密速度非常快,适合經常發送資料的場合。缺點是密鑰的傳輸比較麻煩。
  • 非對稱加密算法
    加密和解密用的密鑰是不同的,這種加密方式是用數學上的難解問題構造的,通常加密解密的速度比較慢,适合偶爾發送資料的場合。優點是密鑰傳輸友善。常見的非對稱加密算法為RSA、ECC和EIGamal。

實際中,一般是通過RSA加密AES的密鑰,傳輸到接收方,接收方解密得到AES密鑰,然後發送方和接收方用AES密鑰來通信。

本文下面AES原理的介紹參考自《現代密碼學教程》,AES的實作在介紹完原理後開始。

AES的基本結構

AES為分組密碼,分組密碼也就是把明文分成一組一組的,每組長度相等,每次加密一組資料,直到加密完整個明文。在AES标準規範中,分組長度隻能是128位,也就是說,每個分組為16個位元組(每個位元組8位)。密鑰的長度可以使用128位、192位或256位。密鑰的長度不同,推薦加密輪數也不同,如下表所示:

AES 密鑰長度(32位比特字) 分組長度(32位比特字) 加密輪數
AES-128 4 4 10
AES-192 6 4 12
AES-256 8 4 14

輪數在下面介紹,這裡實作的是AES-128,也就是密鑰的長度為128位,加密輪數為10輪。 

上面說到,AES的加密公式為C = E(K,P),在加密函數E中,會執行一個輪函數,并且執行10次這個輪函數,這個輪函數的前9次執行的操作是一樣的,隻有第10次有所不同。也就是說,一個明文分組會被加密10輪。AES的核心就是實作一輪中的所有操作。

AES的處理機關是位元組,128位的輸入明文分組P和輸入密鑰K都被分成16個位元組,分别記為P = P0 P1 … P15 和 K = K0 K1 … K15。如,明文分組為P = abcdefghijklmnop,其中的字元a對應P0,p對應P15。一般地,明文分組用位元組為機關的正方形矩陣描述,稱為狀态矩陣。在算法的每一輪中,狀态矩陣的内容不斷發生變化,最後的結果作為密文輸出。該矩陣中位元組的排列順序為從上到下、從左至右依次排列,如下圖所示: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

現在假設明文分組P為”abcdefghijklmnop”,則對應上面生成的狀态矩陣圖如下: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

上圖中,0x61為字元a的十六進制表示。可以看到,明文經過AES加密後,已經面目全非。

類似地,128位密鑰也是用位元組為機關的矩陣表示,矩陣的每一列被稱為1個32位比特字。通過密鑰編排函數該密鑰矩陣被擴充成一個44個字組成的序列W[0],W[1], … ,W[43],該序列的前4個元素W[0],W[1],W[2],W[3]是原始密鑰,用于加密運算中的初始密鑰加(下面介紹);後面40個字分為10組,每組4個字(128比特)分别用于10輪加密運算中的輪密鑰加,如下圖所示: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

上圖中,設K = “abcdefghijklmnop”,則K0 = a, K15 = p, W[0] = K0 K1 K2 K3 = “abcd”。

AES的整體結構如下圖所示,其中的W[0,3]是指W[0]、W[1]、W[2]和W[3]串聯組成的128位密鑰。加密的第1輪到第9輪的輪函數一樣,包括4個操作:位元組代換、行位移、列混合和輪密鑰加。最後一輪疊代不執行列混合。另外,在第一輪疊代之前,先将明文和原始密鑰進行一次異或加密操作。 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

上圖也展示了AES解密過程,解密過程仍為10輪,每一輪的操作是加密操作的逆操作。由于AES的4個輪操作都是可逆的,是以,解密操作的一輪就是順序執行逆行移位、逆位元組代換、輪密鑰加和逆列混合。同加密操作類似,最後一輪不執行逆列混合,在第1輪解密之前,要執行1次密鑰加操作。

下面分别介紹AES中一輪的4個操作階段,這4分操作階段使輸入位得到充分的混淆。

一、位元組代換

1.位元組代換操作

AES的位元組代換其實就是一個簡單的查表操作。AES定義了一個S盒和一個逆S盒。 

AES的S盒:

行/列 1 2 3 4 5 6 7 8 9 A B C D E F
0x63 0x7c 0x77 0x7b 0xf2 0x6b 0x6f 0xc5 0x30 0x01 0x67 0x2b 0xfe 0xd7 0xab 0x76
1 0xca 0x82 0xc9 0x7d 0xfa 0x59 0x47 0xf0 0xad 0xd4 0xa2 0xaf 0x9c 0xa4 0x72 0xc0
2 0xb7 0xfd 0x93 0x26 0x36 0x3f 0xf7 0xcc 0x34 0xa5 0xe5 0xf1 0x71 0xd8 0x31 0x15
3 0x04 0xc7 0x23 0xc3 0x18 0x96 0x05 0x9a 0x07 0x12 0x80 0xe2 0xeb 0x27 0xb2 0x75
4 0x09 0x83 0x2c 0x1a 0x1b 0x6e 0x5a 0xa0 0x52 0x3b 0xd6 0xb3 0x29 0xe3 0x2f 0x84
5 0x53 0xd1 0x00 0xed 0x20 0xfc 0xb1 0x5b 0x6a 0xcb 0xbe 0x39 0x4a 0x4c 0x58 0xcf
6 0xd0 0xef 0xaa 0xfb 0x43 0x4d 0x33 0x85 0x45 0xf9 0x02 0x7f 0x50 0x3c 0x9f 0xa8
7 0x51 0xa3 0x40 0x8f 0x92 0x9d 0x38 0xf5 0xbc 0xb6 0xda 0x21 0x10 0xff 0xf3 0xd2
8 0xcd 0x0c 0x13 0xec 0x5f 0x97 0x44 0x17 0xc4 0xa7 0x7e 0x3d 0x64 0x5d 0x19 0x73
9 0x60 0x81 0x4f 0xdc 0x22 0x2a 0x90 0x88 0x46 0xee 0xb8 0x14 0xde 0x5e 0x0b 0xdb
A 0xe0 0x32 0x3a 0x0a 0x49 0x06 0x24 0x5c 0xc2 0xd3 0xac 0x62 0x91 0x95 0xe4 0x79
B 0xe7 0xc8 0x37 0x6d 0x8d 0xd5 0x4e 0xa9 0x6c 0x56 0xf4 0xea 0x65 0x7a 0xae 0x08
C 0xba 0x78 0x25 0x2e 0x1c 0xa6 0xb4 0xc6 0xe8 0xdd 0x74 0x1f 0x4b 0xbd 0x8b 0x8a
D 0x70 0x3e 0xb5 0x66 0x48 0x03 0xf6 0x0e 0x61 0x35 0x57 0xb9 0x86 0xc1 0x1d 0x9e
E 0xe1 0xf8 0x98 0x11 0x69 0xd9 0x8e 0x94 0x9b 0x1e 0x87 0xe9 0xce 0x55 0x28 0xdf
F 0x8c 0xa1 0x89 0x0d 0xbf 0xe6 0x42 0x68 0x41 0x99 0x2d 0x0f 0xb0 0x54 0xbb 0x16

狀态矩陣中的元素按照下面的方式映射為一個新的位元組:把該位元組的高4位作為行值,低4位作為列值,取出S盒或者逆S盒中對應的行的元素作為輸出。例如,加密時,輸出的位元組S1為0x12,則查S盒的第0x01行和0x02列,得到值0xc9,然後替換S1原有的0x12為0xc9。狀态矩陣經位元組代換後的圖如下: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

2.位元組代換逆操作

逆位元組代換也就是查逆S盒來變換,逆S盒如下:

行/列 1 2 3 4 5 6 7 8 9 A B C D E F
0x52 0x09 0x6a 0xd5 0x30 0x36 0xa5 0x38 0xbf 0x40 0xa3 0x9e 0x81 0xf3 0xd7 0xfb
1 0x7c 0xe3 0x39 0x82 0x9b 0x2f 0xff 0x87 0x34 0x8e 0x43 0x44 0xc4 0xde 0xe9 0xcb
2 0x54 0x7b 0x94 0x32 0xa6 0xc2 0x23 0x3d 0xee 0x4c 0x95 0x0b 0x42 0xfa 0xc3 0x4e
3 0x08 0x2e 0xa1 0x66 0x28 0xd9 0x24 0xb2 0x76 0x5b 0xa2 0x49 0x6d 0x8b 0xd1 0x25
4 0x72 0xf8 0xf6 0x64 0x86 0x68 0x98 0x16 0xd4 0xa4 0x5c 0xcc 0x5d 0x65 0xb6 0x92
5 0x6c 0x70 0x48 0x50 0xfd 0xed 0xb9 0xda 0x5e 0x15 0x46 0x57 0xa7 0x8d 0x9d 0x84
6 0x90 0xd8 0xab 0x00 0x8c 0xbc 0xd3 0x0a 0xf7 0xe4 0x58 0x05 0xb8 0xb3 0x45 0x06
7 0xd0 0x2c 0x1e 0x8f 0xca 0x3f 0x0f 0x02 0xc1 0xaf 0xbd 0x03 0x01 0x13 0x8a 0x6b
8 0x3a 0x91 0x11 0x41 0x4f 0x67 0xdc 0xea 0x97 0xf2 0xcf 0xce 0xf0 0xb4 0xe6 0x73
9 0x96 0xac 0x74 0x22 0xe7 0xad 0x35 0x85 0xe2 0xf9 0x37 0xe8 0x1c 0x75 0xdf 0x6e
A 0x47 0xf1 0x1a 0x71 0x1d 0x29 0xc5 0x89 0x6f 0xb7 0x62 0x0e 0xaa 0x18 0xbe 0x1b
B 0xfc 0x56 0x3e 0x4b 0xc6 0xd2 0x79 0x20 0x9a 0xdb 0xc0 0xfe 0x78 0xcd 0x5a 0xf4
C 0x1f 0xdd 0xa8 0x33 0x88 0x07 0xc7 0x31 0xb1 0x12 0x10 0x59 0x27 0x80 0xec 0x5f
D 0x60 0x51 0x7f 0xa9 0x19 0xb5 0x4a 0x0d 0x2d 0xe5 0x7a 0x9f 0x93 0xc9 0x9c 0xef
E 0xa0 0xe0 0x3b 0x4d 0xae 0x2a 0xf5 0xb0 0xc8 0xeb 0xbb 0x3c 0x83 0x53 0x99 0x61
F 0x17 0x2b 0x04 0x7e 0xba 0x77 0xd6 0x26 0xe1 0x69 0x14 0x63 0x55 0x21 0x0c 0x7d

二、行移位

1.行移位操作

行移位是一個簡單的左循環移位操作。當密鑰長度為128比特時,狀态矩陣的第0行左移0位元組,第1行左移1位元組,第2行左移2位元組,第3行左移3位元組,如下圖所示: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

2.行移位的逆變換

行移位的逆變換是将狀态矩陣中的每一行執行相反的移位操作,例如AES-128中,狀态矩陣的第0行右移0位元組,第1行右移1位元組,第2行右移2位元組,第3行右移3位元組。

三、列混合

1.列混合操作

列混合變換是通過矩陣相乘來實作的,經行移位後的狀态矩陣與固定的矩陣相乘,得到混淆後的狀态矩陣,如下圖的公式所示: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

狀态矩陣中的第j列(0 ≤j≤3)的列混合可以表示為下圖所示: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

其中,矩陣元素的乘法和加法都是定義在基于GF(2^8)上的二進制運算,并不是通常意義上的乘法和加法。這裡涉及到一些資訊安全上的數學知識,不過不懂這些知識也行。其實這種二進制運算的加法等價于兩個位元組的異或,乘法則複雜一點。對于一個8位的二進制數來說,使用域上的乘法乘以(00000010)等價于左移1位(低位補0)後,再根據情況同(00011011)進行異或運算,設S1 = (a7 a6 a5 a4 a3 a2 a1 a0),剛0x02 * S1如下圖所示: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

也就是說,如果a7為1,則進行異或運算,否則不進行。 

類似地,乘以(00000100)可以拆分成兩次乘以(00000010)的運算: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

乘以(0000 0011)可以拆分成先分别乘以(0000 0001)和(0000 0010),再将兩個乘積異或: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

是以,我們隻需要實作乘以2的函數,其他數值的乘法都可以通過組合來實作。 

下面舉個具體的例子,輸入的狀态矩陣如下:

C9 E5 FD 2B
7A F2 78 6E
63 9C 26 67
B0 A7 82 E5

下面,進行列混合運算: 

以第一列的運算為例: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

其它列的計算就不列舉了,列混合後生成的新狀态矩陣如下:

D4 E7 CD 66
28 02 E5 BB
BE C6 D6 BF
22 0F DF A5

2.列混合逆運算

逆向列混合變換可由下圖的矩陣乘法定義: 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

可以驗證,逆變換矩陣同正變換矩陣的乘積恰好為機關矩陣。

四、輪密鑰加

輪密鑰加是将128位輪密鑰Ki同狀态矩陣中的資料進行逐位異或操作,如下圖所示。其中,密鑰Ki中每個字W[4i],W[4i+1],W[4i+2],W[4i+3]為32位比特字,包含4個位元組,他們的生成算法下面在下面介紹。輪密鑰加過程可以看成是字逐位異或的結果,也可以看成位元組級别或者位級别的操作。也就是說,可以看成S0 S1 S2 S3 組成的32位字與W[4i]的異或運算。 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

輪密鑰加的逆運算同正向的輪密鑰加運算完全一緻,這是因為異或的逆操作是其自身。輪密鑰加非常簡單,但卻能夠影響S數組中的每一位。

密鑰擴充

AES首先将初始密鑰輸入到一個4*4的狀态矩陣中,如下圖所示。 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

這個4*4矩陣的每一列的4個位元組組成一個字,矩陣4列的4個字依次命名為W[0]、W[1]、W[2]和W[3],它們構成一個以字為機關的數組W。例如,設密鑰K為”abcdefghijklmnop”,則K0 = ‘a’,K1 = ‘b’, K2 = ‘c’,K3 = ‘d’,W[0] = “abcd”。 

接着,對W數組擴充40個新列,構成總共44列的擴充密鑰數組。新列以如下的遞歸方式産生: 

1.如果i不是4的倍數,那麼第i列由如下等式确定: 

W[i]=W[i-4]⨁W[i-1] 

2.如果i是4的倍數,那麼第i列由如下等式确定: 

W[i]=W[i-4]⨁T(W[i-1]) 

其中,T是一個有點複雜的函數。 

函數T由3部分組成:字循環、位元組代換和輪常量異或,這3部分的作用分别如下。 

a.字循環:将1個字中的4個位元組循環左移1個位元組。即将輸入字[b0, b1, b2, b3]變換成[b1,b2,b3,b0]。 

b.位元組代換:對字循環的結果使用S盒進行位元組代換。 

c.輪常量異或:将前兩步的結果同輪常量Rcon[j]進行異或,其中j表示輪數。 

輪常量Rcon[j]是一個字,其值見下表。

j 1 2 3 4 5
Rcon[j] 01 00 00 00 02 00 00 00 04 00 00 00 08 00 00 00 10 00 00 00
j 6 7 8 9 10
Rcon[j] 20 00 00 00 40 00 00 00 80 00 00 00 1B 00 00 00 36 00 00 00

下面舉個例子: 

設初始的128位密鑰為: 

3C A1 0B 21 57 F0 19 16 90 2E 13 80 AC C1 07 BD 

那麼4個初始值為: 

W[0] = 3C A1 0B 21 

W[1] = 57 F0 19 16 

W[2] = 90 2E 13 80 

W[3] = AC C1 07 BD 

下面求擴充的第1輪的子密鑰(W[4],W[5],W[6],W[7])。 

由于4是4的倍數,是以: 

W[4] = W[0] ⨁ T(W[3]) 

T(W[3])的計算步驟如下: 

1. 循環地将W[3]的元素移位:AC C1 07 BD變成C1 07 BD AC; 

2. 将 C1 07 BD AC 作為S盒的輸入,輸出為78 C5 7A 91; 

3. 将78 C5 7A 91與第一輪輪常量Rcon[1]進行異或運算,将得到79 C5 7A 91,是以,T(W[3])=79 C5 7A 91,故 

W[4] = 3C A1 0B 21 ⨁ 79 C5 7A 91 = 45 64 71 B0 

其餘的3個子密鑰段的計算如下: 

W[5] = W[1] ⨁ W[4] = 57 F0 19 16 ⨁ 45 64 71 B0 = 12 94 68 A6 

W[6] = W[2] ⨁ W[5] =90 2E 13 80 ⨁ 12 94 68 A6 = 82 BA 7B 26 

W[7] = W[3] ⨁ W[6] = AC C1 07 BD ⨁ 82 BA 7B 26 = 2E 7B 7C 9B 

是以,第一輪的密鑰為 45 64 71 B0 12 94 68 A6 82 BA 7B 26 2E 7B 7C 9B。

AES解密

在文章開始的圖中,有AES解密的流程圖,可以對應那個流程圖來進行解密。下面介紹的是另一種等價的解密模式,流程圖如下圖所示。這種等價的解密模式使得解密過程各個變換的使用順序同加密過程的順序一緻,隻是用逆變換取代原來的變換。 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

AES原理到這裡就結束了,下面主要為AES的實作,對以上原理中的每一個小節進行實作講解,講解的時候會插入一些關鍵代碼,完整的代碼參見文章最後。文章最後提供兩個完整的程式,一個能在Linux下面編譯運作,一個能在VC6.0下面編譯通過。

AES算法實作

AES加密函數預覽

aes加密函數中,首先進行密鑰擴充,然後把128位長度的字元串讀進一個4*4的整數數組中,這個數組就是狀态矩陣。例如,pArray[0][0] = S0,pArray[1][0] = S1, pArray[0][1] = S4。這個讀取過程是通過 convertToIntArray()函數來實作的。每個輪操作的函數都對pArray進行修改,也就是對狀态矩陣進行混淆。在執行完10輪加密後,會把pArray轉換回字元串,再存入明文p的字元數組中,是以,在加密完後,明文p的字元串中的字元就是加密後的字元了。這個轉換過程是通過convertArrayToStr()函數來實作的。

/**
 * 參數 p: 明文的字元串數組。
 * 參數 plen: 明文的長度。
 * 參數 key: 密鑰的字元串數組。
 */
void aes(char *p, int plen, char *key){

    int keylen = strlen(key);
    if(plen ==  || plen %  != ) {
        printf("明文字元長度必須為16的倍數!\n");
        exit();
    }

    if(!checkKeyLen(keylen)) {
        printf("密鑰字元長度錯誤!長度必須為16、24和32。目前長度為%d\n",keylen);
        exit();
    }

    extendKey(key);//擴充密鑰
    int pArray[][];

    for(int k = ; k < plen; k += ) {
        convertToIntArray(p + k, pArray);

        addRoundKey(pArray, );//一開始的輪密鑰加

        for(int i = ; i < ; i++){//前9輪

            subBytes(pArray);//位元組代換

            shiftRows(pArray);//行移位

            mixColumns(pArray);//列混合

            addRoundKey(pArray, i);

        }

        //第10輪
        subBytes(pArray);//位元組代換

        shiftRows(pArray);//行移位

        addRoundKey(pArray, );

        convertArrayToStr(pArray, p + k);
    }
}
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

1.密鑰擴充的實作

在開始加密前,必須先獲得第一輪加密用到的密鑰,故先實作密鑰擴充 

下面是密鑰擴充函數的實作,這個函數傳入密鑰key的字元串表示,然後從字元串中讀取W[0]到W[3],函數getWordFromStr()用于實作此功能。讀取後,就開始擴充密鑰,當i是4的倍數的時候,就會調用T()函數來進行擴充,因為T函數的行為與加密的輪數有關,故要把加密的輪數 j 作為參數傳進去。

//密鑰對應的擴充數組
static int w[];

/**
 * 擴充密鑰,結果是把w[44]中的每個元素初始化
 */
static void extendKey(char *key) {
    for(int i = ; i < ; i++)
        w[i] = getWordFromStr(key + i * ); 

    for(int i = , j = ; i < ; i++) {
        if( i %  == ) {
            w[i] = w[i - ] ^ T(w[i - ], j); 
            j++;//下一輪
        }else {
            w[i] = w[i - ] ^ w[i - ]; 
        }
    }   

}
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

下面是T()函數的代碼實作,T()函數中接收兩個參數,參數num為上面傳進的W[i - 1],round為加密的輪數。首先用一個numArray儲存從32位的W[i-1]中取得4個位元組。如果W[i-1]為0x12ABCDEF,那麼numArray[0] = 0x12,numArray[1] = 0xAB。函數splitIntToArray()用于從32位整數中讀取這四個位元組,之是以這樣做是因為整數數組比較容易操作。然後調用leftLoop4int()函數把numArray數組中的4個元素循環左移1位。然後執行位元組代換,通過getNumFromSBox()函數來擷取S盒中相應的值來替換numArray中的值。接着通過mergeArrayToInt()函數把位元組代換後的numArray合并回32位的整數,在進行輪常量異或後傳回。

/**
 * 常量輪值表
 */
static const int Rcon[] = { , ,
    , ,
    , ,
    , ,
    ,  };
/**
 * 密鑰擴充中的T函數
 */
static int T(int num, int round) {
    int numArray[];
    splitIntToArray(num, numArray);
    leftLoop4int(numArray, );//字循環

    //位元組代換
    for(int i = ; i < ; i++)
        numArray[i] = getNumFromSBox(numArray[i]);

    int result = mergeArrayToInt(numArray);
    return result ^ Rcon[round];
}
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

2. 位元組代換的實作

位元組代換的代碼很簡單,就是把狀态矩陣中的每個元素傳進getNumFromSBox()函數中,然後取得前面8位中的高4位作為行值,低4位作為列值,然後傳回S[row][col],這裡的S是儲存S盒的數組。

/**
 * 根據索引,從S盒中獲得元素
 */
static int getNumFromSBox(int index) {
    int row = getLeft4Bit(index);
    int col = getRight4Bit(index);
    return S[row][col];
}

/**
 * 位元組代換
 */
static void subBytes(int array[][]){
    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            array[i][j] = getNumFromSBox(array[i][j]);
}
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3.行移位的實作

行移位的時候,首先把狀态矩陣中第2,3,4行複制出來,然後對它們行進左移相應的位數,然後再複制回去狀态矩陣array中。

/**
 * 将數組中的元素循環左移step位
 */
static void leftLoop4int(int array[], int step) {
    int temp[];
    for(int i = ; i < ; i++)
        temp[i] = array[i];

    int index = step %  ==  ?  : step % ;
    for(int i = ; i < ; i++){
        array[i] = temp[index];
        index++;
        index = index % ;
    }
}

/**
 * 行移位
 */
static void shiftRows(int array[][]) {
    int rowTwo[], rowThree[], rowFour[];
    //複制狀态矩陣的第2,3,4行
    for(int i = ; i < ; i++) {
        rowTwo[i] = array[][i];
        rowThree[i] = array[][i];
        rowFour[i] = array[][i];
    }
    //循環左移相應的位數
    leftLoop4int(rowTwo, );
    leftLoop4int(rowThree, );
    leftLoop4int(rowFour, );

    //把左移後的行複制回狀态矩陣中
    for(int i = ; i < ; i++) {
        array[][i] = rowTwo[i];
        array[][i] = rowThree[i];
        array[][i] = rowFour[i];
    }
}
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

4.列混合的實作

列混合函數中,先把狀态矩陣初始狀态複制一份到tempArray中,然後把tempArray與colM矩陣相乘,colM為存放要乘的常數矩陣的數組。其中的GFMul()函數定義了矩陣相乘時的乘法,加法則直接通過異或來實作。GFMul()通過調用乘以各個數對應的函數來實作乘法。例如,S1 * 2 剛通過調用GFMul2(S1)來實作。S1 * 3 剛通過GFMul3(S1)來實作。在這裡,主要實作GFMul2()函數就行了,其它的都可以通過GFMul2()的組合來實作。舉個例子吧,為計算下面這條等式,需要像下面這樣調用函數 

AES加密對稱算法 AES簡介 AES的基本結構 一、位元組代換 二、行移位 三、列混合 四、輪密鑰加 密鑰擴充 AES解密 AES算法實作 完整的程式代碼

s = GFMul3(0xC9) ^ 0x7A ^ 0x63 ^ GFMul2(0xB0)

/**
 * 列混合要用到的矩陣
 */
static const int colM[][] = { , , , ,
    , , , ,
    , , , ,
    , , ,  };

static int GFMul2(int s) {
    int result = s << ;
    int a7 = result & ;

    if(a7 != ) {
        result = result & ;
        result = result ^ ;
    }

    return result;
}

static int GFMul3(int s) {
    return GFMul2(s) ^ s;
}

/**
 * GF上的二進制運算
 */
static int GFMul(int n, int s) {
    int result;

    if(n == )
        result = s;
    else if(n == )
        result = GFMul2(s);
    else if(n == )
        result = GFMul3(s);
    else if(n == )
        result = GFMul9(s);
    else if(n == )//11
        result = GFMul11(s);
    else if(n == )//13
        result = GFMul13(s);
    else if(n == )//14
        result = GFMul14(s);

    return result;
}

/**
 * 列混合
 */
static void mixColumns(int array[][]) {

    int tempArray[][];

    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            tempArray[i][j] = array[i][j];

    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++){
            array[i][j] = GFMul(colM[i][],tempArray[][j]) ^ GFMul(colM[i][],tempArray[][j])
                ^ GFMul(colM[i][],tempArray[][j]) ^ GFMul(colM[i][], tempArray[][j]);
        }
}
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

5.輪密鑰加的實作

輪密鑰加的實作很簡單,就是根據傳入的輪數來把狀态矩陣與相應的W[i]異或。

/**
 * 輪密鑰加
 */
static void addRoundKey(int array[][], int round) {
    int warray[];
    for(int i = ; i < ; i++) {

        splitIntToArray(w[ round *  + i], warray);

        for(int j = ; j < ; j++) {
            array[j][i] = array[j][i] ^ warray[j];
        }
    }
}

           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

AES解密函數

AES的解密函數和加密函數有點不同,可以參考上面的等價解密流程圖來了解,解密函數中調用的是各輪操作的逆函數。逆函數在這裡就不詳細講解了,可以參考最後的完整代碼。

/**
 * 參數 c: 密文的字元串數組。
 * 參數 clen: 密文的長度。
 * 參數 key: 密鑰的字元串數組。
 */
void deAes(char *c, int clen, char *key) {

    int keylen = strlen(key);
    if(clen ==  || clen %  != ) {
        printf("密文字元長度必須為16的倍數!現在的長度為%d\n",clen);
        exit();
    }

    if(!checkKeyLen(keylen)) {
        printf("密鑰字元長度錯誤!長度必須為16、24和32。目前長度為%d\n",keylen);
        exit();
    }

    extendKey(key);//擴充密鑰
    int cArray[][];
    for(int k = ; k < clen; k += ) {
        convertToIntArray(c + k, cArray);


        addRoundKey(cArray, );

        int wArray[][];
        for(int i = ; i >= ; i--) {
            deSubBytes(cArray);

            deShiftRows(cArray);

            deMixColumns(cArray);
            getArrayFrom4W(i, wArray);
            deMixColumns(wArray);

            addRoundTowArray(cArray, wArray);
        }

        deSubBytes(cArray);

        deShiftRows(cArray);

        addRoundKey(cArray, );

        convertArrayToStr(cArray, c + k);

    }
}
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

完整的程式代碼

Linux版本

aes.h

#ifndef AES_H
#define AES_H

/**
 * 參數 p: 明文的字元串數組。
 * 參數 plen: 明文的長度,長度必須為16的倍數。
 * 參數 key: 密鑰的字元串數組。
 */
void aes(char *p, int plen, char *key);

/**
 * 參數 c: 密文的字元串數組。
 * 參數 clen: 密文的長度,長度必須為16的倍數。
 * 參數 key: 密鑰的字元串數組。
 */
void deAes(char *c, int clen, char *key);

#endif
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

aes.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aes.h"

/**
 * S盒
 */
static const int S[][] = { , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , ,  };

/**
 * 逆S盒
 */
static const int S2[][] = { , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , ,  };

/**
 * 擷取整形資料的低8位的左4個位
 */
static int getLeft4Bit(int num) {
    int left = num & ;
    return left >> ;
}

/**
 * 擷取整形資料的低8位的右4個位
 */
static int getRight4Bit(int num) {
    return num & ;
}
/**
 * 根據索引,從S盒中獲得元素
 */
static int getNumFromSBox(int index) {
    int row = getLeft4Bit(index);
    int col = getRight4Bit(index);
    return S[row][col];
}

/**
 * 把一個字元轉變成整型
 */
static int getIntFromChar(char c) {
    int result = (int) c;
    return result & ;
}

/**
 * 把16個字元轉變成4X4的數組,
 * 該矩陣中位元組的排列順序為從上到下,
 * 從左到右依次排列。
 */
static void convertToIntArray(char *str, int pa[][]) {
    int k = ;
    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++) {
            pa[j][i] = getIntFromChar(str[k]);
            k++;
        }
}

/**
 * 列印4X4的數組
 */
static void printArray(int a[][]) {
    for(int i = ; i < ; i++){
        for(int j = ; j < ; j++)
            printf("a[%d][%d] = 0x%x ", i, j, a[i][j]);
        printf("\n");
    }
    printf("\n");
}

/**
 * 列印字元串的ASSCI,
 * 以十六進制顯示。
 */
static void printASSCI(char *str, int len) {
    for(int i = ; i < len; i++)
        printf("0x%x ", getIntFromChar(str[i]));
    printf("\n");
}

/**
 * 把連續的4個字元合并成一個4位元組的整型
 */
static int getWordFromStr(char *str) {
    int one = getIntFromChar(str[]);
    one = one << ;
    int two = getIntFromChar(str[]);
    two = two << ;
    int three = getIntFromChar(str[]);
    three = three << ;
    int four = getIntFromChar(str[]);
    return one | two | three | four;
}

/**
 * 把一個4位元組的數的第一、二、三、四個位元組取出,
 * 入進一個4個元素的整型數組裡面。
 */
static void splitIntToArray(int num, int array[]) {
    int one = num >> ;
    array[] = one & ;
    int two = num >> ;
    array[] = two & ;
    int three = num >> ;
    array[] = three & ;
    array[] = num & ;
}

/**
 * 将數組中的元素循環左移step位
 */
static void leftLoop4int(int array[], int step) {
    int temp[];
    for(int i = ; i < ; i++)
        temp[i] = array[i];

    int index = step %  ==  ?  : step % ;
    for(int i = ; i < ; i++){
        array[i] = temp[index];
        index++;
        index = index % ;
    }
}

/**
 * 把數組中的第一、二、三和四元素分别作為
 * 4位元組整型的第一、二、三和四位元組,合并成一個4位元組整型
 */
static int mergeArrayToInt(int array[]) {
    int one = array[] << ;
    int two = array[] << ;
    int three = array[] << ;
    int four = array[];
    return one | two | three | four;
}

/**
 * 常量輪值表
 */
static const int Rcon[] = { , ,
    , ,
    , ,
    , ,
    ,  };
/**
 * 密鑰擴充中的T函數
 */
static int T(int num, int round) {
    int numArray[];
    splitIntToArray(num, numArray);
    leftLoop4int(numArray, );//字循環

    //位元組代換
    for(int i = ; i < ; i++)
        numArray[i] = getNumFromSBox(numArray[i]);

    int result = mergeArrayToInt(numArray);
    return result ^ Rcon[round];
}

//密鑰對應的擴充數組
static int w[];

/**
 * 擴充密鑰,結果是把w[44]中的每個元素初始化
 */
static void extendKey(char *key) {
    for(int i = ; i < ; i++)
        w[i] = getWordFromStr(key + i * );

    for(int i = , j = ; i < ; i++) {
        if( i %  == ) {
            w[i] = w[i - ] ^ T(w[i - ], j);
            j++;//下一輪
        }else {
            w[i] = w[i - ] ^ w[i - ];
        }
    }

}

/**
 * 輪密鑰加
 */
static void addRoundKey(int array[][], int round) {
    int warray[];
    for(int i = ; i < ; i++) {

        splitIntToArray(w[ round *  + i], warray);

        for(int j = ; j < ; j++) {
            array[j][i] = array[j][i] ^ warray[j];
        }
    }
}

/**
 * 位元組代換
 */
static void subBytes(int array[][]){
    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            array[i][j] = getNumFromSBox(array[i][j]);
}

/**
 * 行移位
 */
static void shiftRows(int array[][]) {
    int rowTwo[], rowThree[], rowFour[];
    //複制狀态矩陣的第2,3,4行
    for(int i = ; i < ; i++) {
        rowTwo[i] = array[][i];
        rowThree[i] = array[][i];
        rowFour[i] = array[][i];
    }
    //循環左移相應的位數
    leftLoop4int(rowTwo, );
    leftLoop4int(rowThree, );
    leftLoop4int(rowFour, );

    //把左移後的行複制回狀态矩陣中
    for(int i = ; i < ; i++) {
        array[][i] = rowTwo[i];
        array[][i] = rowThree[i];
        array[][i] = rowFour[i];
    }
}

/**
 * 列混合要用到的矩陣
 */
static const int colM[][] = { , , , ,
    , , , ,
    , , , ,
    , , ,  };

static int GFMul2(int s) {
    int result = s << ;
    int a7 = result & ;

    if(a7 != ) {
        result = result & ;
        result = result ^ ;
    }

    return result;
}

static int GFMul3(int s) {
    return GFMul2(s) ^ s;
}

static int GFMul4(int s) {
    return GFMul2(GFMul2(s));
}

static int GFMul8(int s) {
    return GFMul2(GFMul4(s));
}

static int GFMul9(int s) {
    return GFMul8(s) ^ s;
}

static int GFMul11(int s) {
    return GFMul9(s) ^ GFMul2(s);
}

static int GFMul12(int s) {
    return GFMul8(s) ^ GFMul4(s);
}

static int GFMul13(int s) {
    return GFMul12(s) ^ s;
}

static int GFMul14(int s) {
    return GFMul12(s) ^ GFMul2(s);
}

/**
 * GF上的二進制運算
 */
static int GFMul(int n, int s) {
    int result;

    if(n == )
        result = s;
    else if(n == )
        result = GFMul2(s);
    else if(n == )
        result = GFMul3(s);
    else if(n == )
        result = GFMul9(s);
    else if(n == )//11
        result = GFMul11(s);
    else if(n == )//13
        result = GFMul13(s);
    else if(n == )//14
        result = GFMul14(s);

    return result;
}
/**
 * 列混合
 */
static void mixColumns(int array[][]) {

    int tempArray[][];

    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            tempArray[i][j] = array[i][j];

    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++){
            array[i][j] = GFMul(colM[i][],tempArray[][j]) ^ GFMul(colM[i][],tempArray[][j]) 
                ^ GFMul(colM[i][],tempArray[][j]) ^ GFMul(colM[i][], tempArray[][j]);
        }
}
/**
 * 把4X4數組轉回字元串
 */
static void convertArrayToStr(int array[][], char *str) {
    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            *str++ = (char)array[j][i]; 
}
/**
 * 檢查密鑰長度
 */
static int checkKeyLen(int len) {
    if(len == )
        return ;
    else
        return ;
}

/**
 * 參數 p: 明文的字元串數組。
 * 參數 plen: 明文的長度。
 * 參數 key: 密鑰的字元串數組。
 */
void aes(char *p, int plen, char *key){

    int keylen = strlen(key);
    if(plen ==  || plen %  != ) {
        printf("明文字元長度必須為16的倍數!\n");
        exit();
    }

    if(!checkKeyLen(keylen)) {
        printf("密鑰字元長度錯誤!長度必須為16、24和32。目前長度為%d\n",keylen);
        exit();
    }

    extendKey(key);//擴充密鑰
    int pArray[][];

    for(int k = ; k < plen; k += ) { 
        convertToIntArray(p + k, pArray);

        addRoundKey(pArray, );//一開始的輪密鑰加

        for(int i = ; i < ; i++){//前9輪

            subBytes(pArray);//位元組代換

            shiftRows(pArray);//行移位

            mixColumns(pArray);//列混合

            addRoundKey(pArray, i);

        }

        //第10輪
        subBytes(pArray);//位元組代換

        shiftRows(pArray);//行移位

        addRoundKey(pArray, );

        convertArrayToStr(pArray, p + k);
    }
}
/**
 * 根據索引從逆S盒中擷取值
 */
static int getNumFromS1Box(int index) {
    int row = getLeft4Bit(index);
    int col = getRight4Bit(index);
    return S2[row][col];
}
/**
 * 逆位元組變換
 */
static void deSubBytes(int array[][]) {
    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            array[i][j] = getNumFromS1Box(array[i][j]);
}
/**
 * 把4個元素的數組循環右移step位
 */
static void rightLoop4int(int array[], int step) {
    int temp[];
    for(int i = ; i < ; i++)
        temp[i] = array[i];

    int index = step %  ==  ?  : step % ;
    index =  - index;
    for(int i = ; i >= ; i--) {
        array[i] = temp[index];
        index--;
        index = index == - ?  : index;
    }
}

/**
 * 逆行移位
 */
static void deShiftRows(int array[][]) {
    int rowTwo[], rowThree[], rowFour[];
    for(int i = ; i < ; i++) {
        rowTwo[i] = array[][i];
        rowThree[i] = array[][i];
        rowFour[i] = array[][i];
    }

    rightLoop4int(rowTwo, );
    rightLoop4int(rowThree, );
    rightLoop4int(rowFour, );

    for(int i = ; i < ; i++) {
        array[][i] = rowTwo[i];
        array[][i] = rowThree[i];
        array[][i] = rowFour[i];
    }
}
/**
 * 逆列混合用到的矩陣
 */
static const int deColM[][] = { , , , ,
    , , , ,
    , , , ,
    , , ,  };

/**
 * 逆列混合
 */
static void deMixColumns(int array[][]) {
    int tempArray[][];

    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            tempArray[i][j] = array[i][j];

    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++){
            array[i][j] = GFMul(deColM[i][],tempArray[][j]) ^ GFMul(deColM[i][],tempArray[][j]) 
                ^ GFMul(deColM[i][],tempArray[][j]) ^ GFMul(deColM[i][], tempArray[][j]);
        }
}
/**
 * 把兩個4X4數組進行異或
 */
static void addRoundTowArray(int aArray[][],int bArray[][]) {
    for(int i = ; i < ; i++)
        for(int j = ; j < ; j++)
            aArray[i][j] = aArray[i][j] ^ bArray[i][j];
}
/**
 * 從4個32位的密鑰字中獲得4X4數組,
 * 用于進行逆列混合
 */
static void getArrayFrom4W(int i, int array[][]) {
    int index = i * ;
    int colOne[], colTwo[], colThree[], colFour[];
    splitIntToArray(w[index], colOne);
    splitIntToArray(w[index + ], colTwo);
    splitIntToArray(w[index + ], colThree);
    splitIntToArray(w[index + ], colFour);

    for(int i = ; i < ; i++) {
        array[i][] = colOne[i];
        array[i][] = colTwo[i];
        array[i][] = colThree[i];
        array[i][] = colFour[i];
    }

}

/**
 * 參數 c: 密文的字元串數組。
 * 參數 clen: 密文的長度。
 * 參數 key: 密鑰的字元串數組。
 */
void deAes(char *c, int clen, char *key) {

    int keylen = strlen(key);
    if(clen ==  || clen %  != ) {
        printf("密文字元長度必須為16的倍數!現在的長度為%d\n",clen);
        exit();
    }

    if(!checkKeyLen(keylen)) {
        printf("密鑰字元長度錯誤!長度必須為16、24和32。目前長度為%d\n",keylen);
        exit();
    }

    extendKey(key);//擴充密鑰
    int cArray[][];
    for(int k = ; k < clen; k += ) {
        convertToIntArray(c + k, cArray);


        addRoundKey(cArray, );

        int wArray[][];
        for(int i = ; i >= ; i--) {
            deSubBytes(cArray);

            deShiftRows(cArray);

            deMixColumns(cArray);
            getArrayFrom4W(i, wArray);
            deMixColumns(wArray);

            addRoundTowArray(cArray, wArray);
        }

        deSubBytes(cArray);

        deShiftRows(cArray);

        addRoundKey(cArray, );

        convertArrayToStr(cArray, c + k);

    }
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575

main.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include "aes.h"

#define MAXLEN 1024

void getString(char *str, int len){

    int slen = read(, str, len);
    for(int i = ; i < slen; i++,str++){
        if(*str == '\n'){
            *str = '\0';
            break;
        }
    }
}

void printASCCI(char *str, int len) {
    int c;
    for(int i = ; i < len; i++) {
        c = (int)*str++;
        c = c & ;
        printf("0x%x ", c);
    }
    printf("\n");
}

/**
 * 從标準輸入中讀取使用者輸入的字元串
 */
void readPlainText(char *str, int *len) {
    int plen;
    while() {
        getString(str, MAXLEN);
        plen = strlen(str);
        if(plen !=  && plen %  == ) {
            printf("你輸入的明文為:%s\n", str);
            break;
        }else{
            printf("明文字元長度必須為16的倍數,現在的長度為%d\n", plen);
        }
    }
    *len = plen;
}
/**
 * 把字元串寫進檔案
 */
void writeStrToFile(char *str, int len, char *fileName) {
    FILE *fp;
    fp = fopen(fileName, "wb");
    for(int i = ; i < len; i++)
        putc(str[i], fp);
    fclose(fp);
}


void aesStrToFile(char *key) {

    char p[MAXLEN];
    int plen;
    printf("請輸入你的明文,明文字元長度必須為16的倍數\n");
    readPlainText(p,&plen);
    printf("進行AES加密..................\n");

    aes(p, plen, key);//AES加密

    printf("加密完後的明文的ASCCI為:\n");
    printASCCI(p, plen);
    char fileName[];
    printf("請輸入你想要寫進的檔案名,比如'test.txt':\n");
    if(scanf("%s", fileName) == ) {    
        writeStrToFile(p, plen, fileName);
        printf("已經将密文寫進%s中了,可以在運作該程式的目前目錄中找到它。\n", fileName);
    }
}
/**
 * 從檔案中讀取字元串
 */
int readStrFromFile(char *fileName, char *str) {
    FILE *fp = fopen(fileName, "rb");
    if(fp == NULL) {
        printf("打開檔案出錯,請确認檔案存在目前目錄下!\n");
        exit();
    }

    int i;
    for(i = ; i < MAXLEN && (str[i] = getc(fp)) != EOF; i++);

    if(i >= MAXLEN) {
        printf("解密檔案過大!\n");
        exit();
    }

    str[i] = '\0';
    fclose(fp);
    return i;
}


void deAesFile(char *key) {
    char fileName[];
    char c[MAXLEN];//密文字元串
    printf("請輸入要解密的檔案名,該檔案必須和本程式在同一個目錄\n");
    if(scanf("%s", fileName) == ) {
        int clen = readStrFromFile(fileName, c);
        printf("開始解密.........\n");
        deAes(c, clen, key);
        printf("解密後的明文ASCII為:\n");
        printASCCI(c, clen);
        printf("明文為:%s\n", c);
        writeStrToFile(c,clen,fileName);
        printf("現在可以打開%s來檢視解密後的密文了!\n",fileName);
    }
}

void aesFile(char *key) {
    char fileName[];
    char fileP[MAXLEN];

    printf("請輸入要加密的檔案名,該檔案必須和本程式在同一個目錄\n");
    if(scanf("%s", fileName) == ) {
        readStrFromFile(fileName, fileP);
        int plen = strlen(fileP);
        printf("開始加密.........\n");
        printf("加密前檔案中字元的ASCII為:\n");
        printASCCI(fileP, plen);

        aes(fileP, plen, key);//開始加密

        printf("加密後的密文ASCII為:\n");
        printASCCI(fileP, plen);
        writeStrToFile(fileP,plen,fileName);
        printf("已經将加密後的密文寫進%s中了\n",fileName);
    }
}

int main(int argc, char const *argv[]) {

    char key[];
    printf("請輸入16個字元的密鑰:\n");
    int klen;
    while(){
        getString(key,);
        klen = strlen(key);
        if(klen != ){
            printf("請輸入16個字元的密鑰,目前密鑰的長度為%d\n",klen);
        }else{
            printf("你輸入的密鑰為:%s\n",key);
            break;
        }
    }

    printf("輸入's'表示要加密輸入的字元串,并将加密後的内容寫入到檔案\n");
    printf("請輸入要功能選項并按回車,輸入'f'表示要加密檔案\n");
    printf("輸入'p'表示要解密檔案\n");
    char c;
    if(scanf("%s",&c) == ) {
        if(c == 's')
            aesStrToFile(key);//用AES加密字元串,并将字元串寫進檔案中
        else if(c == 'p')
            deAesFile(key);//把檔案中的密文解密,并寫回檔案中
        else if(c == 'f')//用AES加密檔案
            aesFile(key);
    }
    return ;
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169

通過下面的gcc指令來編譯運作:

gcc -o aes aes.c main.c           
  • 1
  • 1

VC6.0版本

由于VC6.0的編譯器比較坑,要先聲明,後使用變量,故要對代碼進行相應的修改。

aes.h

#ifndef MY_AES_H
#define MY_AES_H

/**
 * 參數 p: 明文的字元串數組。
 * 參數 plen: 明文的長度,長度必須為16的倍數。
 * 參數 key: 密鑰的字元串數組。
 */
void aes(char *p, int plen, char *key);

/**
 * 參數 c: 密文的字元串數組。
 * 參數 clen: 密文的長度,長度必須為16的倍數。
 * 參數 key: 密鑰的字元串數組。
 */
void deAes(char *c, int clen, char *key);

#endif           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

aes.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "aes.h"

/**
 * S盒
 */
static const int S[][] = { , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , ,  };

/**
 * 逆S盒
 */
static const int S2[][] = { , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , , ,
    , , , , , , , , , , , , , , ,  };

/**
 * 擷取整形資料的低8位的左4個位
 */
static int getLeft4Bit(int num) {
    int left = num & ;
    return left >> ;
}

/**
 * 擷取整形資料的低8位的右4個位
 */
static int getRight4Bit(int num) {
    return num & ;
}
/**
 * 根據索引,從S盒中獲得元素
 */
static int getNumFromSBox(int index) {
    int row = getLeft4Bit(index);
    int col = getRight4Bit(index);
    return S[row][col];
}

/**
 * 把一個字元轉變成整型
 */
static int getIntFromChar(char c) {
    int result = (int) c;
    return result & ;
}

/**
 * 把16個字元轉變成4X4的數組,
 * 該矩陣中位元組的排列順序為從上到下,
 * 從左到右依次排列。
 */
static void convertToIntArray(char *str, int pa[][]) {
    int k = ;
    int i,j;
    for(i = ; i < ; i++)
        for(j = ; j < ; j++) {
            pa[j][i] = getIntFromChar(str[k]);
            k++;
        }
}

/**
 * 列印4X4的數組
 */
static void printArray(int a[][]) {
    int i,j;
    for(i = ; i < ; i++){
        for(j = ; j < ; j++)
            printf("a[%d][%d] = 0x%x ", i, j, a[i][j]);
        printf("\n");
    }
    printf("\n");
}

/**
 * 列印字元串的ASSCI,
 * 以十六進制顯示。
 */
static void printASSCI(char *str, int len) {
    int i;
    for(i = ; i < len; i++)
        printf("0x%x ", getIntFromChar(str[i]));
    printf("\n");
}

/**
 * 把連續的4個字元合并成一個4位元組的整型
 */
static int getWordFromStr(char *str) {
    int one, two, three, four;
    one = getIntFromChar(str[]);
    one = one << ;
    two = getIntFromChar(str[]);
    two = two << ;
    three = getIntFromChar(str[]);
    three = three << ;
    four = getIntFromChar(str[]);
    return one | two | three | four;
}

/**
 * 把一個4位元組的數的第一、二、三、四個位元組取出,
 * 入進一個4個元素的整型數組裡面。
 */
static void splitIntToArray(int num, int array[]) {
    int one, two, three;
    one = num >> ;
    array[] = one & ;
    two = num >> ;
    array[] = two & ;
    three = num >> ;
    array[] = three & ;
    array[] = num & ;
}

/**
 * 将數組中的元素循環左移step位
 */
static void leftLoop4int(int array[], int step) {
    int temp[];
    int i;
    int index;
    for(i = ; i < ; i++)
        temp[i] = array[i];

    index = step %  ==  ?  : step % ;
    for(i = ; i < ; i++){
        array[i] = temp[index];
        index++;
        index = index % ;
    }
}

/**
 * 把數組中的第一、二、三和四元素分别作為
 * 4位元組整型的第一、二、三和四位元組,合并成一個4位元組整型
 */
static int mergeArrayToInt(int array[]) {
    int one = array[] << ;
    int two = array[] << ;
    int three = array[] << ;
    int four = array[];
    return one | two | three | four;
}

/**
 * 常量輪值表
 */
static const int Rcon[] = { , ,
    , ,
    , ,
    , ,
    ,  };
/**
 * 密鑰擴充中的T函數
 */
static int T(int num, int round) {
    int numArray[];
    int i;
    int result;
    splitIntToArray(num, numArray);
    leftLoop4int(numArray, );//字循環

    //位元組代換
    for(i = ; i < ; i++)
        numArray[i] = getNumFromSBox(numArray[i]);

    result = mergeArrayToInt(numArray);
    return result ^ Rcon[round];
}

//密鑰對應的擴充數組
static int w[];
/**
 * 列印W數組
 */
static void printW() {
    int i, j;
    for(i = , j = ; i < ; i++,j++){
        printf("w[%d] = 0x%x ", i, w[i]);
        if(j %  == )
            printf("\n");
    }
    printf("\n");
}


/**
 * 擴充密鑰,結果是把w[44]中的每個元素初始化
 */
static void extendKey(char *key) {
    int i,j;
    for(i = ; i < ; i++)
        w[i] = getWordFromStr(key + i * );

    for(i = , j = ; i < ; i++) {
        if( i %  == ) {
            w[i] = w[i - ] ^ T(w[i - ], j);
            j++;//下一輪
        }else {
            w[i] = w[i - ] ^ w[i - ];
        }
    }

}

/**
 * 輪密鑰加
 */
static void addRoundKey(int array[][], int round) {
    int warray[];
    int i,j;
    for(i = ; i < ; i++) {

        splitIntToArray(w[ round *  + i], warray);

        for(j = ; j < ; j++) {
            array[j][i] = array[j][i] ^ warray[j];
        }
    }
}

/**
 * 位元組代換
 */
static void subBytes(int array[][]){
    int i,j;
    for(i = ; i < ; i++)
        for(j = ; j < ; j++)
            array[i][j] = getNumFromSBox(array[i][j]);
}

/**
 * 行移位
 */
static void shiftRows(int array[][]) {
    int rowTwo[], rowThree[], rowFour[];
    int i;
    for(i = ; i < ; i++) {
        rowTwo[i] = array[][i];
        rowThree[i] = array[][i];
        rowFour[i] = array[][i];
    }

    leftLoop4int(rowTwo, );
    leftLoop4int(rowThree, );
    leftLoop4int(rowFour, );

    for(i = ; i < ; i++) {
        array[][i] = rowTwo[i];
        array[][i] = rowThree[i];
        array[][i] = rowFour[i];
    }
}

/**
 * 列混合要用到的矩陣
 */
static const int colM[][] = { , , , ,
    , , , ,
    , , , ,
    , , ,  };

static int GFMul2(int s) {
    int result = s << ;
    int a7 = result & ;

    if(a7 != ) {
        result = result & ;
        result = result ^ ;
    }

    return result;
}

static int GFMul3(int s) {
    return GFMul2(s) ^ s;
}

static int GFMul4(int s) {
    return GFMul2(GFMul2(s));
}

static int GFMul8(int s) {
    return GFMul2(GFMul4(s));
}

static int GFMul9(int s) {
    return GFMul8(s) ^ s;
}

static int GFMul11(int s) {
    return GFMul9(s) ^ GFMul2(s);
}

static int GFMul12(int s) {
    return GFMul8(s) ^ GFMul4(s);
}

static int GFMul13(int s) {
    return GFMul12(s) ^ s;
}

static int GFMul14(int s) {
    return GFMul12(s) ^ GFMul2(s);
}

/**
 * GF上的二進制運算
 */
static int GFMul(int n, int s) {
    int result;

    if(n == )
        result = s;
    else if(n == )
        result = GFMul2(s);
    else if(n == )
        result = GFMul3(s);
    else if(n == )
        result = GFMul9(s);
    else if(n == )//11
        result = GFMul11(s);
    else if(n == )//13
        result = GFMul13(s);
    else if(n == )//14
        result = GFMul14(s);

    return result;
}
/**
 * 列混合
 */
static void mixColumns(int array[][]) {

    int tempArray[][];
    int i,j;
    for(i = ; i < ; i++)
        for(j = ; j < ; j++)
            tempArray[i][j] = array[i][j];

    for(i = ; i < ; i++)
        for(j = ; j < ; j++){
            array[i][j] = GFMul(colM[i][],tempArray[][j]) ^ GFMul(colM[i][],tempArray[][j])
                ^ GFMul(colM[i][],tempArray[][j]) ^ GFMul(colM[i][], tempArray[][j]);
        }
}
/**
 * 把4X4數組轉回字元串
 */
static void convertArrayToStr(int array[][], char *str) {
    int i,j;
    for(i = ; i < ; i++)
        for(j = ; j < ; j++)
            *str++ = (char)array[j][i];
}
/**
 * 檢查密鑰長度
 */
static int checkKeyLen(int len) {
    if(len == )
        return ;
    else
        return ;
}


/**
 * 參數 p: 明文的字元串數組。
 * 參數 plen: 明文的長度。
 * 參數 key: 密鑰的字元串數組。
 */
void aes(char *p, int plen, char *key){

    int keylen = strlen(key);
    int pArray[][];
    int k,i;

    if(plen ==  || plen %  != ) {
        printf("明文字元長度必須為16的倍數!\n");
        exit();
    }

    if(!checkKeyLen(keylen)) {
        printf("密鑰字元長度錯誤!長度必須為16。目前長度為%d\n",keylen);
        exit();
    }

    extendKey(key);//擴充密鑰

    for(k = ; k < plen; k += ) {
        convertToIntArray(p + k, pArray);

        addRoundKey(pArray, );//一開始的輪密鑰加

        for(i = ; i < ; i++){

            subBytes(pArray);//位元組代換

            shiftRows(pArray);//行移位

            mixColumns(pArray);//列混合

            addRoundKey(pArray, i);

        }

        subBytes(pArray);//位元組代換

        shiftRows(pArray);//行移位

        addRoundKey(pArray, );

        convertArrayToStr(pArray, p + k);
    }
}
/**
 * 根據索引從逆S盒中擷取值
 */
static int getNumFromS1Box(int index) {
    int row = getLeft4Bit(index);
    int col = getRight4Bit(index);
    return S2[row][col];
}
/**
 * 逆位元組變換
 */
static void deSubBytes(int array[][]) {
    int i,j;
    for(i = ; i < ; i++)
        for(j = ; j < ; j++)
            array[i][j] = getNumFromS1Box(array[i][j]);
}
/**
 * 把4個元素的數組循環右移step位
 */
static void rightLoop4int(int array[], int step) {
    int temp[];
    int i;
    int index;
    for(i = ; i < ; i++)
        temp[i] = array[i];

    index = step %  ==  ?  : step % ;
    index =  - index;
    for(i = ; i >= ; i--) {
        array[i] = temp[index];
        index--;
        index = index == - ?  : index;
    }
}

/**
 * 逆行移位
 */
static void deShiftRows(int array[][]) {
    int rowTwo[], rowThree[], rowFour[];
    int i;
    for(i = ; i < ; i++) {
        rowTwo[i] = array[][i];
        rowThree[i] = array[][i];
        rowFour[i] = array[][i];
    }

    rightLoop4int(rowTwo, );
    rightLoop4int(rowThree, );
    rightLoop4int(rowFour, );

    for(i = ; i < ; i++) {
        array[][i] = rowTwo[i];
        array[][i] = rowThree[i];
        array[][i] = rowFour[i];
    }
}
/**
 * 逆列混合用到的矩陣
 */
static const int deColM[][] = { , , , ,
    , , , ,
    , , , ,
    , , ,  };

/**
 * 逆列混合
 */
static void deMixColumns(int array[][]) {
    int tempArray[][];
    int i,j;
    for(i = ; i < ; i++)
        for(j = ; j < ; j++)
            tempArray[i][j] = array[i][j];

    for(i = ; i < ; i++)
        for(j = ; j < ; j++){
            array[i][j] = GFMul(deColM[i][],tempArray[][j]) ^ GFMul(deColM[i][],tempArray[][j])
                ^ GFMul(deColM[i][],tempArray[][j]) ^ GFMul(deColM[i][], tempArray[][j]);
        }
}
/**
 * 把兩個4X4數組進行異或
 */
static void addRoundTowArray(int aArray[][],int bArray[][]) {
    int i,j;
    for(i = ; i < ; i++)
        for(j = ; j < ; j++)
            aArray[i][j] = aArray[i][j] ^ bArray[i][j];
}
/**
 * 從4個32位的密鑰字中獲得4X4數組,
 * 用于進行逆列混合
 */
static void getArrayFrom4W(int i, int array[][]) {
    int index,j;
    int colOne[], colTwo[], colThree[], colFour[];
    index = i * ;
    splitIntToArray(w[index], colOne);
    splitIntToArray(w[index + ], colTwo);
    splitIntToArray(w[index + ], colThree);
    splitIntToArray(w[index + ], colFour);

    for(j = ; j < ; j++) {
        array[j][] = colOne[j];
        array[j][] = colTwo[j];
        array[j][] = colThree[j];
        array[j][] = colFour[j];
    }

}

/**
 * 參數 c: 密文的字元串數組。
 * 參數 clen: 密文的長度。
 * 參數 key: 密鑰的字元串數組。
 */
void deAes(char *c, int clen, char *key) {

    int cArray[][];
    int keylen,k;
    keylen = strlen(key);
    if(clen ==  || clen %  != ) {
        printf("密文字元長度必須為16的倍數!現在的長度為%d\n",clen);
        exit();
    }

    if(!checkKeyLen(keylen)) {
        printf("密鑰字元長度錯誤!長度必須為16、24和32。目前長度為%d\n",keylen);
        exit();
    }

    extendKey(key);//擴充密鑰

    for(k = ; k < clen; k += ) {
        int i;
        int wArray[][];

        convertToIntArray(c + k, cArray);





        addRoundKey(cArray, );

        for(i = ; i >= ; i--) {
            deSubBytes(cArray);

            deShiftRows(cArray);

            deMixColumns(cArray);
            getArrayFrom4W(i, wArray);
            deMixColumns(wArray);

            addRoundTowArray(cArray, wArray);
        }

        deSubBytes(cArray);

        deShiftRows(cArray);

        addRoundKey(cArray, );

        convertArrayToStr(cArray, c + k);

    }
}
           

繼續閱讀