密码学 January 03, 2020

DES加密算法和AES加密算法初探

Words count 225k Reading time 3:25 Read count 0

一、DES加密算法原理分析

1、所需要的参数:

key:8个字节共64位的工作密钥

data:8个字节共64位的需要被加密或者被解密的数据

mode:DES工作方式,加密或者解密(CBC模式和ECB模式)

2、初始置换

DES算法使用64位的密钥key将64位的明文输入块变成64位的密文输出块,并将输出块分为L0和R0两部分,每部分均为32位。初始置换规则如下:

注意:这里的数字表示的是原数据的位置,不是数据

1
2
3
4
5
6
7
8
58,50,42,34,26,18,10,2,
60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6,
64,56,48,40,32,24,16,8,
57,49,41,33,25,17, 9,1,
59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,
63,55,47,39,31,23,15,7,

即将输入的64位明文的第1位置换到第40位,第2位置换到第8位,第3位置换到第48位。以此类推,最后一位是原来的第7位。其实可以看成是2组2维等差数列,其中横向递减8,纵向递增2排列,这个置换的规则是规定的,L0表示置换后的数据的前32位,R0表示置换后数据的后32位。

例如:64位输入块是D1—D64,则经过初始置换后是D58,D50…..D7。则L0=D58,D50,D12….D8;R0=D57,D49…..D7,该置换过程是在64位密钥控制下。

3、加密处理–迭代过程

经过初始置换后,进行16轮完全相同的运算,在运算过程中数据与密钥结合 。

函数f的输出经过一个异或运算,和左半部分结合形成新的右半部分,原来的右半部分变成新的左半部分。用公式表示如下:

1
2
3
Ln = R(n - 1);

Rn = L(n - 1)⊕f(Rn-1,kn-1)

3.1函数f

函数f由四步运算构成:密钥置换(Kn的生成,n=0-16);扩展置换;S-盒代替;P-盒置换

3.1.1 密钥置换–子密钥生成

DES算法由64位密钥产生16轮的48位子秘钥。在每一轮的迭代过程中,使用不用的子秘钥。(如何产生?)

a、把密钥的奇偶校验位忽略不参与计算,即每个字节的第八位,将64位密钥降至56位,然后根据选择置换PC-1将这56位分为两块C0(28位)和D0(28位);

b、将C0和D0进行循环左移变化(注:每轮循环左移的位数由轮数决定),变换后生成C1和D1,然后C1和D1合并,并通过选择置换PC-2生成子密钥K1(48位)

c、C1和D1在经过循环左移变换,生成C2和D2,然后C2和D2合并,通过选择置换PC-2生成密钥K2(48位);

d、以此类推,得到K16(48位)。但是最后一轮的左右两部分不交换,而是直接合并在一起R16L16,作为逆置换的输入块。其中循环左移的位数一共是循环左移16次,其中第一次,第二次,第九次,第十六次是循环左移一位,其他都是左移2位。

3.1.2 密钥置换选择1—-PC-1(子秘钥的生成)

操作对象是64位的密钥

64位密钥降至56位密钥不是说将每个字节的第八位删除,而是通过缩小选择换位表1(置换选择表1)的变换变成56位,如下:

1
2
3
4
5
6
7
57,49,41,33,25,17,9,1,
58,50,42,34,26,18,10,2,
59,51,43,35,27,19,11,3,
60,52,44,36,63,55,47,39,
31,23,15,7,62,54,46,38,
30,22,14,6,61,53,45,37,
29,21,13,5,28,20,12,4

*注意8,16,24,32,40,48,56,64处的数据都被剔除了,所以变成了56位。

再将56位的密钥分成C0和D0:

C0=K57K49K…..K36

1
2
3
4
57,49,41,33,25,17,9,
1,58,50,42,34,26,18,
10,2,59,51,43,35,27,
19,11,3,60,52,44,36,

D0=K63K55K…..K4

1
2
3
4
63,55,47,39,31,23,15,
7,62,54,46,38,30,22,
14,6,61,53,45,37,29,
21,13,5,28,20,12,4

根据轮数将Cn和Dn分别循环左移1位或2位

下面是移动的位数表:

57648238378

第一轮是循环左移1位,C0循环左移1位后得到C1如下:

1
2
3
4
49,41,33,25,17,9,1,
58,50,42,34,26,18,10,
2,59,51,43,35,27,19,
11,3,60,52,44,36,57

D0循环左移1位后得到D1如下:

1
2
3
4
55,47,39,31,23,15,7,
62,54,46,38,30,22,14,
6,61,53,45,37,29,21,
13,5,28,20,12,4,63

C1和D1合并之后,再经过置换选择表2生成48位的子秘钥K1。置换选择表2(PC-2)如下:

去掉第9、18、22、25、35、38、43、54位,从56位变成48位,再按新表的位置置换。

1
2
3
4
5
6
7
8
14,17,11,24,1,5,
3,28,15,6,21,10,
23,19,12,4,26,8,
16,7,27,20,13,2,
41,52,31,37,47,55,
30,40,51,45,33,48,
44,49,39,56,34,53,
46,42,50,36,29,32

C1和D1再次经过循环左移变换,生成C2和D2,C2和D2合并,通过PC-2生成子秘钥K2。以此类推,得到子秘钥K1~K16。需要注意其中循环左移的位数,根据轮数来定的。

3.1.2 扩展置换E(E位选择表)

通过扩展置换E,数据的右半部分Rn从32位扩展到48位。扩展置换改变了位的次序,重复了某些位。

扩展置换的目的:

a、产生与密钥相同长度的数据以进行异或运算,R0是32位,子秘钥是48位,所以R0要先进行扩展置换之后与子秘钥进行异或运算;

b、提供更长的结果,使得在替代运算时能够进行压缩。

扩展置换E规则如下:

57648726383

1
2
3
4
5
6
7
8
32,1,2,3,4,5,
4,5,6,7,8,9,
8,9,10,11,12,13,
12,13,14,15,16,17,
16,17,18,19,20,21,
20,21,22,23,24,25,
24,25,26,27,28,29,
28,29,30,31,32,1

3.1.3 S-盒代替(功能表S盒)

Rn扩展置换之后与子秘钥Kn异或以后的结果作为输入块进行S盒代替运算

功能是把48位数据变为32位数据

代替运算由8个不同的代替盒(S盒)完成。每个S-盒有6位输入,4位输出。

所以48位的输入块被分成8个6位的分组,每一个分组对应一个S-盒代替操作。

经过S-盒代替,形成8个4位分组结果。

每个S-盒是4行16列的格式,因为二进制4位是0~15。8个S-盒的值如下:

57648784140

57648785382

57648786303)57648787117

S-盒计算过程

57648792524

假设输入是110011,将收尾合并作为行坐标,中间的作为纵坐标,得到(11,1001),二进制转成10进制得到下标为(3,9),得到数值12,转成二进制:1100,因此一个6位的输入作为下标就会得到相应值4位的输出,以此类推。

3.1.4 P-盒置换

S-盒代替运算,每一盒得到4位,8盒得到共32位输出。这32位的输出又作为P盒置换的输入块。

P盒置换将每一位输入位映射到输出位。任何一位都不能被映射2次,也不能被略去。

经过了P盒置换的结果与最初64位分组的左半部分异或,然后左右两部分交换,开始下一轮迭代

P-盒置换表(表示数据的位置)共32位

1
2
16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,
2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25,

将32位的输入的第16位放在第一位,第七位放在第二位,第二十位放在第三位,以此类推,相当于换了位置。

变成新的32位输出。

4、逆置换

将初始置换进行16次的迭代,即进行16层的加密变换,这个运算过程我们暂时称为函数f。得到L16和R16,将此作为输入块,进行逆置换得到最终的密文输出块。逆置换是初始置换的逆运算。从初始置换规则中可以看到,原始数据的第1位置换到了第40位,第2位置换到了第8位。则逆置换就是将第40位置换到第1位,第8位置换到第2位。以此类推,逆置换规则如下:

1
2
3
4
40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,
38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,
36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,
34,2,42,10,50,18,58 26,33,1,41, 9,49,17,57,25,

然后就可以得到最终的输出密文了。

4.DES算法描述

1)、输入64位明文数据,并进行初始置换IP;

2)、在初始置换IP后,明文数据再被分为左右两部分,每部分32位,以L0,R0表示;

3)、在秘钥的控制下,经过16轮运算(f);(包括子密钥生成、扩展置换、s盒代换、p盒代换)

4)、16轮后,左、右两部分交换,并连接再一起,再进行逆置换;

5)、输出64位密文。

5.DES解密

加密和解密可以使用相同的算法。加密和解密唯一不同的是秘钥的次序是相反的。就是说如果每一轮的加密秘钥分别是K1、K2、K3…K16,那么解密秘钥就是K16、K15、K14…K1。为每一轮产生秘钥的算法也是循环的。加密是秘钥循环左移,解密是秘钥循环右移。解密秘钥每次移动的位数是:0、1、2、2、2、2、2、2、1、2、2、2、2、2、2、1。

6.DES算法特点

1、分组加密算法:

以64位为分组。64位明文输入,64位密文输出。

2、对称算法:

加密和解密使用同一秘钥

3、有效秘钥长度为56位

秘钥通常表示为64位数,但每个第8位用作奇偶校验,可以忽略。

4、代替和置换

DES算法是两种加密技术的组合:混乱和扩散。先替代后置换。

5、易于实现

DES算法只是使用了标准的算术和逻辑运算,其作用的数最多也只有64 位,因此用70年代末期的硬件技术很容易实现

算法的重复特性使得它可以非常理想地用在一个专用芯片中。

7 秘钥算法的特点

优点:

效率高,算法简单,系统开销小

适合加密大量数据

明文长度和密文长度相等

缺点:

需要以安全方式进行秘钥交换

秘钥管理复杂

5、c实现:

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
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
/*------------------------
定义枚举型全局变量
------------------------*/
typedef enum
{
false = 0,
true = 1
} bool;

// 十六轮子密钥
static bool SubKey[16][48]={0};

/*---------------------*/
/*-------------------------------------------------------------
各种置换表
-------------------------------------------------------------*/
// IP置换表
const char IP_Table[64]={
58,50,42,34,26,18,10, 2,60,52,44,36,28,20,12, 4,
62,54,46,38,30,22,14, 6,64,56,48,40,32,24,16, 8,
57,49,41,33,25,17, 9, 1,59,51,43,35,27,19,11, 3,
61,53,45,37,29,21,13, 5,63,55,47,39,31,23,15, 7
};
// IP-1置换表
const char IPR_Table[64]={
40, 8,48,16,56,24,64,32,39, 7,47,15,55,23,63,31,
38, 6,46,14,54,22,62,30,37, 5,45,13,53,21,61,29,
36, 4,44,12,52,20,60,28,35, 3,43,11,51,19,59,27,
34, 2,42,10,50,18,58,26,33, 1,41, 9,49,17,57,25
};

// E扩展表
static char E_Table[48]={
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
8, 9,10,11,12,13,12,13,14,15,16,17,
16,17,18,19,20,21,20,21,22,23,24,25,
24,25,26,27,28,29,28,29,30,31,32, 1
};
// PC1置换表
static char PC1_Table[56]={
57,49,41,33,25,17, 9, 1,58,50,42,34,26,18,
10, 2,59,51,43,35,27,19,11, 3,60,52,44,36,
63,55,47,39,31,23,15, 7,62,54,46,38,30,22,
14, 6,61,53,45,37,29,21,13, 5,28,20,12, 4
};

// pc2表
static char PC2_Table[48]={
14,17,11,24, 1, 5, 3,28,15, 6,21,10,
23,19,12, 4,26, 8,16, 7,27,20,13, 2,
41,52,31,37,47,55,30,40,51,34,33,48,
44,49,39,56,34,53,46,42,50,36,29,32
};
// 移位表
static char Move_Table[16]={
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
// S盒
static char S_Box[8][4][16]={
//S1
14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13,
//S2
15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9,
//S3
10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12,
//S4
7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14,
//S5
2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3,
//S6
12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
10,15, 4, 2, 7,12, 0, 5, 6, 1,13,14, 0,11, 3, 8,
9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13,
//S7
4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
13, 0,11, 7, 4, 0, 1,10,14, 3, 5,12, 2,15, 8, 6,
1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12,
//S8
13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11
};
//P置换表
static char P_Table[32]={
16, 7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10,
2, 8,24,14,32,27, 3, 9,19,13,30, 6,22,11, 4,25
};
/*-------------------------------------------------------------------*/

/*-----------------------------自定义函数-----------------------------*/
void SetKey(char My_key[8]); //生成16轮的子密钥;
void ByteToBit(bool * Data_out,char * Data_in,int Num); //字节转换成位;
void Change_bit(bool * Data_out,int Num);//二进制的位置进行转换;
void BitToByte(char My_message[8],bool * Message_in,int Num); //位转换成字节;
void TableReplace(bool *Data_out,bool *Data_in,const char *Table,int Num); //各种表的置换算法;
void Bitcopy(bool * Data_out,bool * Data_in,int Num); //二进制数组的拷贝
void Loop_bit(bool * Data_out,int movstep,int len); //左移位;
void Run_Des(char My_message[8],char HexMssage[16]);//des的轮加密算法
void Xor(bool * Message_out, bool * Message_in,int Num); //执行异或
void S_change(bool * Data_out, bool * Data_in); // S盒变换;
void HexToBit(bool * Data_out,char * Data_in,int Num); // 十六进制转二进制
void BitToHex(char * Data_out,bool * Data_in,int Num); //二进制转换成十六进制;
void Run_desDes(char My_message[8],char HexMessage[16]);// DES轮解密算法;

/*--------------------------*/

/*--------------------------主函数----------------------------------*/
int main()
{
int i=0,j;
char My_key[8]={0}; //记录加密密钥;
char You_key[8]={0}; //解密密钥
char My_message[8]={0}; //明文
char Message_hex[16]={0};//16进制的密文
printf("请输入你要加密的内容(8 Byte):\n");
gets(My_message);
printf("请输入你的加密密钥:\n");
gets(My_key);
i=strlen(My_key);
while(i!=8)
{
printf("请输入加密密钥(8 Byte)\n");
gets(My_key);
i=0;
i=strlen(My_key);
}
SetKey(My_key); //生成16轮的加密子密钥;
Run_Des(My_message,Message_hex); //des的轮加密过程
printf("经过加密的密文为:\n");
for(i=0;i<16;i++)
{
printf("%c ",Message_hex[i]);
}
printf("\n");
printf("请输入你的解密密钥(8 Byte):\n");
gets(You_key);
i=strlen(You_key);
while(i!=8)
{
printf("请输入解密密钥(8 Byte)\n");
gets(You_key);
i=0;
i=strlen(You_key);
}
SetKey(You_key); //生成16轮的解密子密钥;
Run_desDes(My_message,Message_hex);//解密;
printf("解密结果为:\n");
for(i=0;i<8;i++)
{
printf("%c ",My_message[i]);
}
printf("\n");
return 0;
}

/*--------------------具体函数定义----------------------*/
void Bitcopy(bool * Data_out, bool * Data_in,int Num) //二进制数组拷贝
{
int i=0;
for(i=0;i<Num;i++)
{
Data_out[i]=Data_in[i];
}

}
void Change_bit(bool * Data_out,int Num) //二进制的位置进行转换;
{
int i,j;
static bool Temp[8]={0};
for(i=0;i<Num/8;i++)
{
Bitcopy(Temp,Data_out,Num/8);
for(j=0;j<Num/8;j++)
{
Data_out[j]=Temp[Num/8-1-j];
}
Data_out+=Num/8;
}
}
void ByteToBit( bool * Data_out,char * Data_in,int Num) //字节转位
{
int i,j;
for(i=0;i<Num;i++)
{
Data_out[i]=(Data_in[i/8]>>(i%8))&0x01;
}
//Change_bit(Data_out,Num);
}
void BitToHex(char * Data_out, bool * Data_in,int Num) //二进制转十六进制
{
int i;
for(i=0;i<Num/4;i++)
{
Data_out[i]=0;
}
for(i=0;i<Num/4;i++)
{
Data_out[i]=Data_in[4*i]+Data_in[4*i+1]*2+Data_in[4*i+2]*4+Data_in[4*i+3]*8;
if(Data_out[i]%16>9)
{
Data_out[i]=Data_out[i]%16+'7';
}
else
Data_out[i]=Data_out[i]%16+'0';
}
}
void HexToBit(bool * Data_out,char * Data_in,int Num) //十六进制转二进制
{
int i;
for(i=0;i<Num;i++)
{
if(Data_in[i/4]<='9')
{
Data_out[i]=((Data_in[i/4]-'0')>>(i%4))&0x01;
}
else
{
Data_out[i]=((Data_in[i/4]-'7')>>(i%4))&0x01;
}
}
}
void BitToByte(char My_message[8],bool * Message_in,int Num) //位转换成字节
{
int i=0;
for(i=0;i<(Num/8);i++)
{
My_message[i]=0;
}
for(i=0;i<Num;i++)
{
My_message[i/8]|=Message_in[i]<<(i%8);
}
}
void TableReplace( bool *Data_out, bool * Data_in,const char *Table ,int Num) // 置换算法
{
int i=0;
static bool Temp[256]={0};
for(i=0;i<Num;i++)
{
Temp[i]=Data_in[Table[i]-1];
}
Bitcopy(Data_out,Temp,Num);
}
void Loop_bit(bool * Data_out,int movstep,int len)
{
static bool Temp[256]={0};
Bitcopy(Temp,Data_out,movstep);
Bitcopy(Data_out,Data_out+movstep,len-movstep);
Bitcopy(Data_out+len-movstep,Temp,movstep);
/*Temp=Data_out;
Temp[movstep]='\0';
Data_out=Data_out+movstep;
Data_out+(len-movstep)=Temp;*/
}
void Xor(bool * Message_out,bool * Message_in,int Num)//执行异或
{
int i;
for(i=0;i<Num;i++)
{
Message_out[i]=Message_out[i]^Message_in[i];
}
}
void SetKey(char My_key[8])
{
int i,j;
static bool Key_bit[64]={0}; //Key的二进制缓存;
static bool *Key_bit_L,*Key_bit_R;
Key_bit_L=&Key_bit[0]; //key的左边28位;
Key_bit_R=&Key_bit[28]; //key的右边28位;
ByteToBit(Key_bit,My_key,64);
/* Change_bit(Key_bit,64) ;//二进制的位置进行转换;
for(i=0;i<64;i++)
{
printf("%d ",Key_bit[i]);
}
printf("\n");
printf("\n");*/
TableReplace(Key_bit,Key_bit,PC1_Table,56);//pc-1 置换
for(i=0;i<16;i++)
{
Loop_bit(Key_bit_L,Move_Table[i],28);
Loop_bit(Key_bit_R,Move_Table[i],28);
TableReplace(SubKey[i],Key_bit,PC2_Table,48);//pc-2置换
}
}
void S_change(bool * Data_out, bool * Data_in) //S盒变换
{
int i;
int r=0,c=0;//S盒的行和列;
for(i=0;i<8;i++,Data_in=Data_in+6,Data_out=Data_out+4)
{
r=Data_in[0]*2+Data_in[5]*1;
c=Data_in[1]*8+Data_in[2]*4+Data_in[3]*2+Data_in[4]*1;
ByteToBit(Data_out,&S_Box[i][r][c],4);
}
}
void F_change(bool Data_out[32],bool Data_in[48]) // f函数;
{
int i;
static bool Message_E[48]={0}; //存放E置换的结果;
TableReplace(Message_E,Data_out,E_Table,48);//E表置换
Xor(Message_E,Data_in,48);
S_change(Data_out,Message_E); // S盒变换
TableReplace(Data_out,Data_out,P_Table,32); //P置换
}
void Run_Des(char My_message[8],char HexMssage[16])//des轮加密算法;
{
int i;
static bool Message_bit[64]={0};
static bool *Message_bit_L=&Message_bit[0],*Message_bit_R=&Message_bit[32];
static bool Temp[32]={0};
ByteToBit(Message_bit,My_message,64);
/*Change_bit(Message_bit,64) ;//二进制的位置进行转换;
for(i=0;i<64;i++)
{
printf("%d ",Message_bit[i]);
}
printf("\n");
printf("\n");*/
TableReplace(Message_bit,Message_bit,IP_Table,64);
for(i=0;i<16;i++)
{
Bitcopy(Temp,Message_bit_R,32);
F_change(Message_bit_R,SubKey[i]);
Xor(Message_bit_R,Message_bit_L,32);
Bitcopy(Message_bit_L,Temp,32);
}
TableReplace(Message_bit,Message_bit,IPR_Table,64);
BitToHex(HexMssage,Message_bit,64);//二进制转换成十六进制;
}
void Run_desDes(char My_message[8],char HexMessage[16])// DES轮解密算法;
{
int i=0;
static bool Message_bit[64]={0};
static bool * Message_bit_L=&Message_bit[0], * Message_bit_R=&Message_bit[32];
static bool Temp[32]={0};
HexToBit(Message_bit,HexMessage,64);
TableReplace(Message_bit,Message_bit,IP_Table,64);
for(i=15;i>=0;i--)
{
Bitcopy(Temp,Message_bit_L,32);
F_change(Message_bit_L,SubKey[i]);
Xor(Message_bit_L,Message_bit_R,32);
Bitcopy(Message_bit_R,Temp,32);
}
TableReplace(Message_bit,Message_bit,IPR_Table,64);
BitToByte(My_message,Message_bit,64);
}

二、AES加密算法分析

分类如下:57655044782

这里只分析AES128的情况

首先我们知道分组长度为128bit,密钥长度也是128bit,进行的加密轮数是10轮

image-20200508121149743

1、密钥加法层

这里是将128位的明文x和128位的密钥k[0]进行一个按字节异或的操作,前提是按照固定的排列顺序

image-20200508121333656

2、字节代换层

需要用到一个s盒,如下

image-20200508140918410

这里的理解如下,输入的字符1:0011 0001,即(0011,0001),即(3,1),取到0xC7

image-20200508141008837

3、行位移——shiftrows

image-20200508141449698

这里的解释就是,第一行不变,然后第二行左移1个字节,第三行左移2个字节,第四行左移3个字节,解密时就是一个相反的过程:

image-20200508142420460

4、列混淆——mixcolumn

image-20200508142231399

这里主要是左乘了一个矩阵,然后将加法和乘法运算利用GF(128)下的有限域去求解,转成特殊的运算,从而使得输入的数据再次混淆,这里解密时,用的是正矩阵的逆矩阵:

image-20200508142320238

加密部分讲解完毕,最后应该注意要将密文结果从矩阵形式还原成字符串形式输出!这就是一轮的加密处理操作,当进行到最后一轮的时候,不再进行列混淆的操作了。

image-20200508143901188

下面继续看看我们的key是怎么生成的

5、密钥生成

image-20200508143518443

这里有个g函数的处理,作用主要有2个,一是增强密钥编排中的非线性,二是消除aes中的对称性,可以有效地抵抗分组密码的攻击

image-20200508143043699

image-20200508143127449

从这里可以看到,k0就是初始密钥k,然后(1,4)通过异或运算生成了5,接着(2,5)生成了6,以此类推。

每4个为一个周期生成密钥,一共生成了16个密钥(如果轮数是16的话)

6、解密

image-20200508144050113

image-20200508144058546

刚好是反向的过程,但是第一次有列混淆的逆向处理操作,最后回到第一轮时就没有了,同时s盒是变的,然后其他的都是可以逆向的,难点其实是S盒和逆S盒的生成,涉及到数论的知识点,我们这里会用即可。

大概的流程如下:

1、n个子密钥生成

2、子密钥和data进行密钥加法层运算(xor)

3、密钥加法层的结果进行字节代换层运算

4、进入行位移层运算,移位

5、进入列混淆层运算,乘以混淆矩阵

6、一共进行10轮这样的加密,最后一步不用列混淆,得到密文

c语言实现模板

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

#include <stdio.h>
/*aes_small.c*/
//辅助矩阵
/*s盒矩阵:The AES Substitution Table*/// 256 位的密匙256 位支持长度为32 个字符
static const unsigned char sbox[256]={ //static:内部变量 const:只读,不可变常量
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,
};
//逆向S 盒矩阵
static const unsigned char contrary_sbox[256]={
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,//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,
};
/*轮常量表 The key schedule rcon table*/
static const unsigned char Rcon[10]={
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36};

//辅助函数
/*有限域*2乘法 The x2time() function */
static unsigned char x2time(unsigned char x)
{
if (x&0x80)
{
return (((x<<1)^0x1B)&0xFF);
}
return x<<1;
}
/*有限域*3乘法 The x2time() function */
static unsigned char x3time(unsigned char x)
{
return (x2time(x)^x);
}
/*有限域*4乘法 The x4time() function */
static unsigned char x4time(unsigned char x)
{
return ( x2time(x2time(x)) );
}
/*有限域*8乘法 The x8time() function */
static unsigned char x8time(unsigned char x)
{
return ( x2time(x2time(x2time(x))) );
}
/*有限域9乘法 The x9time() function */
static unsigned char x9time(unsigned char x) //9:1001
{
return ( x8time(x)^x );
}
/*有限域*B乘法 The xBtime() function */
static unsigned char xBtime(unsigned char x) //B:1011
{
return ( x8time(x)^x2time(x)^x );
}
/*有限域*D乘法 The xDtime() function */
static unsigned char xDtime(unsigned char x) //D:1101
{
return ( x8time(x)^x4time(x)^x );
}
/*有限域*E乘法 The xEtime() function */
static unsigned char xEtime(unsigned char x) //E:1110
{
return ( x8time(x)^x4time(x)^x2time(x) );
}

/****************************************************************************************************************/
/*第三类操作:列混合操作 MixColumns: Process the entire block*/
static void MixColumns(unsigned char *col)//列混合
{
unsigned char tmp[4],xt[4];
int i;
for(i=0;i<4;i++,col+=4) //col代表一列的基地址,col+4:下一列的基地址
{
/*
xt[0]=x2time(col[0]);
xt[1]=x2time(col[1]);
xt[2]=x2time(col[2]);
xt[3]=x2time(col[3]);
//xt[n]代表*2 xt[n]^col[n]代表*3 col[n]代表*1
tmp[0]=(xt[0])^(xt[1]^col[1])^col[2]^col[3]; //2 3 1 1
tmp[1]=col[0]^(xt[1])^(xt[2]^col[2])^col[3]; //1 2 3 1
tmp[2]=col[0]^col[1]^(xt[2])^(xt[3]^col[3]); //1 1 2 3
tmp[3]=(xt[0]^col[0])^col[1]^col[2]^(xt[3]); //3 1 1 2
*/
tmp[0]=x2time(col[0])^x3time(col[1])^col[2]^col[3]; //2 3 1 1
tmp[1]=col[0]^x2time(col[1])^x3time(col[2])^col[3]; //1 2 3 1
tmp[2]=col[0]^col[1]^x2time(col[2])^x3time(col[3]); //1 1 2 3
tmp[3]=x3time(col[0])^col[1]^col[2]^x2time(col[3]); //3 1 1 2
//修改后的值 直接在原矩阵上修改
col[0]=tmp[0];
col[1]=tmp[1];
col[2]=tmp[2];
col[3]=tmp[3];
}
}
//逆向列混淆
static void Contrary_MixColumns(unsigned char *col)
{
unsigned char tmp[4];
unsigned char xt2[4];//colx2
unsigned char xt4[4];//colx4
unsigned char xt8[4];//colx8
int x;
for(x=0;x<4;x++,col+=4)
{
/*
xt2[0]=x2time(col[0]);
xt2[1]=x2time(col[1]);
xt2[2]=x2time(col[2]);
xt2[3]=x2time(col[3]);
xt4[0]=x2time(xt2[0]);
xt4[1]=x2time(xt2[1]);
xt4[2]=x2time(xt2[2]);
xt4[3]=x2time(xt2[3]);
xt8[0]=x2time(xt4[0]);
xt8[1]=x2time(xt4[1]);
xt8[2]=x2time(xt4[2]);
xt8[3]=x2time(xt4[3]);
tmp[0]=xt8[0]^xt4[0]^xt2[0]^xt8[1]^xt2[1]^col[1]^xt8[2]^xt4[2]^col[2]^xt8[3]^col[3];
tmp[1]=xt8[0]^col[0]^xt8[1]^xt4[1]^xt2[1]^xt8[2]^xt2[2]^col[2]^xt8[3]^xt4[3]^col[3];
tmp[2]=xt8[0]^xt4[0]^col[0]^xt8[1]^col[1]^xt8[2]^xt4[2]^xt2[2]^xt8[3]^xt2[3]^col[3];
tmp[3]=xt8[0]^xt2[0]^col[0]^xt8[1]^xt4[1]^col[1]^xt8[2]^col[2]^xt8[3]^xt4[3]^xt2[3];
*/
tmp[0]=xEtime(col[0])^xBtime(col[1])^xDtime(col[2])^x9time(col[3]);
tmp[1]=x9time(col[0])^xEtime(col[1])^xBtime(col[2])^xDtime(col[3]);
tmp[2]=xDtime(col[0])^x9time(col[1])^xEtime(col[2])^xBtime(col[3]);
tmp[3]=xBtime(col[0])^xDtime(col[1])^x9time(col[2])^xEtime(col[3]);
col[0]=tmp[0];
col[1]=tmp[1];
col[2]=tmp[2];
col[3]=tmp[3];
}
}
/*第二类操作:行移位:行左循环移位 ShiftRows:Shifts the entire block*/
static void ShiftRows(unsigned char *col)//正向行移位
{
/*
1 5 9 13 5 9 13 1
2 6 10 14 10 14 2 6
3 7 11 15 15 3 7 11
4 8 12 16 16 4 8 12
*/
unsigned char t;
/*1nd row*///左移1位
t=col[1];col[1]=col[5];col[5]=col[9];col[9]=col[13];col[13]=t;
/*2rd row*///左移2位,交换2次数字来实现
t=col[2];col[2]=col[10];col[10]=t;
t=col[6];col[6]=col[14];col[14]=t;
/*3th row*///左移3位,相当于右移1次
t=col[15];col[15]=col[11];col[11]=col[7];col[7]=col[3];col[3]=t;
/*4th row*/ //第4行不移位
}
//逆向行移位
static void Contrary_ShiftRows(unsigned char *col)
{
unsigned char t;
/*1nd row*/
t=col[13];col[13]=col[9];col[9]=col[5];col[5]=col[1];col[1]=t;
/*2rd row*/
t=col[2];col[2]=col[10];col[10]=t;
t=col[6];col[6]=col[14];col[14]=t;
/*3th row*/
t=col[3];col[3]=col[7];col[7]=col[11];col[11]=col[15];col[15]=t;
/*4th row*/ //第4行不移位
}
/*第一类操作:s盒字节代换替换 SubBytes*/
static void SubBytes(unsigned char *col)//字节代换
{
int x;
for(x=0;x<16;x++)
{
col[x]=sbox[col[x]];
}
}
//逆向字节代换
static void Contrary_SubBytes(unsigned char *col)
{
int x;
for(x=0;x<16;x++)
{
col[x]=contrary_sbox[col[x]];
}
}
/*第四类操作:轮密钥加 AddRoundKey*/
static void AddRoundKey(unsigned char *col,unsigned char *expansionkey,int round)//密匙加
{
//扩展密钥:44*32bit =11*4* 4*8 = 16字节*11轮,每轮用16字节密钥
//第0轮,只进行一次轮密钥加
//第1-10轮,轮密钥加
int x;
for(x=0;x<16;x++) //每1轮操作:4*32bit密钥 = 16个字节密钥
{
col[x]^=expansionkey[(round<<4)+x];
}
}
/* AES加密总函数 10轮4类操作 Encrypt a single block with Nr Rounds(10,12,14)*/
void AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr)//加密一个区块
{
//输入blk原文,直接在上面修改,输出blk密文
//输入skey:
//输入Nr = 10轮
int round;
//第1轮之前:轮密钥加
AddRoundKey(blk,expansionkey,0);
//第1-9轮:4类操作:字节代换、行移位、列混合、轮密钥加
for(round=1;round<=(Nr-1);round++)
{
SubBytes(blk); //输入16字节数组,直接在原数组上修改
ShiftRows(blk); //输入16字节数组,直接在原数组上修改
MixColumns(blk); //输入16字节数组,直接在原数组上修改
AddRoundKey(blk,expansionkey,round);
}
//第10轮:不进行列混合
SubBytes(blk);
ShiftRows(blk);
AddRoundKey(blk,expansionkey,Nr);
}
//AES 解密总函数
void Contrary_AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr)
{
int x;
/* unsigned char *contrary_key=key;
for(x=0;x<11;x++,key+=16)
Contrary_MixColumns(key);*/
AddRoundKey(blk,expansionkey,Nr);
(blk);
Contrary_SubBytes(blk);
for(x=(Nr-1);x>=1;x--)
{
AddRoundKey(blk,expansionkey,x);
Contrary_MixColumns(blk);
Contrary_ShiftRows(blk);
Contrary_SubBytes(blk);
}
AddRoundKey(blk,expansionkey,0);
}
/*//密钥编排,16字节--->44列32bit密钥生成--> 11组16字节:分别用于11轮 轮密钥加运算
Schedule a secret key for use.
*outkey[] must be 16*15 bytes in size
*Nk==number of 32 bit words in the key,e.g.,4,6,8
*Nr==number of rounds,e.g.,10,12,14
*/
void ScheduleKey(unsigned char *inkey,unsigned char *outkey,int Nk,int Nr)//安排一个保密密钥使用
{
//inkey:初始16字节密钥key
//outkey:11组*16字节扩展密钥expansionkey
//Nk:4列
//Nr:10轮round
unsigned char temp[4],t;
int x,i;
/*copy the key*/
//第0组:[0-3]直接拷贝
for(i=0;i<(4*Nk);i++)
{
outkey[i]=inkey[i];
}
//第1-10组:[4-43]
i=Nk;
while(i<(4*(Nr+1))) //i=4~43 WORD 32bit的首字节地址,每一个4字节
{//1次循环生成1个字节扩展密钥,4次循环生成一个WORD
//temp:4字节数组:代表一个WORD密钥
/*temp=w[i-1]*/
//i不是4的倍数的时候
//每个temp = 每个outkey32bit = 4字节
for(x=0;x<4;x++)
temp[x]=outkey[(4*(i-1))+x]; //i:32bit的首字节地址
//i是4的倍数的时候
if(i%Nk==0)
{
/*字循环:循环左移1字节 RotWord()*/
t=temp[0];temp[0]=temp[1];temp[1]=temp[2];temp[2]=temp[3];temp[3]=t;
/*字节代换:SubWord()*/
for(x=0;x<4;x++)
{
temp[x]=sbox[temp[x]];
}
/*轮常量异或:Rcon[j]*/
temp[0]^=Rcon[(i/Nk)-1];
}
//else if(Nk>6 && (i%Nk)==4) //Nk>6的算法不同,暂时用不到
//{
// /*SubWord*/
// for(x=0;x<4;x++)
// {
// temp[x]=sbox[temp[x]];
// }
//}

/*w[i] = w[i-4]^w[i-1]*/
for(x=0;x<4;x++)
{
outkey[(4*i)+x]=outkey[(4*(i-Nk))+x]^temp[x];
}
++i;
}
}
int main(void){
/*
pt:原文16字节-->密文
key:原密钥16字节
skey:密钥扩展44long
sbox:s盒
*/

unsigned char pt[17],key[17];
unsigned char expansionkey[15*16];
int i;
int j;
printf("please input plaintext\n");//输入无格式的字符串字符个数不得少于六个!!!!尽量用不同的数字或字母
scanf("%s",pt);
printf("please input key\n");//输入加密钥匙密匙个数不得低于六个!!!!尽量用不同的数字或字母
scanf("%s",key);

/*加密*/
ScheduleKey(key,expansionkey,4,10); //1、密钥扩展生成
AesEncrypt(pt,expansionkey,10); //2、AES 加密
printf("AesEncrypt text is: "); //输出密码文件
for (i = 0; i < 16; i++)
{
printf("%02x ", pt[i]);
}
printf("\n");
printf("\n");

/*解密*/
Contrary_AesEncrypt(pt,expansionkey,10);//AES 解密
printf("after Contrary_AesEncrypt,plaintext is: ");//将解密文件输出
for (i = 0; i < 16; i++)
{
printf("%c ", pt[i]);
}
printf("\n");
printf("\n");
while(1);
return 0;
}

再来个详细的aes算法的cbc模式:

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
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>


#define BLOCKSIZE 16

typedef struct{
uint32_t eK[44],dK[44];
int rounds;
} AESKEY;

#define ROF32(x,n) ((x << n) | (x >> (32-n)))

#define ROR32(x,n) ((x >> n) | (x << (32-n)))

#define BYTE(x,n) (((x)>>((n)*8)) & 0xff)

#define MIX(x) (((S[BYTE((x),2)] << 24) & 0xff000000) ^ \
((S[BYTE((x),1)] << 16) & 0xff0000) ^ \
((S[BYTE((x),0)] << 8) & 0xff00) ^ \
((S[BYTE((x),3)]) & 0xff))


#define LOAD32(x,y) do{ (x) = \
((uint32_t)((y)[0]&0xff)<<24) |\
((uint32_t)((y)[1]&0xff)<<16) |\
((uint32_t)((y)[2]&0xff)<<8 ) |\
((uint32_t)((y)[3]&0xff));\
}while(0)

#define STORE32(x,y) do{ \
(y)[0] = (uint8_t)(((x)>>24) & 0xff) ; \
(y)[1] = (uint8_t)(((x)>>16) & 0xff) ; \
(y)[2] = (uint8_t)(((x)>>8) & 0xff) ; \
(y)[3] = (uint8_t)((x) & 0xff) ; \
}while(0)


unsigned char S[256] = {
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};

unsigned char inv_S[256] = {
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};

uint8_t M[4][4] = {
{0x02, 0x03, 0x01, 0x01},
{0x01, 0x02, 0x03, 0x01},
{0x01, 0x01, 0x02, 0x03},
{0x03, 0x01, 0x01, 0x02}
};

uint8_t inv_M[4][4] = {
{0x0E, 0x0B, 0x0D, 0x09},
{0x09, 0x0E, 0x0B, 0x0D},
{0x0D, 0x09, 0x0E, 0x0B},
{0x0B, 0x0D, 0x09, 0x0E}
};


static const uint32_t rcon[10] = {
0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL,
0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL
};


int KeyExpansion(uint8_t * key,AESKEY * aeskey){
uint32_t * w = aeskey ->eK;
uint32_t * v = aeskey ->dK;
for(int i=0 ; i<4 ; i++ ){
LOAD32(w[i], key+i*4);
}
for(int i=0;i<10;i++){
w[4]=w[0]^MIX(w[3])^rcon[i];
w[5]=w[1]^w[4];
w[6]=w[2]^w[5];
w[7]=w[3]^w[6];
w+=4;
}
w = (aeskey -> eK) + 40;
for(int j=0 ;j<11;j++){
for(int i = 0 ; i<4;i++){
v[i]=w[i];
}
v+=4;
w-=4;
}
return 0;
}

void loadStateArray(uint8_t (*state)[4],uint8_t *in){
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
state[j][i]=*in++;
}
}
}

void storeStateArray(uint8_t (*state)[4],uint8_t *out){
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
*out++=state[j][i];
}
}
}

void shiftRows(uint8_t (*state)[4]){
uint32_t temp[4]={0};
for(int i=0;i<4;i++){
LOAD32(temp[i], state[i]);
temp[i]=ROF32(temp[i], i*8);
STORE32(temp[i], state[i]);
}
}

void invShiftRows(uint8_t (*state)[4]) {
uint32_t temp[4] = {0};
for (int i = 0; i < 4; i++) {
LOAD32(temp[i], state[i]);
temp[i] = ROR32(temp[i], i*8);
STORE32(temp[i], state[i]);
}
}

uint8_t GMul(uint8_t u, uint8_t v) {
uint8_t p = 0;
for (int i = 0; i < 8; ++i) {
if (u & 0x01) { //
p ^= v;
}
int flag = (v & 0x80);
v <<= 1;
if (flag) {
v ^= 0x1B;
}
u >>= 1;
}
return p;
}

void mixColumns(uint8_t (*state)[4]){
uint8_t tmp[4][4];

for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j){
tmp[i][j] = state[i][j];
}
}

for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = GMul(M[i][0], tmp[0][j]) ^
GMul(M[i][1], tmp[1][j]) ^
GMul(M[i][2], tmp[2][j]) ^
GMul(M[i][3], tmp[3][j]) ;
}
}

}

void invMixColumns(uint8_t (*state)[4]){
uint8_t tmp[4][4];

for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j){
tmp[i][j] = state[i][j];
}
}

for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = GMul(inv_M[i][0], tmp[0][j]) ^
GMul(inv_M[i][1], tmp[1][j]) ^
GMul(inv_M[i][2], tmp[2][j]) ^
GMul(inv_M[i][3], tmp[3][j]) ;
}
}

}

int addRoundKey(uint8_t (*state)[4], const uint32_t *key) {
uint8_t k[4][4];
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
k[j][i] = (uint8_t) BYTE(key[i], 3 - j); //按列异或秘钥
state[j][i] ^= k[j][i];
}
}

return 0;
}

int subBytes(uint8_t (*state)[4]) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = S[state[i][j]];
}
}
return 0;
}

int invSubBytes(uint8_t (*state)[4]) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = inv_S[state[i][j]];
}
}
return 0;
}


void aesEncryptBlock(uint8_t * mblock,uint8_t * cblock,uint8_t * key){
AESKEY aeskey;
uint8_t state[4][4]={0};
KeyExpansion(key, &aeskey);
loadStateArray(state, mblock);
uint32_t * ekPointer = aeskey.eK;
addRoundKey(state, ekPointer);
for(int i=1;i<10;i++){
ekPointer += 4;
subBytes(state);
shiftRows(state);
mixColumns(state);
addRoundKey(state, ekPointer);
}
ekPointer += 4;
subBytes(state);
shiftRows(state);
addRoundKey(state, ekPointer);
storeStateArray(state, cblock);
}

void aesDecryptBlock(uint8_t * mblock,uint8_t * cblock,uint8_t * key){
AESKEY aeskey;
uint8_t state[4][4]={0};
KeyExpansion(key, &aeskey);
loadStateArray(state, cblock);
uint32_t * dkPointer = aeskey.dK;
addRoundKey(state, dkPointer);

for(int i=1;i<10;i++){
dkPointer += 4;
invSubBytes(state);
invShiftRows(state);
addRoundKey(state, dkPointer);
invMixColumns(state);

}
dkPointer += 4;
invSubBytes(state);
invShiftRows(state);
addRoundKey(state, dkPointer);
storeStateArray(state, mblock);
}


int splitBlock(char * message,uint8_t ** blocks){
int len = (int)strlen(message);
int block_num = (len/16)+1;
int mod = len % 16;
if(mod == 0){
block_num++;
}
*blocks = (uint8_t *)malloc(block_num*16);
memcpy(*blocks, message, len);
memset(*blocks+len,0,16-mod);
return block_num;
}

uint8_t * aesEncryptCBC(uint8_t * blocks,uint8_t * key,int block_num,uint8_t * iv){
uint8_t * tmp = iv;
for(int i = 0;i<block_num;i++){
for(int j = 0;j<16;j++){
blocks[16*i+j] ^= tmp[j];
}
aesEncryptBlock(blocks+16*i, blocks+16*i, key);
tmp = blocks+16*i;
}
return blocks;
}

void aesDecryptCBC(uint8_t * blocks,uint8_t * key,int block_num,uint8_t * iv){
uint8_t * tmp = blocks+(16*(block_num-2));
for(int i = block_num-1;i > -1;i--){
aesDecryptBlock(blocks+16*i, blocks+16*i, key);
for(int j = 0;j<16;j++){
blocks[16*i+j] ^= tmp[j];
}
if(i==1){
tmp = iv;
}else{
tmp -= 16;
}
}
}

int main(int argc, const char * argv[]) {
// char message[] ="\x0C\xF9\x65\x1F\x91\x6D\x27\xDC\xEA\x2C\x65\xD5\x89\x38\xF9\xF4";
char message[] ="\x21\x23\x2F\x29\x7A\x57\xA5\xA7\x43\x89\x4A\x0E\x4A\x80\x1F\xC3";
uint8_t key[16]="\x8C\xE5\x1F\x93\x50\xF4\x45\x11\xA8\x54\xE1\xB5\xF0\xA3\xFB\xCA";
uint8_t iv[16] ="\x6E\xD6\xCE\x61\xBB\x8F\xB7\xF3\x10\xB7\x70\x45\x9E\xFC\xE1\xB1";

uint8_t * blocks = NULL;
int block_num = splitBlock(message,&blocks);
// printf("shuliang: %d",block_num);

aesEncryptCBC(blocks,key,0x10,iv);

// printf("加密密文:");
for(int i=0;i<16;i++){
printf("\\x%02x",blocks[i]);
}
// printf("\n");

// aesDecryptCBC(blocks,key,0x10,iv);
// for(int i=0;i<16;i++){
// printf("\\x%02x",blocks[i]);
// }
// printf("解密明文:%s\n",blocks);
// free(blocks);
return 0;

}

最后des和aes算法用python实现的脚本如下:

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
# -*- coding: utf-8 -*-
from Crypto.Cipher import ARC4, AES, DES
from Crypto.Util.Padding import unpad
from binascii import *
import libnum
from Crypto.Util.number import *

key = b"De1CTF"
des_key = key.ljust(8, b"\x02")
aes_key = key.ljust(16, b"\x0a")
def aes_decrypt(cipher, key=aes_key):
aes = AES.new(key, iv=key, mode=AES.MODE_CBC)
return aes.decrypt(cipher)
def aes_encrypt(cipher, key=aes_key):
aes = AES.new(key, iv=key, mode=AES.MODE_CBC)
return aes.encrypt(cipher)
def des_decrypt(cipher, key=des_key):
des = DES.new(key, iv=key, mode=AES.MODE_CBC)
return des.decrypt(cipher)
def des_encrypt(cipher, key=des_key):
des = DES.new(key, iv=key, mode=AES.MODE_CBC)
return des.encrypt(cipher)


minwen = b"flag{1234567!99}"
cipher = b"\x38\x7d\xa0\xf9\x89\x1b\x2e\x1a\x8e\x78\x6b\x39\xde\x6f\xd9\x84"
print des_decrypt(cipher)
print aes_decrypt(cipher)

三、加密模式

在这里讲解下aes和des加密都有的几种加密模式:ECB\CBC\CFB\CRT\OCF,主要讲ecb和cbc模式。

1、ECB模式,也称为电码本模式,就是将明文分为若干段相同的小段,然后对每一小段进行加密

image-20200508145228291

2、CBC模式,也称为密码分组链接模式

这种模式是先将明文切分成为若干小段,然后每一小段与初始块IV或者上一段的密文段进行异或运算后,再与密钥进行加密。

image-20200508145427772

通过对比可以知道,ecb不用iv这个值,但是cbc需要,同时cbc进行了迭代的异或操作,ecb没有,ecb比较简单,cbc比较复杂一些。

参考链接:

https://www.cnblogs.com/starwolf/p/3365834.html

https://zhuanlan.zhihu.com/p/78913397

https://www.cnblogs.com/songwenlong/p/5944139.html

0%