一.简介

AES是一种对称加密算法,所谓对称加密就是加密与解密使用的密钥是一个,广泛用于数据加密和保护信息安全,取代了之前的 DES。

二. AES 分类

名字 AES-128 AES-196 AES-256
明文分组长度 /位 128 128 128
密钥长度 /位 128 198 256
迭代轮数 10 12 14

三.加密流程(以AES128为例)

1.明文分组 —— 128bit。加密解密算法的输入是一个 128 位分组。这些分组被描述成 4×4 的字节方阵,这个分组被复制到一个 16 字节数组中,并在加密和解密的每一阶段都被修改。

2.密钥扩展 —— w[0, 3] 到 w[40, 43],下文将表示为 k0 到 k10,一共 11 个 k。密钥扩展的具体步骤将在第 6 章描述。

3.初始变换第 0 轮迭代 —— 明文 ⊕ K0。

4.9 轮迭代,每轮包括 4 个步骤 —— 字节替换,行移位,列混淆,轮密钥加。

5.第 10 轮迭代,仅 3 个步骤 —— 字节替换,行变换,轮密钥加。
简单来说就是执行字节代换,行位移,列混合,轮密钥加四个操作共9轮,第十轮不进行列混合操作

AES有256位S盒进行字节替换

标准S盒如下

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

十个参与密钥拓展算法的轮常量

以下为标准轮常量

1
2
3
4
5
6
const uint32_t Rcon[10] = {0x01000000, 0x02000000,
0x04000000, 0x08000000,
0x10000000, 0x20000000,
0x40000000, 0x80000000,
0x1b000000, 0x36000000};

首先进行密钥拓展,AES的密钥由原本128位密钥组成的4个uint32_t为基础,拓展出10轮,总计44个共11组密钥
因为加密是在4*4矩阵上进行操作,且矩阵是列优先排列的,所以先将密文按块转化为矩阵,加密完成后在转换回去

初始密钥加操作,循环9轮

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
void convertToStateArray(uint8_t s[16], uint8_t a[4][4])
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
a[j][i] = s[i * 4 + j];
}
}
}
void AES(uint8_t *message, uint64_t messageLen, uint8_t *key)
{
extendKey(key);
uint8_t sArray[4][4];

for (int i = 0; i < messageLen; i += 16)
{
convertToStateArray(message + i, sArray); // 转换为状态矩阵
addRoundKey(sArray, 0); // 初始轮密钥加
for (int j = 1; j < 10; j++) // 1~9
{
subbytes(sArray); // 字节代换
shiftRows(sArray); // 行移位
columnMix(sArray); // 列混合
addRoundKey(sArray, j); // 轮密钥加
}
subbytes(sArray);
shiftRows(sArray);
addRoundKey(sArray, 10); // 最终轮密钥加
convertToStr(sArray, message + i); // 转换回字符串
}
}

字节拓展,T是密钥拓展使用的轮函数,由字节偏移,字节代换,轮常量异或三个操作组成

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
uint32_t T(uint32_t w, int round)
{
w = (w >> 24) | (w << 8); // 字节偏移,循环左移一字节
uint8_t temp[4];
convertToWordArray(w, temp); // 转换为字节数组
for (int i = 0; i < 4; i++)
{
temp[i] = S[temp[i] >> 4][temp[i] & 0x0F]; // 字节代换
}
w = convertToWord(temp);
w ^= Rcon[round]; // 轮常量异或
return w;
}
void extendKey(uint8_t *key)
{
for (int i = 0; i < 4; i++)
{
w[i] = getBigEndian(key + i * 4); // 转大端序
}
for (int i = 4, j = 0; i < 44; i++) // 密钥拓展
{
if (i % 4 == 0)
{
w[i] = w[i - 4] ^ T(w[i - 1], j);
j++;
}
else
w[i] = w[i - 4] ^ w[i - 1];
}
}

轮密钥加操作,将当前轮对应的密钥与数据进行异或

1
2
3
4
5
6
7
8
9
10
11
12
void addRoundKey(uint8_t sArray[4][4], int round) // 轮密钥加
{
uint8_t wArray[4];
for (int i = 0; i < 4; i++)
{
convertToWordArray(w[round * 4 + i], wArray); // 转换为字节数组
for (int j = 0; j < 4; j++)
{
sArray[j][i] ^= wArray[j]; // 异或操作
}
}
}

行位移

整个矩阵第一行不动,第二行循环左移1位,第三行2位,第四行3位

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
void shiftRows(uint8_t sArray[4][4])
{
// 第0行不移位

// 第1行左移1位
uint8_t temp = sArray[1][0];
sArray[1][0] = sArray[1][1];
sArray[1][1] = sArray[1][2];
sArray[1][2] = sArray[1][3];
sArray[1][3] = temp;

// 第2行左移2位
uint8_t temp1 = sArray[2][0];
uint8_t temp2 = sArray[2][1];
sArray[2][0] = sArray[2][2];
sArray[2][1] = sArray[2][3];
sArray[2][2] = temp1;
sArray[2][3] = temp2;

// 第3行左移3位
temp = sArray[3][0];
sArray[3][0] = sArray[3][3];
sArray[3][3] = sArray[3][2];
sArray[3][2] = sArray[3][1];
sArray[3][1] = temp;
}

字节代换操作,将矩阵中一个字节的高4位作为行号,低四位作为列号在S盒中查表

1
2
3
4
5
6
void subbytes(uint8_t sArray[4][4])
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
sArray[i][j] = S[sArray[i][j] >> 4][sArray[i][j] & 0x0F]; // 字节代换
}

列混合操作是使用一个事先准备好的4*4矩阵和当前矩阵进行矩阵乘法,
GF(2^8)下的乘法满足交换律,结合律和分配律,且与二相乘可以等价于如下操作:
1.左移一位
2.如果左移前最高位为1,则与0x1B异或
所以只要实现乘二就能实现所有情况下的乘法

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
uint8_t GFMul(uint8_t s, int n)
{
if (n == 1)
{
return s;
}
if (n == 2)
{
uint8_t result = s << 1;

if (s & 0x80)
{
result = result ^ 0x1b;
}

return result;
}
if (n % 2 == 0)
return GFMul(GFMul(s, n / 2), 2);
else
return GFMul(s, n - 1) ^ s;
}
const uint8_t colM[4][4] = {2, 3, 1, 1,
1, 2, 3, 1,
1, 1, 2, 3,
3, 1, 1, 2};
void columnMix(uint8_t sArray[4][4])
{
uint8_t tempArray[4][4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
tempArray[i][j] = sArray[i][j];
for (int j = 0; j < 4; j++)
{
for (int i = 0; i < 4; i++)
{
sArray[i][j] = GFMul(tempArray[0][j], colM[i][0]) ^
GFMul(tempArray[1][j], colM[i][1]) ^
GFMul(tempArray[2][j], colM[i][2]) ^
GFMul(tempArray[3][j], colM[i][3]);
}
}
}

加密代码

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
#include <bits/stdc++.h>
using namespace std;
int w[44];
uint32_t getBigEndian(uint8_t a[4])
{
uint32_t res = 0;
res = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
return res;
}
void convertToStateArray(uint8_t s[16], uint8_t a[4][4])
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
a[j][i] = s[i * 4 + j];
}
}
}
void convertToStr(uint8_t a[4][4], uint8_t s[16])
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
s[i * 4 + j] = a[j][i];
}
void convertToWordArray(uint32_t W, uint8_t w[4])
{
w[0] = (W >> 24) & 0xFF;
w[1] = (W >> 16) & 0xFF;
w[2] = (W >> 8) & 0xFF;
w[3] = W & 0xFF;
}
uint32_t convertToWord(uint8_t w[4])
{
uint32_t res = 0;
res = (w[0] << 24) | (w[1] << 16) | (w[2] << 8) | w[3];
return res;
}
const uint8_t S[16][16] = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
const uint32_t Rcon[10] = {0x01000000, 0x02000000,
0x04000000, 0x08000000,
0x10000000, 0x20000000,
0x40000000, 0x80000000,
0x1b000000, 0x36000000};
uint32_t T(uint32_t w, int round)
{
w = (w >> 24) | (w << 8); // 字节偏移,循环左移一字节
uint8_t temp[4];
convertToWordArray(w, temp); // 转换为字节数组
for (int i = 0; i < 4; i++)
{
temp[i] = S[temp[i] >> 4][temp[i] & 0x0F]; // 字节代换
}
w = convertToWord(temp);
w ^= Rcon[round]; // 轮常量异或
return w;
}
void extendKey(uint8_t *key)
{
for (int i = 0; i < 4; i++)
{
w[i] = getBigEndian(key + i * 4); // 转大端序
}
for (int i = 4, j = 0; i < 44; i++) // 密钥拓展
{
if (i % 4 == 0)
{
w[i] = w[i - 4] ^ T(w[i - 1], j);
j++;
}
else
w[i] = w[i - 4] ^ w[i - 1];
}
}
void addRoundKey(uint8_t sArray[4][4], int round) // 轮密钥加
{
uint8_t wArray[4];
for (int i = 0; i < 4; i++)
{
convertToWordArray(w[round * 4 + i], wArray); // 转换为字节数组
for (int j = 0; j < 4; j++)
{
sArray[j][i] ^= wArray[j]; // 异或操作
}
}
}
void subbytes(uint8_t sArray[4][4])
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
sArray[i][j] = S[sArray[i][j] >> 4][sArray[i][j] & 0x0F]; // 字节代换
}
void shiftRows(uint8_t sArray[4][4])
{
// 第0行不移位

// 第1行左移1位
uint8_t temp = sArray[1][0];
sArray[1][0] = sArray[1][1];
sArray[1][1] = sArray[1][2];
sArray[1][2] = sArray[1][3];
sArray[1][3] = temp;

// 第2行左移2位
uint8_t temp1 = sArray[2][0];
uint8_t temp2 = sArray[2][1];
sArray[2][0] = sArray[2][2];
sArray[2][1] = sArray[2][3];
sArray[2][2] = temp1;
sArray[2][3] = temp2;

// 第3行左移3位
temp = sArray[3][0];
sArray[3][0] = sArray[3][3];
sArray[3][3] = sArray[3][2];
sArray[3][2] = sArray[3][1];
sArray[3][1] = temp;
}
const uint8_t colM[4][4] = {2, 3, 1, 1,
1, 2, 3, 1,
1, 1, 2, 3,
3, 1, 1, 2};
uint8_t GFMul(uint8_t s, int n)
{
if (n == 1)
{
return s;
}
if (n == 2)
{
uint8_t result = s << 1;

if (s & 0x80)
{
result = result ^ 0x1b;
}

return result;
}
if (n % 2 == 0)
return GFMul(GFMul(s, n / 2), 2);
else
return GFMul(s, n - 1) ^ s;
}
void columnMix(uint8_t sArray[4][4])
{
uint8_t tempArray[4][4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
tempArray[i][j] = sArray[i][j];
for (int j = 0; j < 4; j++)
{
for (int i = 0; i < 4; i++)
{
sArray[i][j] = GFMul(tempArray[0][j], colM[i][0]) ^
GFMul(tempArray[1][j], colM[i][1]) ^
GFMul(tempArray[2][j], colM[i][2]) ^
GFMul(tempArray[3][j], colM[i][3]);
}
}
}
void AES(uint8_t *message, uint64_t messageLen, uint8_t *key)
{
extendKey(key);
uint8_t sArray[4][4];

for (int i = 0; i < messageLen; i += 16)
{
convertToStateArray(message + i, sArray); // 转换为状态矩阵
addRoundKey(sArray, 0); // 初始轮密钥加
for (int j = 1; j < 10; j++) // 1~9
{
subbytes(sArray); // 字节代换
shiftRows(sArray); // 行移位
columnMix(sArray); // 列混合
addRoundKey(sArray, j); // 轮密钥加
}
subbytes(sArray);
shiftRows(sArray);
addRoundKey(sArray, 10); // 最终轮密钥加
convertToStr(sArray, message + i); // 转换回字符串
}
}
int main()
{
char key[] = "0123456789abcdef";
char message[] = "0123456789abcdef";
AES((uint8_t *)message, strlen(message), (uint8_t *)key);
for (int i = 0; i < 16; i++)
{
printf("%02X ", message[i] & 0xFF);
}
return 0;
}

解密代码

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

// 第1行右移1位
uint8_t temp = sArray[1][3];
sArray[1][3] = sArray[1][2];
sArray[1][2] = sArray[1][1];
sArray[1][1] = sArray[1][0];
sArray[1][0] = temp;

// 第2行右移2位
uint8_t temp1 = sArray[2][0];
uint8_t temp2 = sArray[2][1];
sArray[2][0] = sArray[2][2];
sArray[2][1] = sArray[2][3];
sArray[2][2] = temp1;
sArray[2][3] = temp2;

// 第3行右移3位
temp = sArray[3][0];
sArray[3][0] = sArray[3][1];
sArray[3][1] = sArray[3][2];
sArray[3][2] = sArray[3][3];
sArray[3][3] = temp;
}
const uint8_t deColM[4][4] = {0xe, 0xb, 0xd, 0x9,
0x9, 0xe, 0xb, 0xd,
0xd, 0x9, 0xe, 0xb,
0xb, 0xd, 0x9, 0xe};
void deMixColumns(uint8_t sArray[4][4])
{
uint8_t tempArray[4][4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
tempArray[i][j] = sArray[i][j];
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++)
sArray[i][j] = GFMul(tempArray[0][j], deColM[i][0]) ^
GFMul(tempArray[1][j], deColM[i][1]) ^
GFMul(tempArray[2][j], deColM[i][2]) ^
GFMul(tempArray[3][j], deColM[i][3]);
}
void AESdecrypt(uint8_t *message, uint64_t messageLen, uint8_t *key)
{
extendKey(key);
uint8_t sArray[4][4];

for (int i = 0; i < messageLen; i += 16)
{
convertToStateArray(message + i, sArray); // 转换为状态矩阵
addRoundKey(sArray, 10); // 初始轮密钥加
deShiftRows(sArray); // 行移位
deSubBytes(sArray); // 字节代换
for (int j = 9; j >= 1; j--)
{
addRoundKey(sArray, j); // 轮密钥加
deMixColumns(sArray); // 列混合
deShiftRows(sArray); // 行移位
deSubBytes(sArray); // 字节代换
}
addRoundKey(sArray, 0); // 最终轮密钥加
convertToStr(sArray, message + i);
}
}