RC4

RC4是一种流加密算法,其工作原理可以分为两个主要部分:密钥调度算法KSA和伪随机生成算法PRGA

  1. KSA密钥调度算法:

    初始化一个256字节的数组S,S[i] = i。

    根据密钥对S进行混排。通过循环交换S数组中的元素,确保密钥影响S的内容。

  2. PRGA伪随机生成算法:

    使用KSA生成的S数组,通过循环更新和交换元素生成伪随机字节。

    生成的字节与明文进行异或运算,得到密文。

RC4的加密和解密过程相同,因为它是基于与伪随机流的异或运算。

在逆向分析实战中判断RC4算法的可从其会初始化一个256字节的数组将一个key也填充到数组中以及加密函数大概率有两个参数,一个是key 一个是keylen

下面是RC4算法加/解密过程的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
#include <stdio.h>
#include <stdlib.h>

void swap(unsigned char* a, unsigned char* b) // 交换两个字节
{
unsigned char temp = *a;
*a = *b;
*b = temp;
}

void RC4_enc(unsigned char* plaintext, int length, const char* key) // RC4加密函数
{
int i, j;
unsigned char* S;
unsigned char k[256];
int keylen = 0;

while (key[keylen] != '\0')
{
keylen++;
}// 计算密钥长度

for (i = 0; i < 256; i++)
{
k[i] = key[i % keylen];
} // 初始化密钥数组k

S = (unsigned char*)malloc(256 * sizeof(unsigned char));
for (i = 0; i < 256; i++) {
S[i] = i;
}// 初始化S盒

j = 0;
for (i = 0; i < 256; i++) {
j = (j + S[i] + k[i]) % 256;
swap(&S[i], &S[j]);
}// 打乱S盒

i = 0;
j = 0;
for (int n = 0; n < length; n++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
swap(&S[i], &S[j]);
int t = (S[i] + S[j]) % 256;
plaintext[n] ^= S[t];
}// 进行加密

free(S);
}

int main() {
unsigned char plaintext[] =
{
0x11,0x45,0x14
};//此处为密文
const char key[] = "Key"; //此处为秘钥
RC4_enc(plaintext, sizeof(plaintext), key);

for (int i = 0; i < sizeof(plaintext); i++)
printf("%02X ", plaintext[i]);
printf("\n"); // 输出加密后的密文

return 0;
}

由于RC4加密具有自反性,所以解密过程与加密过程相同,只需要将密文作为明文,秘钥作为密钥即可

TEA

TEA在加密的过程中要加密的明文使用2个32位无符号整数(2×4字节),秘钥为4个32位无符号整数(4×4字节),更长的明文可通过分为多个4字节为单位的小组分别进行加密(循环)

在逆向分析实战中判断TEA算法的可从其3行核心加密中出现的右移4左移5,两行各有3个小括号互相异或的加密流程单次加密循环32次以及运算中出现的sumdelta变量看出

加密流程示意图:

下面是TEA算法加密过程的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
#include <stdio.h>
#include <stdint.h>
void encrypt(uint32_t* temp, uint32_t* key)// 加密函数
{
uint32_t v0 = temp[0], v1 = temp[1];// v0、v1分别是明文的左、右半部分
int sum = 0; // sum用作加密过程中的一个累加变量
uint32_t delta = 0x9e3779b9; // 作为sum每次累加的变化值,题目中往往会修改此值
for (int i = 0; i < 32; i++)
{
//以下3行是核心加密过程,题目中可能会对部分细节做出修改
//但由于异或的对称性质,无需记忆,写解密函数时照抄即可
v1 += ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);
v0 += ((v1 << 4) + key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);
sum += delta;
}
temp[0] = v0;
temp[1] = v1;
}

int main()
{
uint32_t key[4] =
{
// 此处存放密钥
};
uint32_t temp[2]; // 存储每组明文
uint8_t flag[32] =
{
// 此处存放要加密的数据
};
for (int i = 0; i < 32; i += 8)
{
temp[0] = *(uint32_t*)&flag[i];
temp[1] = *(uint32_t*)&flag[i + 4];// 设置每组明文

encrypt(temp, key);// 调用加密函数

for (int j = 0; j < 2; j++) // 输出加密后的数据
{
for (int m = 0; m < 4; m++)
{
printf("%c", temp[j] & 0xff); // 按字节输出
temp[j] >>= 8;
}
}
}
return 0;
}

下面是TEA算法解密过程的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
#include <stdio.h>
#include <stdint.h>
void decrypt(uint32_t* temp, uint32_t* key) // 解密函数
{
uint32_t v0 = temp[0], v1 = temp[1];
int sum = 0x9e3779b9 * 32; // 初始sum值,注意此处要修改为delta的32倍
uint32_t delta = 0x9e3779b9; // 和加密函数一致的delta常量
for (int i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);// 不要修改算式!
v0 -= ((v1 << 4) + key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);
sum -= delta;
}
temp[0] = v0;
temp[1] = v1;
}

int main() {
uint32_t key[4] =
{
// 此处存放密钥
};
uint32_t temp[2]; // 存储每组密文
uint8_t flag[32] =
{
// 此处存放要解密的数据
};

for (int i = 0; i < 32; i += 8)
{
temp[0] = *(uint32_t*)&flag[i];
temp[1] = *(uint32_t*)&flag[i + 4];

decrypt(temp, key);// 调用解密函数

for (int j = 0; j < 2; j++) // 输出解密后的数据
{
for (int m = 0; m < 4; m++)
{
printf("%c", temp[j] & 0xff); // 按字节输出,恢复原始字符
temp[j] >>= 8;
}
}
}
return 0;
}

魔改TEA的一些方法:

  1. 腾讯TEA

    TEA的变种,标准TEA中使用的32轮加密,而腾讯只用了16轮。

  2. CBC模式的TEA

将明文分组与前一个密文分组进行异或运算,然后再进行加密,对于第一组的话就设置一个初始值来和第一组明文异或。

每一轮是取v0和v1,data1, data2和v0,v1异或,异或之后的data1和data2传入指针进行tea加密,之后再将加密之后的赋值回的v0和v1。

逆向方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void encrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0, i;

data1 ^= v0;
data2 ^= v1;
v0 = data1;
v1 = data2;

uint32_t delta = 0x6e75316c;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (i = 0; i < 32; i++)
{
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1) ^ (sum + i);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3) ^ (sum + i);
}
data1 = v0;
data2 = v1;
}

XTEA

TEA中,密钥是直接分成4个32位部分(总共128位),每轮加密过程中使用这些部分直接参与计算。密钥在整个加密过程中的使用比较固定,没有变化。这样,攻击者只需要通过分析固定密钥的几轮加密就能发现模式,从而降低了加密算法的安全性。

XTEA中,以及密钥并不是每轮加密中直接使用固定的部分。相反,XTEA通过密钥的不同部分在每一轮加密中进行动态调度,密钥在加密过程中会经过多次变换,从而增强了密钥的复杂性和加密过程的不可预测性。

加密流程示意图:

下面是XTEA算法加密过程的C语言代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void encrypt(uint32_t v[2], uint32_t const key[4]) 
{
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
for (i=0; i < 64; i++) // XTEA默认循环64轮,与TEA不同,题目也可能修改循环次数
{
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
// 此处对key的索引方式与TEA不同
}
v[0]=v0; v[1]=v1;
}
// 主函数部分和TEA部分一致

下面是XTEA算法解密过程的C语言代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
void decipher(uint32_t v[2], uint32_t const key[4])
{
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++)
{
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
// 主函数部分和TEA部分一致

XXTEA

XXTEA使用更复杂的运算方式,它的块大小可以是任意的,密钥也可以是任意长度的(可以不是4的倍数)。

在加密时,XXTEA会对明文进行分块,然后每个块都会进行加密,加密后的结果再进行拼接,最终形成密文。

在解密时,XXTEA会对密文进行分块,然后每个块都会进行解密,解密后的结果再进行拼接,最终形成明文。

加密过程示意图:

下面是XXTEA算法加密过程的C语言代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void xxtea_encrypt(uint32_t *v, int n, uint32_t *key) {
uint32_t y, z, sum, delta, e;
uint32_t p, q, rounds, limit;
uint32_t *k = key;

rounds = 6 + 52 / n; // 计算加密轮数
sum = 0;
delta = 0x9E3779B9; // 初始化delta常数
limit = rounds * delta; // 计算sum的最大值

q = 6 + limit / delta;
while (q-- > 0) { // 执行加密轮数
sum += delta; // 更新sum
e = sum >> 2 & 3; // 计算e值
for (p = 0; p < n; p++) { // 对每个数据块执行加密操作
y = v[(p + 1) % n];
z = v[p] += ((v[(p + n - 1) % n] >> 5) ^ (y << 2)) + ((y >> 3) ^ (v[(p + n - 1) % n] << 4)) ^ ((sum ^ y) + (k[(p ^ e) & 3] ^ v[(p + n - 1) % n]));
// 计算加密后的数据块
}
}
}

下面是XXTEA算法解密过程的C语言代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void xxtea_decrypt(uint32_t *v, int n, uint32_t *key) {
uint32_t y, z, sum, delta, e;
uint32_t p, q, rounds, limit;
uint32_t *k = key;

rounds = 6 + 52 / n; // 计算加密轮数
sum = rounds * 0x9E3779B9; // 初始化sum常数
delta = 0x9E3779B9; // 初始化delta常数
limit = rounds * delta; // 计算sum的最大值

q = 6 + limit / delta;
while (q-- > 0) { // 执行加密轮数
e = sum >> 2 & 3; // 计算e值
for (p = n - 1; p > 0; p--) { // 对每个数据块执行解密操作
z = v[(p + n - 1) % n];
y = v[p] -= ((v[(p + n - 1) % n] >> 5) ^ (v[(p + 1) % n] << 2)) + ((v[(p + 1) % n] >> 3) ^ (v[(p + n - 1) % n] << 4)) ^ ((sum ^ v[(p + 1) % n]) + (k[(p ^ e) & 3] ^ v[(p + n - 1) % n]));
// 计算解密后的数据块
}
z = v[(n + n - 1) % n];
y = v[0] -= ((v[(n + n - 1) % n] >> 5) ^ (v[(1) % n] << 2)) + ((v[(1) % n] >> 3) ^ (v[(n + n - 1) % n] << 4)) ^ ((sum ^ v[(1) % n]) + (k[(0 ^ e) & 3] ^ v[(n + n - 1) % n]));
// 特殊处理第一个和最后一个数据块
sum -= delta; // 更新sum
}

上文代码中n代表待加密数据的长度,公式的含义是,对于给定的数据块长度,根据公式计算出加密轮数rounds,以便在加密过程中执行足够的轮数,达到较高的安全性。

DES

Data Encryption Standard是一种对称密钥加密算法,由IBM公司开发,并于1977年被美国国家标准局采纳为联邦信息处理标准。DES使用56位的密钥和64位的明文分组,通过16轮的Feistel网络进行加密。

DES使用的Feistel网络的结构分为很多个轮(DES为16轮),其中一轮的流程大致为:将输入的64位明文分为长度相等的左右两部分,右半部分直接保留,左半部分由本轮产生的子密钥和右半部分代入轮函数f所得的结果与原左半部分进行异或运算得到,然后将左右两部分交换,进行下一轮加密。其示意图可表示为:

本人用自己的语言总结其算法如下:

在加密时,首先进行一次IP置换,然后即进入Feistel网络,轮函数f的具体过程为先对左半部分进行E置换将其从32位扩展为48位,然后与轮秘钥按位异或,然后分为8组,每组6位,用这六位的首位和末位作为列索引,用剩下4位作为行索引,从对应的S盒中取出对应的值,然后进行P置换,将结果与右半部分进行异或运算,最后将结果与左半部分交换,进行下一轮加密。在最后一轮加密结束后,进行一次逆IP置换得到最终的密文。

而密钥生成过程则是64位密钥先经过PC1置换得到56位秘钥,然后进行循环左移+PC2置换得到48位秘钥,分为16组的子密钥用于16轮加密。

由此可得到完整的DES加密过程。

用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
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
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>

void main()
{ //声明变量
char MingWen[104]; //存放原始的明文
char target[8]; //将明文断成8个字符的一个分组
char InputKey[9]; //存放字符型的八位密钥
int text[64]; //存放一个分组转成二进制后的数据
int text_ip[64]; //存放第一次初始换位的结果
int L0[32], Li[32]; //将64位分成左右各32位进行迭代
int R0[32], Ri[32];
int RE0[48]; //存放右半部分经过E表扩展换位后的48位数据
int key[64]; //存放密钥的二进制形式
int keyPC1[56]; //存放密钥key经过PC1换位表后变成的56位二进制
int A[28]; //将keyPC1分成左右两部分,左部A,右部B,各28位,以便进行循环左移
int B[28];
int keyAB[56]; //将循环左移后两部分的结果合并起来
int K[16][48]; //存放16次循环左移产生的子密钥
int RK[48]; //存放RE和K异或运算后的结果
int RKS[8]; //存放经过查找8个S表后得到的8个十进制结果
int SP[32]; //将RKS表中的十进制数化成二进制
int RKSP[32]; //存放SP表经过P盒换位后的结果
int text_end[64]; //存放经过左右32位换位后的结果
int text_out[14][64]; //存放初始化向量和所有经过DES的分组的二进制
char init[9] = { "HTmadeit" }; //设置初始化向量为“HTmadeit”
int CBC[64];
int result[13][64];
int H[208];
char MiWen[208];
int C[832];
int M[13][8];

char choice;
int t;
int i, j;
int k, l, m, n;
int r[8], c[8];
int flag = 1;

int IP[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
};

int E[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 };

int PC1[56] = { //PC1换位表(64—>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 };

int move[16] = { //循环移位表
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };

int PC2[48] = { //PC2换位表(56—>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, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32 };

int S1[4][16] = { //S换位表
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
};
int S2[4][16] = {
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
};
int S3[4][16] = {
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
};
int S4[4][16] = {
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
};
int S5[4][16] = {
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
};
int S6[4][16] = {
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 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
};
int S7[4][16] = {
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 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
};
int S8[4][16] = {
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
};
int P[32] = { //P换位表
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
};

printf("HYs-des加密/解密\n\n");
while (flag)
{
printf("A加密,B解密,请选择:\n");
scanf("%c", &choice);

while (choice != 'A' && choice != 'B' && choice != 'a' && choice != 'b')
{
printf("对不起,您的输入不合法。请选择A或B,A表示加密,B表示解密。\n");
scanf("%c", &choice);
}
getchar();

//生成子密钥
printf("请输入8位密钥:\n");
gets_s(InputKey);
while (InputKey[7] == '\0' || InputKey[8] != '\0')
{
printf("您输入的密钥位数有误,请重新输入8位密钥:\n");
gets_s(InputKey);
}

for (i = 0; i < 8; i++) //将密钥转化成64位二进制数放到一维数组key中
{
int a[8] = { 0,0,0,0,0,0,0,0 };
m = InputKey[i];
for (j = 0; m != 0; j++)
{
a[j] = m % 2;
m = m / 2;
}
for (j = 0; j < 8; j++)
key[(i * 8) + j] = a[7 - j];
}

//for(i=0;i<64;i++)
//printf("%d,",key[i]);

for (i = 0; i < 56; i++) //通过PC1换位表变成56位密钥放在keyPC1中
keyPC1[i] = key[PC1[i] - 1];

for (i = 0; i < 28; i++) //分成A和B两部分,各28位
{
A[i] = keyPC1[i];
B[i] = keyPC1[i + 28];
}

for (t = 0; t < 16; t++)
{
if (move[t] == 1) //按照循环移位表将Ai和Bi分别左移move[t]位
{
n = A[0];
for (i = 0; i < 27; i++)
A[i] = A[i + 1];
A[27] = n;
n = B[0];
for (i = 0; i < 28; i++)
B[i] = B[i + 1];
B[27] = n;
}
else
{
n = A[0];
m = A[1];
for (i = 0; i < 26; i++)
A[i] = A[i + 2];
A[26] = n;
A[27] = m;
n = B[0];
m = B[1];
for (i = 0; i < 26; i++)
B[i] = B[i + 2];
B[26] = n;
B[27] = m;
}

for (i = 0; i < 28; i++) //将A和B合并成56位
{
keyAB[i] = A[i];
keyAB[i + 28] = B[i];
}

for (i = 0; i < 48; i++) //通过PC2换位表变成48位密钥
K[t][i] = keyAB[PC2[i] - 1];
}

//for(t=0;t<16;t++)
//for(i=0;i<48;i++)
// printf("%d,",K[t][i]);

for (i = 0; i < 8; i++) //将初始化向量转化成二进制数储存到数组text_out的第一行中
{
int a[8] = { 0,0,0,0,0,0,0,0 };
m = init[i];
for (j = 0; m != 0; j++)
{
a[j] = m % 2;
m = m / 2;
}
for (j = 0; j < 8; j++)
text_out[0][(i * 8) + j] = a[7 - j];
}


//加密程序

if (choice == 'A' || choice == 'a')
{
printf("请输入您想加密的内容:\n"); //输入明文
gets_s(MingWen);
while (MingWen[0] == '\0')
{
printf("对不起,明文不可为空,请您输入正确的明文。\n");
gets_s(MingWen);
}

//CBC模式下的加密
i = 0; //将明文每8个字符作为一个分组,共有n个分组
n = 0;
while (MingWen[i] != '\0')
{
n++;
i++;
}
k = n % 8;
n = (n - 1) / 8 + 1;

for (l = 0; l < n; l++)
{
if (l == (n - 1) && k != 0)
{
for (i = 0; i < k; i++) //将每个分组的8个字符放到数组target中,不够的用空格补充
target[i] = MingWen[i + (8 * l)];
for (i = k; i < 8; i++)
target[i] = ' ';
}
else
for (i = 0; i < 8; i++)
target[i] = MingWen[i + (8 * l)];

for (i = 0; i < 8; i++) //将得到的明文转化成二进制数储存到数组text中
{
int a[8] = { 0,0,0,0,0,0,0,0 };
m = target[i];
for (j = 0; m != 0; j++)
{
a[j] = m % 2;
m = m / 2;
}
for (j = 0; j < 8; j++)
text[(i * 8) + j] = a[7 - j];
}

//for(i=0;i<64;i++)
//printf("%d,",text[i]);
//printf("\n");

//for(i=0;i<64;i++)
//printf("%d,",text_out[l][i]);
//printf("\n");

for (i = 0; i < 64; i++) //CBC模式下前一分组的密文异或当前分组
text[i] = text_out[l][i] ^ text[i];

//for(i=0;i<64;i++)
//printf("%d,",text[i]);
//printf("\n");

//对每个text进行DES加密

for (i = 0; i < 64; i++) //进行初始换位
text_ip[i] = text[IP[i] - 1];

for (i = 0; i < 32; i++) //分成左右两部分,各32位
{
L0[i] = text_ip[i];
R0[i] = text_ip[i + 32];
}

//for(i=0;i<32;i++)
// printf("%d,",L0[i]);
//for(i=0;i<32;i++)
// printf("%d,",R0[i]);


//十六次迭代

for (t = 0; t < 16; t++)
{
for (i = 0; i < 48; i++) //将右半部分通过扩展换位表E从32位扩展成48位
RE0[i] = R0[E[i] - 1];

//printf("RE0\n");
//for(i=0;i<48;i++)
//printf("%d,",RE0[i]);

for (i = 0; i < 48; i++) //RE与K异或运算
RK[i] = RE0[i] ^ K[t][i];


//printf("\n");
//for(i=0;i<48;i++)
//printf("%d,",RK[i]);

for (i = 0; i < 8; i++) //将R和K异或运算的结果通过S位移表
{
r[i] = RK[(i * 6) + 0] * 2 + RK[(i * 6) + 5];
c[i] = RK[(i * 6) + 1] * 8 + RK[(i * 6) + 2] * 4 + RK[(i * 6) + 3] * 2 + RK[(i * 6) + 4];
}
RKS[0] = S1[r[0]][c[0]];
RKS[1] = S2[r[1]][c[1]];
RKS[2] = S3[r[2]][c[2]];
RKS[3] = S4[r[3]][c[3]];
RKS[4] = S5[r[4]][c[4]];
RKS[5] = S6[r[5]][c[5]];
RKS[6] = S7[r[6]][c[6]];
RKS[7] = S8[r[7]][c[7]];

for (i = 0; i < 8; i++) //把结果转成32位二进制储存在数组SP中
{
int b[4] = { 0,0,0,0 };
m = RKS[i];
for (j = 3; m != 0; j--)
{
b[j] = m % 2;
m = m / 2;
}
for (j = 0; j < 4; j++)
SP[j + (i * 4)] = b[j];
}

for (i = 0; i < 32; i++) //将二进制结果再经过一个P盒换位
RKSP[i] = SP[P[i] - 1];

for (i = 0; i < 32; i++) //与前一次的左部异或运算,得到本次迭代的右部
Ri[i] = L0[i] ^ RKSP[i];

for (i = 0; i < 32; i++)
{
L0[i] = R0[i];
R0[i] = Ri[i];
}
}

//一个左右32位交换

for (i = 0; i < 32; i++)
Li[i] = R0[i];
for (i = 0; i < 32; i++)
R0[i] = L0[i];
for (i = 0; i < 32; i++)
L0[i] = Li[i];


//初始换位的逆过程

for (i = 0; i < 32; i++) //把左右两部分合起来存到text_end中
text_end[i] = L0[i];
for (i = 32; i < 64; i++)
text_end[i] = R0[i - 32];

for (i = 0; i < 64; i++) //进行初始换位的逆过程
text_out[l + 1][IP[i] - 1] = text_end[i];

for (i = 0; i < 64; i++)
result[l][i] = text_out[l + 1][i];

//for(i=0;i<64;i++)
//printf("%d,",result[l][i]);
//printf("\n");
}

for (j = 0; j < n; j++) //把result中的二进制密文转成十进制存到数组H中
for (i = 0; i < 16; i++)
H[i + (j * 16)] = result[j][0 + (i * 4)] * 8 + result[j][1 + (i * 4)] * 4 + result[j][2 + (i * 4)] * 2 + result[j][3 + (i * 4)];

//for(i=0;i<l*16;i++)
//printf("%d,",H[i]);

for (i = 0; i < n * 16; i++)
{
if (H[i] < 10)
MiWen[i] = H[i] + 48;
else if (H[i] == 10)
MiWen[i] = 'A';
else if (H[i] == 11)
MiWen[i] = 'B';
else if (H[i] == 12)
MiWen[i] = 'C';
else if (H[i] == 13)
MiWen[i] = 'D';
else if (H[i] == 14)
MiWen[i] = 'E';
else if (H[i] == 15)
MiWen[i] = 'F';
//else MiWen[i]='\0';
}
for (i = l * 16; i < 208; i++)
MiWen[i] = '\0';//注意数组越界

printf("您的明文经过DES加密后的密文是:\n");
printf("%s\n", MiWen);
printf("\n\n");
}


//解密程序
else if (choice == 'B' || choice == 'b')
{
printf("请输入密文内容:\n");
gets_s(MiWen);

for (i = 0; i < 208; i++)
H[i] = 0;

for (i = 0; MiWen[i] != '\0'; i++) //将十六进制密文转化成十进制存放在数组H中
{
if (MiWen[i] >= '0' && MiWen[i] <= '9')
H[i] = MiWen[i] - '0';
else if (MiWen[i] >= 'A' && MiWen[i] <= 'F')
H[i] = MiWen[i] - 'A' + 10;
else if (MiWen[i] >= 'a' && MiWen[i] <= 'f')
H[i] = MiWen[i] - 'a' + 10;
else
{
printf("注意:请输入用十六进制表示的密文内容:\n");
gets_s(MiWen);
i = 0;
}
}
n = i; //密文中共有n个字符
if (n % 16 != 0)
{
printf("对不起,您输入的密文不正确,请确认密文的内容,密文的字符数应是16的倍数。\n");
printf("请输入密文内容:\n");
gets_s(MiWen);

for (i = 0; i < 208; i++)
H[i] = 0;
for (i = 0; MiWen[i] != '\0'; i++) //将十六进制密文转化成十进制存放在数组H中
{
if (MiWen[i] >= '0' && MiWen[i] <= '9')
H[i] = MiWen[i] - '0';
else if (MiWen[i] >= 'A' && MiWen[i] <= 'F')
H[i] = MiWen[i] - 'A' + 10;
else if (MiWen[i] >= 'a' && MiWen[i] <= 'f')
H[i] = MiWen[i] - 'a' + 10;
}
}

for (i = 0; i < n; i++) //将十进制密文转化成二进制存放在数组C中
{
int he[4] = { 0,0,0,0 };
for (j = 3; H[i] != 0; j--)
{
he[j] = H[i] % 2;
H[i] = H[i] / 2;
}
for (j = 0; j < 4; j++)
C[j + (i * 4)] = he[j];
}

//for(i=0;i<130;i++)
// printf("%d,",C[i]);
//printf("\n");

k = n / 16;
for (l = 0; l < k; l++)
{
for (i = 0; i < 64; i++) //将每个分组对应的64位二进制密文放到text_out中
text_out[l + 1][i] = C[i + (l * 64)];

//for(i=0;i<64;i++)
// printf("%d,",text_out[l][i]);
//printf("\n");

//对每个text进行DES解密

for (i = 0; i < 64; i++) //进行初始换位
text_ip[i] = text_out[l + 1][IP[i] - 1];

//for(i=0;i<64;i++)
//printf("%d,",text_ip[i]);
//printf("\n");

for (i = 0; i < 32; i++) //分成左右两部分,各32位
{
L0[i] = text_ip[i];
R0[i] = text_ip[i + 32];
}
//for(i=0;i<32;i++)
// printf("%d,",L0[i]);
//for(i=0;i<32;i++)
// printf("%d,",R0[i]);


//十六次迭代

for (t = 0; t < 16; t++)
{
for (i = 0; i < 48; i++) //将右半部分通过扩展换位表E从32位扩展成48位
RE0[i] = R0[E[i] - 1];

//printf("RE0\n");
//for(i=0;i<48;i++)
//printf("%d,",RE0[i]);

for (i = 0; i < 48; i++) //RE与K异或运算
RK[i] = RE0[i] ^ K[15 - t][i];

//printf("\n");
//for(i=0;i<48;i++)
//printf("%d,",RK[i]);

for (i = 0; i < 8; i++) //将R和K异或运算的结果通过S位移表
{
r[i] = RK[(i * 6) + 0] * 2 + RK[(i * 6) + 5];
c[i] = RK[(i * 6) + 1] * 8 + RK[(i * 6) + 2] * 4 + RK[(i * 6) + 3] * 2 + RK[(i * 6) + 4];
}

RKS[0] = S1[r[0]][c[0]];
RKS[1] = S2[r[1]][c[1]];
RKS[2] = S3[r[2]][c[2]];
RKS[3] = S4[r[3]][c[3]];
RKS[4] = S5[r[4]][c[4]];
RKS[5] = S6[r[5]][c[5]];
RKS[6] = S7[r[6]][c[6]];
RKS[7] = S8[r[7]][c[7]];

for (i = 0; i < 8; i++) //把结果转成32位二进制储存在数组SP中
{
int b[4] = { 0,0,0,0 };
m = RKS[i];
for (j = 3; m != 0; j--)
{
b[j] = m % 2;
m = m / 2;
}
for (j = 0; j < 4; j++)
SP[j + (i * 4)] = b[j];
}

for (i = 0; i < 32; i++) //将二进制结果再经过一个P盒换位
RKSP[i] = SP[P[i] - 1];

for (i = 0; i < 32; i++) //与前一次的左部异或运算,得到本次迭代的右部
Ri[i] = L0[i] ^ RKSP[i];

for (i = 0; i < 32; i++)
{
L0[i] = R0[i];
R0[i] = Ri[i];
}
}

//一个左右32位交换

for (i = 0; i < 32; i++)
Li[i] = R0[i];
for (i = 0; i < 32; i++)
R0[i] = L0[i];
for (i = 0; i < 32; i++)
L0[i] = Li[i];

//初始换位的逆过程

for (i = 0; i < 32; i++) //把左右两部分合起来存到text_end中
text_end[i] = L0[i];
for (i = 32; i < 64; i++)
text_end[i] = R0[i - 32];

for (i = 0; i < 64; i++) //进行初始换位的逆过程
text[IP[i] - 1] = text_end[i];


//CBC模式下的解密

for (i = 0; i < 64; i++) //前一分组的密文异或当前分组所得明文的二进制放到result中
result[l][i] = text_out[l][i] ^ text[i];

}

for (i = 0; i < (n / 16); i++) //将二进制转成十进制
for (j = 0; j < 8; j++)
M[i][j] = result[i][(j * 8) + 0] * 128 + result[i][(j * 8) + 1] * 64 + result[i][(j * 8) + 2] * 32 + result[i][(j * 8) + 3] * 16 + result[i][(j * 8) + 4] * 8 + result[i][(j * 8) + 5] * 4 + result[i][(j * 8) + 6] * 2 + result[i][(j * 8) + 7];

printf("您的密文经过DES解密后的明文是:\n");
for (i = 0; i < (n / 16); i++)
for (j = 0; j < 8; j++)
printf("%c", M[i][j]);
printf("\n\n\n");
}
flag = 0;
printf("是否继续?\n");
printf("Y继续,N退出,请选择:\n");
scanf("%c", &choice);

while (choice != 'Y' && choice != 'N' && choice != 'y' && choice != 'n')
{
printf("对不起,您的输入不合法。请选择Y或N,Y表示继续使用本程序,N表示退出。\n");
scanf("%c", &choice);
}
getchar();
if (choice == 'Y' || choice == 'y')
flag = 1;
}
}

用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
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
import re

PC_1 = [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
]

# 选择压缩表2(PC_2) 56->48
PC_2 = [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
]

# 移位次数表
shift_num = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]


def pc_1_change(bin_key):
"""初始置换

64位的种子密钥经过PC_1置换后,生成56位的密钥
"""
return [bin_key[i - 1] for i in PC_1] # 列表形式


def shift_left(bin_key, num):
"""实现C和D的循环左移"""
return bin_key[num:] + bin_key[:num]


def pc_2_change(bin_key):
"""选择压缩

56位的密钥经过PC_2压缩,生成48位子密钥
"""
return ''.join([bin_key[i - 1] for i in PC_2]) # 列表转字符串


def get_subkey_list(bin_key):
"""生成16轮的加解子密钥"""
subkey_list = [] # 存储16轮子密钥
# 1. 初始置换 64->58
temp = pc_1_change(bin_key)
# 2. 循环左移
for i in shift_num:
temp[:28] = shift_left(temp[:28], i) # C部分循环左移
temp[28:] = shift_left(temp[28:], i) # D部分循环左移
subkey_list.append(pc_2_change(temp)) # 生成子密钥
return subkey_list


# ========================================
# 二、DES加解密实现
# ========================================

# 初始置换表IP 64->64
IP = [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 64->64
_IP = [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 32->48
E = [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
]

# S盒 48->32
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, 9, 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, 9, 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
]
S = [S1, S2, S3, S4, S5, S6, S7, S8]

# P盒
P = [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
]


# encrypt
def ip_change(bin_text):
"""初始置换"""
return [bin_text[i - 1] for i in IP]


def s_box(bin_result):
"""S盒替换"""
int_result = []
result = ''
for i in range(8):
# 二进制行号
bin_row = bin_result[i][0] + bin_result[i][5]
# 二进制列号
bin_col = ''.join(bin_result[i][j] for j in range(1, 5))
# 获取对应的十进制数
int_result.append(S[i][16 * int(bin_row, base=2) + int(bin_col, base=2)])
# 十进制转成二进制
result += bin(int_result[-1])[2:].zfill(4)
return result


def p_box(result):
"""P盒置换"""
return ''.join(result[i - 1] for i in P)


def f(R, bin_key):
"""轮函数f()"""
# 1.将R由32位扩展成48位
R_ext = [R[i - 1] for i in E]
# 2.与子密钥进行逐位异或
bin_temp = [str(int(r) ^ int(k)) for r, k in zip(R_ext, bin_key)]
# 6个字符为一组,共8组
bin_result = [''.join(bin_temp[i:i + 6]) for i in range(0, len(bin_temp), 6)]
# 3.S盒替换 48->32
result = s_box(bin_result)
# 4.P盒置换 32->32
return p_box(result)


def _ip_change(bin_text):
"""进行IP-1逆置换"""
return ''.join(bin_text[i - 1] for i in _IP)


def des_cipher(bin_text, bin_key, reverse_keys=False):
"""通用DES加密解密函数"""
# 1. 初始置换IP
bin_text = ip_change(bin_text)
# 2. 分成左右两部分L、R
L, R = bin_text[:32], bin_text[32:]
# 3. 获得16轮子密钥
subkey_list = get_subkey_list(bin_key)
if reverse_keys:
subkey_list = subkey_list[::-1] # 解密时反转子密钥列表
# 4. 进行16轮迭代
for i in subkey_list:
R_temp = R
# 轮函数f()结果和L进行异或
R = ''.join(str(int(r) ^ int(l)) for r, l in zip(f(R, i), L))
L = R_temp
# 5. 进行IP-1逆置换 64->64
return _ip_change(R + L) # 输出二进制字符串


# 使用示例
def str2bin(text):
"""字符串转二进制字符串"""
return ''.join(bin(byte)[2:].zfill(8) for byte in text.encode())


def bin2str(bin_text):
"""二进制字符串转字符串"""
# 1.将二进制字符串按8位分割,并转换为字节数组
byte_array = bytearray(int(i, 2) for i in re.findall(r'.{8}', bin_text) if int(i, 2) != 0)
# 2.将字节序列解码为字符串
return byte_array.decode()


def is_valid_key(key):
"""检查密钥是否有效 64bit"""
return len(key.encode()) == 8


def des_encrypt(plaintext, key):
"""DES加密"""
# 1.明文转成二进制字符串, 0填充至64的倍数
bin_plaintext = str2bin(plaintext)
padding_len = (64 - (len(bin_plaintext) % 64)) % 64
bin_padding_plaintext = bin_plaintext + '0' * padding_len
# 2.进行64位分组加密
bin_group_64 = re.findall(r'.{64}', bin_padding_plaintext)
bin_ciphertext = ''
for g in bin_group_64:
bin_ciphertext += des_cipher(g, str2bin(key))
# 3.密文转为16进制输出
bin_group_4 = re.findall(r'.{4}', bin_ciphertext)
hex_ciphertext = ''
for g in bin_group_4:
hex_ciphertext += format(int(g, 2), 'x')
return hex_ciphertext


def des_decrypt(hex_ciphertext, key):
"""DES解密"""
# 1.16进制密文转为2进制字符串
bin_ciphertext = ''.join(bin(int(h, 16))[2:].zfill(4) for h in hex_ciphertext)
# 2.进行64位分组解密
bin_group_64 = re.findall(r'.{64}', bin_ciphertext)
bin_deciphertext = ''
for g in bin_group_64:
bin_deciphertext += des_cipher(g, str2bin(key), reverse_keys=True)
# 3.将解密密文转为字符串输出
return bin2str(bin_deciphertext)


def des_run():
"""DES启动界面"""
flag = True
while flag:
print('=' * 3, "DES加密解密", '=' * 3)
print('[1]加密')
print('[2]解密')
print('[0]退出')
choice = input('请输入你的选择:')
match choice:
case '0':
flag = False
case '1':
plaintext = input('请输入明文:')
key = input('请输入密钥(64bit):')
if not is_valid_key(key):
print('密钥长度错误')
continue
ciphertext = des_encrypt(plaintext, key)
print(f'密文:{ciphertext}')
case '2':
ciphertext = input('请输入密文:')
key = input('请输入密钥(64bit):')
if not is_valid_key(key):
print('密钥长度错误')
continue
print(f'解密:{des_decrypt(ciphertext, key)}')
case _:
print('输入错误')
print('=' * 15)


if __name__ == '__main__':
des_run()

由于DES属于OpenSSL的加密算法,故也可使用OpenSSL的库,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
#include <stdio.h>
#include <openssl/des.h>
int main(int argc, char** argv){
DES_cblock key;
//随机密钥
DES_random_key(&key);
DES_key_schedule schedule;
//转换成schedule
DES_set_key_checked(&key, &schedule);
const_DES_cblock input = "abc";
DES_cblock output;
printf("cleartext: %s\n", input);
//加密
DES_ecb_encrypt(&input, &output, &schedule, DES_ENCRYPT);
printf("Encrypted!\nciphertext: ");
int i;
for (i = 0; i < sizeof(input); i++)
printf("%02x", output[i]);
printf("\n");
//解密
DES_ecb_encrypt(&output, &input, &schedule, DES_DECRYPT);
printf("Decrypted!\ncleartext:%s\n", input);
return 0;
}

AES

AES(Advanced Encryption Standard)是新一代的加密标准,其分组长度为128位,密钥长度常为128位。AES的SPN(Substitution-Permutation Network,代换-置换网络) 结构是其加密过程的核心设计思想。SPN 是一种对称密钥分组密码结构,通过多轮重复的 代换(Substitution) 和 置换(Permutation) 操作,结合密钥扩展机制,实现高效的混淆(Confusion)和扩散(Diffusion),从而确保安全性。

AES加密算法的SPN结构有四步操作:逐字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。

  1. 逐字节替代SubBytes:

    AES 加密中的核心非线性操作步骤,通过S盒对状态矩阵的每个字节进行替换,实现混淆。代码中,SubBytes通过查表高效实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// S 盒定义(部分)
unsigned char S[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
// ... 其余 240 个字节
};

// SubBytes 函数
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;
}
  1. 行移位ShiftRows:

    行移位(ShiftRows)​ 是 AES 加密中的关键步骤,属于 ​置换(Permutation)​ 操作,负责在状态矩阵的行方向上扩散字节,增强算法的 ​扩散性(Diffusion)​,使得单个字节的变化能在多轮迭代后扩散到整个密文分组。其代码实现为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int shiftRows(uint8_t (*state)[4]) {
uint32_t block[4] = {0};

// 将每行 4 字节转换为 32 位整数
for (int i = 0; i < 4; ++i) {
LOAD32H(block[i], state[i]);
}

// 按行循环左移不同偏移量
block[1] = ROF32(block[1], 8); // 行1左移1字节
block[2] = ROF32(block[2], 16); // 行2左移2字节
block[3] = ROF32(block[3], 24); // 行3左移3字节

// 将32位整数转回字节数组
for (int i = 0; i < 4; ++i) {
STORE32H(block[i], state[i]);
}

return 0;
}
  1. 列混淆MixColumns:

    是 AES 加密中的核心线性变换步骤,属于​扩散(Diffusion)操作,负责在状态矩阵的列方向上混合字节,使得单个字节的变化扩散到整个列。其通过​矩阵乘法对每一列进行变换,代码实现为:

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 GMul(uint8_t a, uint8_t b) {
uint8_t p = 0;
for (int i = 0; i < 8; ++i) {
if (b & 0x01) {
p ^= a;
}
int hiBitSet = (a & 0x80);
a <<= 1;
if (hiBitSet) {
a ^= 0x1B; // 异或不可约多项式 0x11B(去最高位)
}
b >>= 1;
}
return p;
}

// 列混淆(加密)
int mixColumns(uint8_t (*state)[4]) {
uint8_t tmp[4][4];
uint8_t M[4][4] = {{0x02, 0x03, 0x01, 0x01},
{0x01, 0x02, 0x03, 0x01},
{0x01, 0x01, 0x02, 0x03},
{0x03, 0x01, 0x01, 0x02}};

// 复制原始状态到临时矩阵
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]);
}
}
return 0;
}
  1. 轮密钥异或AddRoundKey:

    是 AES 加密和解密中的关键步骤,在每轮中通过 ​异或(XOR)操作 将当前状态矩阵与轮密钥(Round Key)结合,确保密钥信息融入每一轮的处理过程。它是 AES 中唯一直接使用密钥的步骤,承担了密钥混淆的核心作用。在代码中,轮密钥通常以 ​32 位字(uint32_t)​ 存储,需转换为 4×4 字节矩阵后再异或:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int addRoundKey(uint8_t (*state)[4], const uint32_t *roundKey) {
uint8_t keyBytes[4][4]; // 将轮密钥从uint32_t[4]转换为4x4字节矩阵

// 提取轮密钥的每个字节
for (int col = 0; col < 4; col++) {
keyBytes[0][col] = (uint8_t)(roundKey[col] >> 24); // 高位字节
keyBytes[1][col] = (uint8_t)(roundKey[col] >> 16);
keyBytes[2][col] = (uint8_t)(roundKey[col] >> 8);
keyBytes[3][col] = (uint8_t)(roundKey[col] & 0xFF); // 低位字节
}

// 逐字节异或
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
state[row][col] ^= keyBytes[row][col];
}
}
return 0;
}

而AES的密钥生成过程则是将初始密钥(128/192/256位)扩展为多轮加密所需的​轮密钥(Round Keys)​ 的过程。以 AES-128(128位密钥,10轮加密)为例,密钥扩展生成11个轮密钥​(每轮使用一个)。

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 KeyExpansion(const uint8_t *key, uint32_t *w) {
// 加载初始密钥到w[0]-w[3]
for (int i = 0; i < 4; i++) {
w[i] = ((uint32_t)key[4*i] << 24) |
((uint32_t)key[4*i+1] << 16) |
((uint32_t)key[4*i+2] << 8) |
(uint32_t)key[4*i+3];
}

// 生成后续字(w[4]-w[43])
for (int i = 4; i < 44; i++) {
uint32_t temp = w[i-1];
if (i % 4 == 0) {
temp = SubWord(RotWord(temp)) ^ Rcon[i/4];
}
w[i] = w[i-4] ^ temp;
}
}

// 循环左移1字节
uint32_t RotWord(uint32_t x) {
return (x << 8) | (x >> 24);
}

// S盒替换
uint32_t SubWord(uint32_t x) {
return (S[(x >> 24) & 0xFF] << 24) |
(S[(x >> 16) & 0xFF] << 16) |
(S[(x >> 8) & 0xFF] << 8) |
S[x & 0xFF];
}

完整的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
#include <stdio.h>
#include <stdlib.h>

void she(int *p)//S盒
{
int i;
int 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
};
for (i = 0; i < 16; i++)*(p + i) = s[*(p + i)];
}

void gshe(int *p)//g-S盒
{
int i;
int 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
};
for (i = 0; i < 4; i++)*(p + i) = s[*(p + i)];
}

void left(int *p)//行移位
{
int i, j;
int b[4][4];
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
b[j][i] = *(p + j * 4 + (i + j) % 4);
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
*(p + i + j * 4) = b[j][i];
}

void addbyte16(int *p, int *q)//4*4矩阵字节加法,结果保存到左加数,也为轮密钥加
{
int i, j;
for (j = 0; j < 4; j++)for (i = 0; i < 4; i++)
*(p + j * 4 + i) = *(p + j * 4 + i) ^ *(q + j * 4 + i);
}

void addbyte4(int *p, int *q)//1*4矩阵字节加法,结果保存到左加数
{
int i;
for (i = 0; i < 4; i++)
*(p + i) = *(p + i) ^ *(q + i);
}

int mul(int b,int a)//有限域上的乘法,只定义了01、02、03与其他数相乘
{
if (b == 0x02)
{
if (a < 0x80)a = (a * 0x02);
else a = ((a % 0x80) * 0x02) ^ 0x1b;
}
if (b == 0x03)
{
if (a < 0x80)b = (a * 0x02);
else b = ((a % 0x80) * 0x02) ^ 0x1b;
a = a^b;
}
return a;
}

void column(int *p, int *q)//列混淆
{
int i, j;
int a[4][4];
for (j = 0; j < 4; j++)for (i = 0; i < 4; i++)
{
a[j][i] = mul(*(q + j * 4 + 0), *(p + 0 * 4 + i)) ^ mul(*(q + j * 4 + 1), *(p + 1 * 4 + i)) ^
mul(*(q + j * 4 + 2), *(p + 2 * 4 + i)) ^ mul(*(q + j * 4 + 3), *(p + 3 * 4 + i));
}
for (j = 0; j < 4; j++)for (i = 0; i < 4; i++)*(p + j * 4 + i) = a[j][i];
}

void g(int *p,int j)//g函数
{
int rc[10] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36 };
int i,a = *p;
for (i = 0; i < 3; i++)*(p+i) = *(p + i + 1);*(p + 3) = a;
gshe(p);
*p = *p^rc[j];
}

void keyextension(int *p, int j)//密钥扩展
{
int a[4], b[4], c[4], d[4], d1[4];
int i, *q1 = &a[0], *q2 = &b[0], *q3 = &c[0], *q4 = &d[0], *q5 = &d1[0];
for (i = 0; i < 4; i++)a[i] = *(p + i * 4 + 0);
for (i = 0; i < 4; i++)b[i] = *(p + i * 4 + 1);
for (i = 0; i < 4; i++)c[i] = *(p + i * 4 + 2);
for (i = 0; i < 4; i++)d[i] = *(p + i * 4 + 3);
for (i = 0; i < 4; i++)d1[i] = *(p + i * 4 + 3);
g(q5, j);
addbyte4(q1, q5);
addbyte4(q2, q1);
addbyte4(q3, q2);
addbyte4(q4, q3);
for (i = 0; i < 4; i++)*(p + i * 4 + 0) = a[i];
for (i = 0; i < 4; i++)*(p + i * 4 + 1) = b[i];
for (i = 0; i < 4; i++)*(p + i * 4 + 2) = c[i];
for (i = 0; i < 4; i++)*(p + i * 4 + 3) = d[i];
}

int main(int argc, char *argv[]) {
int i, j;
int u[4][4],key[4][4];

//输入明文
printf("input plaintext:\n");
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
scanf("%x",&u[j][i]);

//输入密钥
printf("input key:\n");
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
scanf("%x",&key[j][i]);

//列混淆常数矩阵
int u1[4][4] =
{
0x02,0x03,0x01,0x01,
0x01,0x02,0x03,0x01,
0x01,0x01,0x02,0x03,
0x03,0x01,0x01,0x02
};
int *p = &u[0][0];
int *q = &u1[0][0];
int *k = &key[0][0];

//第一轮前
addbyte16(p,k);

//第一轮到第九轮(0~8)
for(i=0;i<9;i++)
{
she(p);
left(p);
column(p,q);
keyextension(k,i);
addbyte16(p,k);
}

//第十轮
she(p);
left(p);
keyextension(k,9);
addbyte16(p,k);

//密文输出
printf("ciphertext:\n");
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)printf("%x ", u[i][j]);
printf("\n");
}

system("pause");
return 0;
}

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
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
class AES:

MIX_C = [[0x2, 0x3, 0x1, 0x1], [0x1, 0x2, 0x3, 0x1], [0x1, 0x1, 0x2, 0x3], [0x3, 0x1, 0x1, 0x2]]
I_MIXC = [[0xe, 0xb, 0xd, 0x9], [0x9, 0xe, 0xb, 0xd], [0xd, 0x9, 0xe, 0xb], [0xb, 0xd, 0x9, 0xe]]
RCon = [0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000]

S_BOX = [[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]]

I_SBOX = [[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]]

def SubBytes(self, State):
# 字节替换
return [self.S_BOX[i][j] for i, j in
[(_ >> 4, _ & 0xF) for _ in State]]

def SubBytes_Inv(self, State):
# 字节逆替换
return [self.I_SBOX[i][j] for i, j in
[(_ >> 4, _ & 0xF) for _ in State]]

def ShiftRows(self, S):
# 行移位
return [S[ 0], S[ 5], S[10], S[15],
S[ 4], S[ 9], S[14], S[ 3],
S[ 8], S[13], S[ 2], S[ 7],
S[12], S[ 1], S[ 6], S[11]]

def ShiftRows_Inv(self, S):
# 逆行移位
return [S[ 0], S[13], S[10], S[ 7],
S[ 4], S[ 1], S[14], S[11],
S[ 8], S[ 5], S[ 2], S[15],
S[12], S[ 9], S[ 6], S[ 3]]

def MixColumns(self, State):
# 列混合
return self.Matrix_Mul(self.MIX_C, State)

def MixColumns_Inv(self, State):
# 逆列混合
return self.Matrix_Mul(self.I_MIXC, State)

def RotWord(self, _4byte_block):
# 用于生成轮密钥的字移位
return ((_4byte_block & 0xffffff) << 8) + (_4byte_block >> 24)

def SubWord(self, _4byte_block):
# 用于生成密钥的字节替换
result = 0
for position in range(4):
i = _4byte_block >> position * 8 + 4 & 0xf
j = _4byte_block >> position * 8 & 0xf
result ^= self.S_BOX[i][j] << position * 8
return result

def mod(self, poly, mod = 0b100011011):
# poly模多项式mod
while poly.bit_length() > 8:
poly ^= mod << poly.bit_length() - 9
return poly

def mul(self, poly1, poly2):
# 多项式相乘
result = 0
for index in range(poly2.bit_length()):
if poly2 & 1 << index:
result ^= poly1 << index
return result

def Matrix_Mul(self, M1, M2): # M1 = MIX_C M2 = State
# 用于列混合的矩阵相乘
M = [0] * 16
for row in range(4):
for col in range(4):
for Round in range(4):
M[row + col*4] ^= self.mul(M1[row][Round], M2[Round+col*4])
M[row + col*4] = self.mod(M[row + col*4])
return M

def round_key_generator(self, _16bytes_key):
# 轮密钥产生
w = [_16bytes_key >> 96,
_16bytes_key >> 64 & 0xFFFFFFFF,
_16bytes_key >> 32 & 0xFFFFFFFF,
_16bytes_key & 0xFFFFFFFF] + [0]*40
for i in range(4, 44):
temp = w[i-1]
if not i % 4:
temp = self.SubWord(self.RotWord(temp)) ^ self.RCon[i//4-1]
w[i] = w[i-4] ^ temp
return [self.num_2_16bytes(
sum([w[4 * i] << 96, w[4*i+1] << 64,
w[4*i+2] << 32, w[4*i+3]])
) for i in range(11)]

def AddRoundKey(self, State, RoundKeys, index):
# 异或轮密钥
return self._16bytes_xor(State, RoundKeys[index])

def _16bytes_xor(self, _16bytes_1, _16bytes_2):
return [_16bytes_1[i] ^ _16bytes_2[i] for i in range(16)]

def _16bytes2num(cls, _16bytes):
# 16字节转数字
return int.from_bytes(_16bytes, byteorder = 'big')

def num_2_16bytes(cls, num):
# 数字转16字节
return num.to_bytes(16, byteorder = 'big')

def aes_encrypt(self, plaintext_list, RoundKeys):
State = plaintext_list
State = self.AddRoundKey(State, RoundKeys, 0)
for Round in range(1, 10):
State = self.SubBytes(State)
State = self.ShiftRows(State)
State = self.MixColumns(State)
State = self.AddRoundKey(State, RoundKeys, Round)
State = self.SubBytes(State)
State = self.ShiftRows(State)
State = self.AddRoundKey(State, RoundKeys, 10)
return State

def aes_decrypt(self, ciphertext_list, RoundKeys):
State = ciphertext_list
State = self.AddRoundKey(State, RoundKeys, 10)
for Round in range(1, 10):
State = self.ShiftRows_Inv(State)
State = self.SubBytes_Inv(State)
State = self.AddRoundKey(State, RoundKeys, 10-Round)
State = self.MixColumns_Inv(State)
State = self.ShiftRows_Inv(State)
State = self.SubBytes_Inv(State)
State = self.AddRoundKey(State, RoundKeys, 0)
return State

if __name__ == '__main__':

aes = AES()
key = 0x000102030405060708090a0b0c0d0e0f
RoundKeys = aes.round_key_generator(key)

# 加密
plaintext = 0x00112233445566778899aabbccddeeff
# 0x00112233445566778899aabbccddeeff -> b'\x00\x11"3DUfw\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
plaintext = aes.num_2_16bytes(plaintext)
ciphertext = aes.aes_encrypt(plaintext, RoundKeys)
print('ciphertext = ' + hex(aes._16bytes2num(ciphertext)))

# 解密
ciphertext = 0x69c4e0d86a7b0430d8cdb78070b4c55a
ciphertext = aes.num_2_16bytes(ciphertext)
plaintext = aes.aes_decrypt(ciphertext, RoundKeys)
print('plaintext = ' + hex(aes._16bytes2num(plaintext)))

若要使用Python的第三方库,可简化为:

1
2
3
4
5
6
7
8
9
10
from Crypto.Cipher import AES

password = b'1234567812345678' #秘钥,b就是表示为bytes类型
text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型
aes = AES.new(password,AES.MODE_ECB) #创建一个aes对象
# AES.MODE_ECB 表示模式是ECB模式
en_text = aes.encrypt(text) #加密明文
print("密文:",en_text) #加密明文,bytes类型
den_text = aes.decrypt(en_text) # 解密密文
print("明文:",den_text)

这样使用要先安装对应的库

1
2
3
pip uninstall crypto
pip uninstall pycryptodome
pip install pycryptodome

SM4

SM4是中国自主研发的分组密码算法,由国家密码管理局于2006年发布,2012年成为国家标准(GB/T 32907-2016),其分组长度为128位,密钥长度为128位,加密算法为32轮Feistel结构,解密算法为32轮Feistel结构,加密和解密使用相同的轮函数。

  1. 秘钥扩展

    其分为以下几个步骤:

    1. 主密钥分割:将128位主密钥分成4个32位字 MK0, MK1, MK2, MK3
    2. 初始异或:与固定参数 FK[0..3] 异或,得到 K0..K3
    3. ​轮密钥生成:过32轮迭代生成轮密钥 rk[0..31],每轮使用 CK[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
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
#include <stdint.h>

// 固定参数 FK (系统参数)
static const uint32_t FK[4] = {
0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC
};

// 固定参数 CK (密钥扩展常量,需按标准填充完整)
static const uint32_t CK[32] = {
0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269,
0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249,
0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229,
0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209,
0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
};

// S盒定义(需按标准填充完整256个值)
static const uint8_t SBOX[256] = {
0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
// ... 其他240个值需补充
};

// 循环左移
static uint32_t rotl(uint32_t x, int n) {
return (x << n) | (x >> (32 - n));
}

// 密钥扩展中的T'变换
static uint32_t T_prime(uint32_t x) {
// S盒替换
uint8_t a[4] = {
SBOX[(x >> 24) & 0xFF],
SBOX[(x >> 16) & 0xFF],
SBOX[(x >> 8) & 0xFF],
SBOX[x & 0xFF]
};
x = ((uint32_t)a[0] << 24) | ((uint32_t)a[1] << 16) | ((uint32_t)a[2] << 8) | a[3];
// 线性变换L'
return x ^ rotl(x, 13) ^ rotl(x, 23);
}

// 密钥扩展函数
void sm4_key_schedule(const uint8_t key[16], uint32_t rk[32]) {
uint32_t MK[4], K[36];

// 1. 将主密钥分为4个32位字
for (int i = 0; i < 4; i++) {
MK[i] = ((uint32_t)key[4*i] << 24) |
((uint32_t)key[4*i+1] << 16) |
((uint32_t)key[4*i+2] << 8) |
key[4*i+3];
}

// 2. 初始异或FK
for (int i = 0; i < 4; i++) {
K[i] = MK[i] ^ FK[i];
}

// 3. 生成32个轮密钥
for (int i = 0; i < 32; i++) {
uint32_t temp = K[i+1] ^ K[i+2] ^ K[i+3] ^ CK[i];
temp = T_prime(temp); // 应用T'变换
K[i+4] = K[i] ^ temp; // 更新K[i+4]
rk[i] = K[i+4]; // 保存轮密钥
}
}
  1. SM4的加密过程SM4加密采用32轮非平衡Feistel结构,每轮使用一个轮密钥
    1. 明文分组:将128位明文分为4个32位字 X0, X1, X2, X3
    2. ​32轮迭代:每轮计算 X[i+4] = X[i] ^ T(X[i+1] ^ X[i+2] ^ X[i+3] ^ rk[i])
    3. 反序输出:最终结果反序组合为密文 X35, X34, X33, X32
      代码实现如下
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
// 加密中的T变换
static uint32_t T(uint32_t x) {
// S盒替换
uint8_t a[4] = {
SBOX[(x >> 24) & 0xFF],
SBOX[(x >> 16) & 0xFF],
SBOX[(x >> 8) & 0xFF],
SBOX[x & 0xFF]
};
x = ((uint32_t)a[0] << 24) | ((uint32_t)a[1] << 16) | ((uint32_t)a[2] << 8) | a[3];
// 线性变换L
return x ^ rotl(x, 2) ^ rotl(x, 10) ^ rotl(x, 18) ^ rotl(x, 24);
}

// 加密函数
void sm4_encrypt(const uint8_t in[16], const uint32_t rk[32], uint8_t out[16]) {
uint32_t X[36]; // 加密状态数组

// 1. 明文分组
for (int i = 0; i < 4; i++) {
X[i] = ((uint32_t)in[4*i] << 24) |
((uint32_t)in[4*i+1] << 16) |
((uint32_t)in[4*i+2] << 8) |
in[4*i+3];
}

// 2. 32轮迭代
for (int i = 0; i < 32; i++) {
uint32_t temp = X[i+1] ^ X[i+2] ^ X[i+3] ^ rk[i];
X[i+4] = X[i] ^ T(temp); // Feistel轮函数
}

// 3. 反序输出
uint32_t Y[4] = {X[35], X[34], X[33], X[32]};
for (int i = 0; i < 4; i++) {
out[4*i] = (Y[i] >> 24) & 0xFF;
out[4*i+1] = (Y[i] >> 16) & 0xFF;
out[4*i+2] = (Y[i] >> 8) & 0xFF;
out[4*i+3] = Y[i] & 0xFF;
}
}

完整解密过程如下所示:

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
#ifndef _SM4_H_
#define _SM4_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define u8 unsigned char
#define u32 unsigned long

void four_uCh2uLong(u8 *in, u32 *out); //四字节转换成u32

void uLong2four_uCh(u32 in, u8 *out); //u32转换成四字节

unsigned long move(u32 data, int length); //左移,保留丢弃位放置尾部

unsigned long func_key(u32 input); //先使用Sbox进行非线性变化,再将线性变换L置换为L'

unsigned long func_data(u32 input); //先使用Sbox进行非线性变化,再进行线性变换L

void print_hex(u8 *data, int len); //无符号字符数组转16进制打印

void encode_fun(u8 len,u8 *key, u8 *input, u8 *output); //加密函数

void decode_fun(u8 len,u8 *key, u8 *input, u8 *output); //解密函数

/******************************定义系统参数FK的取值****************************************/
const u32 TBL_SYS_PARAMS[4] = {
0xa3b1bac6,
0x56aa3350,
0x677d9197,
0xb27022dc
};

/******************************定义固定参数CK的取值****************************************/
const u32 TBL_FIX_PARAMS[32] = {

0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
0x10171e25,0x2c333a41,0x484f565d,0x646b7279
};

/******************************SBox参数列表****************************************/
const u8 TBL_SBOX[256] = {

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

#endif
#include "sm4.h"

//4字节无符号数组转无符号long型
void four_uCh2uLong(u8 *in, u32 *out)
{
int i = 0;
*out = 0;
for (i = 0; i < 4; i++)
*out = ((u32)in[i] << (24 - i * 8)) ^ *out;
}

//无符号long型转4字节无符号数组
void uLong2four_uCh(u32 in, u8 *out)
{
int i = 0;
//从32位unsigned long的高位开始取
for (i = 0; i < 4; i++)
*(out + i) = (u32)(in >> (24 - i * 8));
}

//左移,保留丢弃位放置尾部
u32 move(u32 data, int length)
{
u32 result = 0;
result = (data << length) ^ (data >> (32 - length));

return result;
}

//秘钥处理函数,先使用Sbox进行非线性变化,再将线性变换L置换为L'
u32 func_key(u32 input)
{
int i = 0;
u32 ulTmp = 0;
u8 ucIndexList[4] = { 0 };
u8 ucSboxValueList[4] = { 0 };
uLong2four_uCh(input, ucIndexList);
for (i = 0; i < 4; i++)
{
ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
}
four_uCh2uLong(ucSboxValueList, &ulTmp);
ulTmp = ulTmp ^ move(ulTmp, 13) ^ move(ulTmp, 23);

return ulTmp;
}

//加解密数据处理函数,先使用Sbox进行非线性变化,再进行线性变换L
u32 func_data(u32 input)
{
int i = 0;
u32 ulTmp = 0;
u8 ucIndexList[4] = { 0 };
u8 ucSboxValueList[4] = { 0 };
uLong2four_uCh(input, ucIndexList);
for (i = 0; i < 4; i++)
{
ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
}
four_uCh2uLong(ucSboxValueList, &ulTmp);
ulTmp = ulTmp ^ move(ulTmp, 2) ^ move(ulTmp, 10) ^ move(ulTmp, 18) ^ move(ulTmp, 24);

return ulTmp;
}

//加密函数(可以加密任意长度数据,16字节为一次循环,不足部分补0凑齐16字节的整数倍)
//len:数据长度(任意长度数据) key:密钥(16字节) input:输入的原始数据 output:加密后输出数据
void encode_fun(u8 len,u8 *key, u8 *input, u8 *output)
{
int i = 0,j=0;
u8 *p = (u8 *)malloc(50); //定义一个50字节缓存区
u32 ulKeyTmpList[4] = { 0 }; //存储密钥的u32数据
u32 ulKeyList[36] = { 0 }; //用于密钥扩展算法与系统参数FK运算后的结果存储
u32 ulDataList[36] = { 0 }; //用于存放加密数据

/***************************开始生成子秘钥********************************************/
four_uCh2uLong(key, &(ulKeyTmpList[0]));
four_uCh2uLong(key + 4, &(ulKeyTmpList[1]));
four_uCh2uLong(key + 8, &(ulKeyTmpList[2]));
four_uCh2uLong(key + 12, &(ulKeyTmpList[3]));

ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];

for (i = 0; i < 32; i++) //32次循环迭代运算
{
//5-36为32个子秘钥
ulKeyList[i + 4] = ulKeyList[i] ^ func_key(ulKeyList[i + 1] ^ ulKeyList[i + 2] ^ ulKeyList[i + 3] ^ TBL_FIX_PARAMS[i]);
}
/***********************************生成32轮32位长子秘钥结束**********************************/

for (i = 0; i < len; i++) //将输入数据存放在p缓存区
*(p + i) = *(input + i);
for (i = 0; i < 16-len % 16; i++)//将不足16位补0凑齐16的整数倍
*(p + len + i) = 0;

for (j = 0; j < len / 16 + ((len % 16) ? 1:0); j++) //进行循环加密,并将加密后数据保存(可以看出此处是以16字节为一次加密,进行循环,即若16字节则进行一次,17字节补0至32字节后进行加密两次,以此类推)
{
/*开始处理加密数据*/
four_uCh2uLong(p + 16 * j, &(ulDataList[0]));
four_uCh2uLong(p + 16 * j + 4, &(ulDataList[1]));
four_uCh2uLong(p + 16 * j + 8, &(ulDataList[2]));
four_uCh2uLong(p + 16 * j + 12, &(ulDataList[3]));
//加密
for (i = 0; i < 32; i++)
{
ulDataList[i + 4] = ulDataList[i] ^ func_data(ulDataList[i + 1] ^ ulDataList[i + 2] ^ ulDataList[i + 3] ^ ulKeyList[i + 4]);
}
/*将加密后数据输出*/
uLong2four_uCh(ulDataList[35], output + 16 * j);
uLong2four_uCh(ulDataList[34], output + 16 * j + 4);
uLong2four_uCh(ulDataList[33], output + 16 * j + 8);
uLong2four_uCh(ulDataList[32], output + 16 * j + 12);
}
free(p);
}

//解密函数(与加密函数基本一致,只是秘钥使用的顺序不同,即把钥匙反着用就是解密)
//len:数据长度 key:密钥 input:输入的加密后数据 output:输出的解密后数据
void decode_fun(u8 len,u8 *key, u8 *input, u8 *output)
{
int i = 0,j=0;
u32 ulKeyTmpList[4] = { 0 };//存储密钥的u32数据
u32 ulKeyList[36] = { 0 }; //用于密钥扩展算法与系统参数FK运算后的结果存储
u32 ulDataList[36] = { 0 }; //用于存放加密数据

/*开始生成子秘钥*/
four_uCh2uLong(key, &(ulKeyTmpList[0]));
four_uCh2uLong(key + 4, &(ulKeyTmpList[1]));
four_uCh2uLong(key + 8, &(ulKeyTmpList[2]));
four_uCh2uLong(key + 12, &(ulKeyTmpList[3]));

ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];

for (i = 0; i < 32; i++) //32次循环迭代运算
{
//5-36为32个子秘钥
ulKeyList[i + 4] = ulKeyList[i] ^ func_key(ulKeyList[i + 1] ^ ulKeyList[i + 2] ^ ulKeyList[i + 3] ^ TBL_FIX_PARAMS[i]);
}
/*生成32轮32位长子秘钥结束*/

for (j = 0; j < len / 16; j++) //进行循环加密,并将加密后数据保存
{
/*开始处理解密数据*/
four_uCh2uLong(input + 16 * j, &(ulDataList[0]));
four_uCh2uLong(input + 16 * j + 4, &(ulDataList[1]));
four_uCh2uLong(input + 16 * j + 8, &(ulDataList[2]));
four_uCh2uLong(input + 16 * j + 12, &(ulDataList[3]));

//解密
for (i = 0; i < 32; i++)
{
ulDataList[i + 4] = ulDataList[i] ^ func_data(ulDataList[i + 1] ^ ulDataList[i + 2] ^ ulDataList[i + 3] ^ ulKeyList[35 - i]);//与加密唯一不同的就是轮密钥的使用顺序
}
/*将解密后数据输出*/
uLong2four_uCh(ulDataList[35], output + 16 * j);
uLong2four_uCh(ulDataList[34], output + 16 * j + 4);
uLong2four_uCh(ulDataList[33], output + 16 * j + 8);
uLong2four_uCh(ulDataList[32], output + 16 * j + 12);
}
}

//无符号字符数组转16进制打印
void print_hex(u8 *data, int len)
{
int i = 0;
char alTmp[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
for (i = 0; i < len; i++)
{
printf("%c", alTmp[data[i] / 16]);
printf("%c", alTmp[data[i] % 16]);
putchar(' ');
}
putchar('\n');
}
/*在主函数中实现任意字节加密与解密,并且结果正确*/
int main(void)
{
u8 i,len;
u8 encode_Result[50] = { 0 }; //定义加密输出缓存区
u8 decode_Result[50] = { 0 }; //定义解密输出缓存区
u8 key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 }; //定义16字节的密钥
//u8 Data_plain[18] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x01,0x23 };//定义18字节的原始输入数据(测试用)
//u8 Data_plain[32] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//定义32字节的原始输入数据(测试用)
u8 Data_plain[16] = { 0x01,0x23,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//定义16字节的原始输入数据(测试用)
len = 16 * (sizeof(Data_plain) / 16) + 16 * ((sizeof(Data_plain) % 16) ? 1 : 0);//得到扩充后的字节数(解密函数会用到)

encode_fun(sizeof(Data_plain),key, Data_plain, encode_Result); //数据加密
printf("加密后数据是:\n");
for (i = 0; i < len ; i++)
printf("%x ", *(encode_Result + i));
/*注意:此处解密函数的输入数据长度应为扩展后的数据长度,即必为16的倍数*/
decode_fun(len,key, encode_Result, decode_Result); //数据解密
printf("解密后数据是:\n");
for (i = 0; i < len; i++)
printf("%x ", *(decode_Result + i));

system("pause");
return 0;
}

#ifndef _SM4_H_
#define _SM4_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define u8 unsigned char
#define u32 unsigned long

void four_uCh2uLong(u8 *in, u32 *out); //四字节转换成u32

void uLong2four_uCh(u32 in, u8 *out); //u32转换成四字节

unsigned long move(u32 data, int length); //左移,保留丢弃位放置尾部

unsigned long func_key(u32 input); //先使用Sbox进行非线性变化,再将线性变换L置换为L'

unsigned long func_data(u32 input); //先使用Sbox进行非线性变化,再进行线性变换L

void print_hex(u8 *data, int len); //无符号字符数组转16进制打印

void encode_fun(u8 len,u8 *key, u8 *input, u8 *output); //加密函数

void decode_fun(u8 len,u8 *key, u8 *input, u8 *output); //解密函数

/******************************定义系统参数FK的取值****************************************/
const u32 TBL_SYS_PARAMS[4] = {
0xa3b1bac6,
0x56aa3350,
0x677d9197,
0xb27022dc
};

/******************************定义固定参数CK的取值****************************************/
const u32 TBL_FIX_PARAMS[32] = {

0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
0x10171e25,0x2c333a41,0x484f565d,0x646b7279
};

/******************************SBox参数列表****************************************/
const u8 TBL_SBOX[256] = {

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

#endif

//4字节无符号数组转无符号long型
void four_uCh2uLong(u8 *in, u32 *out)
{
int i = 0;
*out = 0;
for (i = 0; i < 4; i++)
*out = ((u32)in[i] << (24 - i * 8)) ^ *out;
}

//无符号long型转4字节无符号数组
void uLong2four_uCh(u32 in, u8 *out)
{
int i = 0;
//从32位unsigned long的高位开始取
for (i = 0; i < 4; i++)
*(out + i) = (u32)(in >> (24 - i * 8));
}

//左移,保留丢弃位放置尾部
u32 move(u32 data, int length)
{
u32 result = 0;
result = (data << length) ^ (data >> (32 - length));

return result;
}

//秘钥处理函数,先使用Sbox进行非线性变化,再将线性变换L置换为L'
u32 func_key(u32 input)
{
int i = 0;
u32 ulTmp = 0;
u8 ucIndexList[4] = { 0 };
u8 ucSboxValueList[4] = { 0 };
uLong2four_uCh(input, ucIndexList);
for (i = 0; i < 4; i++)
{
ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
}
four_uCh2uLong(ucSboxValueList, &ulTmp);
ulTmp = ulTmp ^ move(ulTmp, 13) ^ move(ulTmp, 23);

return ulTmp;
}

//加解密数据处理函数,先使用Sbox进行非线性变化,再进行线性变换L
u32 func_data(u32 input)
{
int i = 0;
u32 ulTmp = 0;
u8 ucIndexList[4] = { 0 };
u8 ucSboxValueList[4] = { 0 };
uLong2four_uCh(input, ucIndexList);
for (i = 0; i < 4; i++)
{
ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
}
four_uCh2uLong(ucSboxValueList, &ulTmp);
ulTmp = ulTmp ^ move(ulTmp, 2) ^ move(ulTmp, 10) ^ move(ulTmp, 18) ^ move(ulTmp, 24);

return ulTmp;
}

//加密函数(可以加密任意长度数据,16字节为一次循环,不足部分补0凑齐16字节的整数倍)
//len:数据长度(任意长度数据) key:密钥(16字节) input:输入的原始数据 output:加密后输出数据
void encode_fun(u8 len,u8 *key, u8 *input, u8 *output)
{
int i = 0,j=0;
u8 *p = (u8 *)malloc(50); //定义一个50字节缓存区
u32 ulKeyTmpList[4] = { 0 }; //存储密钥的u32数据
u32 ulKeyList[36] = { 0 }; //用于密钥扩展算法与系统参数FK运算后的结果存储
u32 ulDataList[36] = { 0 }; //用于存放加密数据

/***************************开始生成子秘钥********************************************/
four_uCh2uLong(key, &(ulKeyTmpList[0]));
four_uCh2uLong(key + 4, &(ulKeyTmpList[1]));
four_uCh2uLong(key + 8, &(ulKeyTmpList[2]));
four_uCh2uLong(key + 12, &(ulKeyTmpList[3]));

ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];

for (i = 0; i < 32; i++) //32次循环迭代运算
{
//5-36为32个子秘钥
ulKeyList[i + 4] = ulKeyList[i] ^ func_key(ulKeyList[i + 1] ^ ulKeyList[i + 2] ^ ulKeyList[i + 3] ^ TBL_FIX_PARAMS[i]);
}
/***********************************生成32轮32位长子秘钥结束**********************************/

for (i = 0; i < len; i++) //将输入数据存放在p缓存区
*(p + i) = *(input + i);
for (i = 0; i < 16-len % 16; i++)//将不足16位补0凑齐16的整数倍
*(p + len + i) = 0;

for (j = 0; j < len / 16 + ((len % 16) ? 1:0); j++) //进行循环加密,并将加密后数据保存(可以看出此处是以16字节为一次加密,进行循环,即若16字节则进行一次,17字节补0至32字节后进行加密两次,以此类推)
{
/*开始处理加密数据*/
four_uCh2uLong(p + 16 * j, &(ulDataList[0]));
four_uCh2uLong(p + 16 * j + 4, &(ulDataList[1]));
four_uCh2uLong(p + 16 * j + 8, &(ulDataList[2]));
four_uCh2uLong(p + 16 * j + 12, &(ulDataList[3]));
//加密
for (i = 0; i < 32; i++)
{
ulDataList[i + 4] = ulDataList[i] ^ func_data(ulDataList[i + 1] ^ ulDataList[i + 2] ^ ulDataList[i + 3] ^ ulKeyList[i + 4]);
}
/*将加密后数据输出*/
uLong2four_uCh(ulDataList[35], output + 16 * j);
uLong2four_uCh(ulDataList[34], output + 16 * j + 4);
uLong2four_uCh(ulDataList[33], output + 16 * j + 8);
uLong2four_uCh(ulDataList[32], output + 16 * j + 12);
}
free(p);
}

//解密函数(与加密函数基本一致,只是秘钥使用的顺序不同,即把钥匙反着用就是解密)
//len:数据长度 key:密钥 input:输入的加密后数据 output:输出的解密后数据
void decode_fun(u8 len,u8 *key, u8 *input, u8 *output)
{
int i = 0,j=0;
u32 ulKeyTmpList[4] = { 0 };//存储密钥的u32数据
u32 ulKeyList[36] = { 0 }; //用于密钥扩展算法与系统参数FK运算后的结果存储
u32 ulDataList[36] = { 0 }; //用于存放加密数据

/*开始生成子秘钥*/
four_uCh2uLong(key, &(ulKeyTmpList[0]));
four_uCh2uLong(key + 4, &(ulKeyTmpList[1]));
four_uCh2uLong(key + 8, &(ulKeyTmpList[2]));
four_uCh2uLong(key + 12, &(ulKeyTmpList[3]));

ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];

for (i = 0; i < 32; i++) //32次循环迭代运算
{
//5-36为32个子秘钥
ulKeyList[i + 4] = ulKeyList[i] ^ func_key(ulKeyList[i + 1] ^ ulKeyList[i + 2] ^ ulKeyList[i + 3] ^ TBL_FIX_PARAMS[i]);
}
/*生成32轮32位长子秘钥结束*/

for (j = 0; j < len / 16; j++) //进行循环加密,并将加密后数据保存
{
/*开始处理解密数据*/
four_uCh2uLong(input + 16 * j, &(ulDataList[0]));
four_uCh2uLong(input + 16 * j + 4, &(ulDataList[1]));
four_uCh2uLong(input + 16 * j + 8, &(ulDataList[2]));
four_uCh2uLong(input + 16 * j + 12, &(ulDataList[3]));

//解密
for (i = 0; i < 32; i++)
{
ulDataList[i + 4] = ulDataList[i] ^ func_data(ulDataList[i + 1] ^ ulDataList[i + 2] ^ ulDataList[i + 3] ^ ulKeyList[35 - i]);//与加密唯一不同的就是轮密钥的使用顺序
}
/*将解密后数据输出*/
uLong2four_uCh(ulDataList[35], output + 16 * j);
uLong2four_uCh(ulDataList[34], output + 16 * j + 4);
uLong2four_uCh(ulDataList[33], output + 16 * j + 8);
uLong2four_uCh(ulDataList[32], output + 16 * j + 12);
}
}

//无符号字符数组转16进制打印
void print_hex(u8 *data, int len)
{
int i = 0;
char alTmp[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
for (i = 0; i < len; i++)
{
printf("%c", alTmp[data[i] / 16]);
printf("%c", alTmp[data[i] % 16]);
putchar(' ');
}
putchar('\n');
}
/*在主函数中实现任意字节加密与解密,并且结果正确*/
int main(void)
{
u8 i,len;
u8 encode_Result[50] = { 0 }; //定义加密输出缓存区
u8 decode_Result[50] = { 0 }; //定义解密输出缓存区
u8 key[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 }; //定义16字节的密钥
//u8 Data_plain[18] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x01,0x23 };//定义18字节的原始输入数据(测试用)
//u8 Data_plain[32] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//定义32字节的原始输入数据(测试用)
u8 Data_plain[16] = { 0x01,0x23,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//定义16字节的原始输入数据(测试用)
len = 16 * (sizeof(Data_plain) / 16) + 16 * ((sizeof(Data_plain) % 16) ? 1 : 0);//得到扩充后的字节数(解密函数会用到)

encode_fun(sizeof(Data_plain),key, Data_plain, encode_Result); //数据加密
printf("加密后数据是:\n");
for (i = 0; i < len ; i++)
printf("%x ", *(encode_Result + i));
/*注意:此处解密函数的输入数据长度应为扩展后的数据长度,即必为16的倍数*/
decode_fun(len,key, encode_Result, decode_Result); //数据解密
printf("解密后数据是:\n");
for (i = 0; i < len; i++)
printf("%x ", *(decode_Result + i));

system("pause");
return 0;
}

Python实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from gmssl import sm4

# 密钥和IV(必须为16字节)
key = b'\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10'
iv = b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF'

# 明文
plaintext = b"Hello SM4 with Python!"

# 加密
cipher = sm4_encrypt_cbc(key, iv, plaintext)
print("Ciphertext (hex):", cipher.hex())

# 解密
decrypted = sm4_decrypt_cbc(key, iv, cipher)
print("Decrypted:", decrypted.decode())

这种方法需要导入gmssl库

1
pip install gmssl