我又来填坑了,这篇文章主要是来解析一下DES算法是如何实现加密解密。本文主要参考的是 J.Orlin Grabbe 的《DES Algorithm Illustrated》

密钥创建

首先我们需要一个64位的密钥作为 key_seed

比如,我们的十六进制密钥 K 为

1
K = 0123456789ABCDEF

它的64位二进制为

1
2
3
K = 
00000001 00100011 01000101 01100111
10001001 10101011 11001101 11101111

第一步:创建16个48位的子密钥

1.混淆(压缩)

根据下列顺序,重组密钥,进行第一次【混淆】

1
2
3
4
5
6
7
8
9
10
11
static char pc_1[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
};

即新密钥的前八位是原密钥的第57,49,41,33,25,17,9位

注意⚠️:原密钥中只有56位会进入新密钥。

比如,原密钥:

1
2
3
K = 
00000001 00100011 01000101 01100111
10001001 10101011 11001101 11101111

得到的56位新密钥:

1
2
3
K = 
1111000 0110011 0010101 0100000
1010101 0110011 0011110 0000000

2.左移

然后我们讲这个密钥拆分成左右两个部分,每部分28位。

1
2
C0 = 1111000 0110011 0010101 0100000
D0 = 1010101 0110011 0011110 0000000

现在我们要创建16个字密钥 Ci ,Di ,1<= i <= 16. 每一个子钥都是前一对子钥【左移】而来。下表是每轮左移的位数。

1
2
3
4
5
static char num_left_shift[16] = 
{
1, 1, 2, 2, 2, 2, 2, 2, \
1, 2, 2, 2, 2, 2, 2, 1
};

即 C2 是由 C1 左移一位得来,D3 是由 D2 左移2位得来。

上面提到的密钥左移生成的结果是:

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
C1 = 1110000 1100110 0101010 1000001
D1 = 0101010 1100110 0111100 0000001
C2 = 1100001 1001100 1010101 0000011
D2 = 1010101 1001100 1111000 0000010
C3 = 0000110 0110010 1010100 0001111
D3 = 1010110 0110011 1100000 0001010
C4 = 0011001 1001010 1010000 0111100
D4 = 1011001 1001111 0000000 0101010
C5 = 1100110 0101010 1000001 1110000
D5 = 1100110 0111100 0000001 0101010
C6 = 0011001 0101010 0000111 1000011
D6 = 0011001 1110000 0000101 0101011
C7 = 1100101 0101000 0011110 0001100
D7 = 1100111 1000000 0010101 0101100
C8 = 0010101 0100000 1111000 0110011
D8 = 0011110 0000000 1010101 0110011
C9 = 0101010 1000001 1110000 1100110
D9 = 0111100 0000001 0101010 1100110
C10 = 0101010 0000111 1000011 0011001
D10 = 1110000 0000101 0101011 0011001
C11 = 0101000 0011110 0001100 1100101
D11 = 1000000 0010101 0101100 1100111
C12 = 0100000 1111000 0110011 0010101
D12 = 0000000 1010101 0110011 0011110
C13 = 0000011 1100001 1001100 1010101
D13 = 0000010 1010101 1001100 1111000
C14 = 0001111 0000110 0110010 1010100
D14 = 0001010 1010110 0110011 1100000
C15 = 0111100 0011001 1001010 1010000
D15 = 0101010 1011001 1001111 0000000
C16 = 1111000 0110011 0010101 0100000
D16 = 1010101 0110011 0011110 0000000

3.混淆(扩展)

最后再过一次【混淆】,将 Ci 与 Di 拼在一起,混淆得到字密钥 Ki

1
2
3
4
5
6
7
8
9
10
11
static char pc_2[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
};

这个时候得到的字密钥就只有48位了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
K0 = 000110 110000 001011 101111 111111 000111 000001 110010 
K1 = 011110 011010 111011 011001 110110 111100 100111 100101
K2 = 010101 011111 110010 001010 010000 101100 111110 011001
K3 = 011100 101010 110111 010110 110110 110011 010100 011101
K4 = 011111 001110 110000 000111 111010 110101 001110 101000
K5 = 011000 111010 010100 111110 010100 000111 101100 101111
K6 = 111011 001000 010010 110111 111101 100001 100010 111100
K7 = 111101 111000 101000 111010 110000 010011 101111 111011
K8 = 111000 001101 101111 101011 111011 011110 011110 000001
K9 = 101100 011111 001101 000111 101110 100100 011001 001111
K10 = 001000 010101 111111 010011 110111 101101 001110 000110
K11 = 011101 010111 000111 110101 100101 000110 011111 101001
K12 = 100101 111100 010111 010001 111110 101011 101001 000001
K13 = 010111 110100 001110 110111 111100 101110 011100 111010
K14 = 101111 111001 000110 001101 001111 010011 111100 001010
K15 = 110010 110011 110110 001011 000011 100001 011111 110101

第二步:加密数据的每个64位区块

1.混淆

明文也要过一次【混淆】

1
2
3
4
5
6
7
8
9
10
11
static char 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
};

如我们的明文是

1
plaintext = abcdef0987654321

二进制为:

1
2
3
plaintext:
10101011 11001101 11101111 00001001
10000111 01100101 01000011 00100001

混淆后:

1
2
3
plaintext after confusion:
01100110 00000000 00110110 11111111
00010111 10100101 00001111 01010101

2.加密

然后我们把混淆后的明文分成左32位,右32位

1
2
L0 = 01100110 00000000 00110110 11111111
R0 = 00010111 10100101 00001111 01010101

接着进行16轮迭代,迭代公式为:

Li = Ri-1
Ri = Li + f (Ri-1 , Ki)

其中f函数的操作是:

  • 通过下表,将 R 扩展为48位,然后再与 K 进行异或
1
2
3
4
5
6
7
8
9
10
11
static char E_bit_selections[64] =
{
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
};
  • 然后过一个 sbox
    先把 Ki ^ E(Ri-1) 分成8个部分,每个部分6位

    Ki ^ E(Ri-1) = B1B2B3B4B5B6B7B8

    然后对每个部分过 sbox。第i 部分去查第 isbox
    Bi 的第一位与最后一位组合起来确定行,剩下四位确定列。比如B1 = 100101,行就是11(十进制为3),列为0010(十进制为2)。

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
static char sbox[8][64] =
{
/* 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
};
  • 最后一步 【混淆】
    把得到的结果按下表进行混淆
1
2
3
4
5
6
7
8
9
10
11
static char sbox_perm_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
};

比如

1
2
3
4
5
L0 = 01100110 00000000 00110110 11111111
R0 = 00010111 10100101 00001111 01010101
K1 = 011110 011010 111011 011001 110110 111100 100111 100101
L1 = 00010111 10100101 00001111 01010101
R1 = 11110111 00000100 11100110 10001010

3.组合

最后加密的结果: cipher text = R16L16

1
2
3
4
5
key_seed = 0123456789ABCDEF
plaintext = abcdef0987654321
ciphertext = 2353d034c2c9e18e
/* ciphertext的二进制是 */
00100011 01010011 11010000 00110100 11000010 11001001 11100001 10001110

解密的过程就是密钥的逆用,加密用K1,K2……解密就用K16,K15……

附录:代码实现

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
//
// main.cpp
// DES
//
// Created by Yy Y on 2021/6/4.
//

#include <iostream>
using namespace std;


static char pc_1[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
};
static char pc_2[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
};
static char 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
};
static char num_left_shift[16] =
{
1, 1, 2, 2, 2, 2, 2, 2, \
1, 2, 2, 2, 2, 2, 2, 1
};
static char E_bit_selections[64] =
{
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
};
static char sbox[8][64] =
{
/* 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
};
static char sbox_perm_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
};
static char fp[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
};

void Encrypt(int key_seed[], int plaintext[], int ciphertext[]);
void Decrypt(int key_seed[], int plaintext[], int ciphertext[]);
void create_Key(int key_seed[], int key[16][48]);
void read_64bits(int arr[]);
void ip_plain(int plain_text[], int key[16][48], int ciphertext[]);
void reverse_ip_plain(int plain_text[], int key[16][48], int ciphertext[]);
void f(int R_out[32], int L[32], int K[48], int R[32]);
void f_reverse(int R_out[32], int L[32], int K[48], int R[32]);


int main(int argc, const char * argv[])
{
// insert code here...
int key_seed[16], plaintext[16], ciphertext[16];
cout << "---------- Ya Ou ----------" << endl;
cout << "Choose : 1.Encrypt 2.Decrypt" << endl;
int choice;
cin >> choice;
if(choice == 1)
{
cout << "---------- input: ----------" << endl;
cout << "key_seed: ";
read_64bits(key_seed);
cout << "plaintext: ";
read_64bits(plaintext);

Encrypt(key_seed, plaintext, ciphertext);
cout << "---------- ciphertext ----------" << endl;
for(int i=0; i<16; i++)
cout << hex << ciphertext[i];
cout << endl;
}
else if(choice == 2)
{
cout << "---------- input: ----------" << endl;
cout << "key_seed: ";
read_64bits(key_seed);
cout << "ciphertext: ";
read_64bits(ciphertext);

Decrypt(key_seed, plaintext, ciphertext);
cout << "---------- plaintext ----------" << endl;
for(int i=0; i<16; i++)
cout << hex << plaintext[i];
cout << endl;
}
else
cout << "bye!" << endl;

return 0;
}

void Encrypt(int key_seed[], int plaintext[], int ciphertext[])
{
int key[16][48];
create_Key(key_seed, key);
ip_plain(plaintext, key, ciphertext);
}

void Decrypt(int key_seed[], int plaintext[], int ciphertext[])
{
int key[16][48];
create_Key(key_seed, key);
reverse_ip_plain(plaintext, key, ciphertext);
}

void read_64bits(int arr[])
{
for(int i=0; i<16; i++)
{
char tmp;
cin >> tmp;
if(tmp >= '0' && tmp <= '9')
arr[i] = tmp - '0';
else if (tmp >= 'A' && tmp <= 'Z')
arr[i] = tmp - 'A' + 10;
else if (tmp >= 'a' && tmp <= 'z')
arr[i] = tmp - 'a' + 10;
}
}

void create_Key(int key_seed[], int key[16][48])
{
cout << "--------- creating key... ----------" << endl;
cout << "key_seed = " << endl;
for(int i=0; i<4; i++)
{

cout << bitset<sizeof(int)>(key_seed[2*i]);
cout << bitset<sizeof(int)>(key_seed[2*i+1]);
cout << " ";
}
cout << endl;
for(int i=4; i<8; i++)
{
cout << bitset<sizeof(int)>(key_seed[2*i]);
cout << bitset<sizeof(int)>(key_seed[2*i+1]);
cout << " ";
}
cout << endl << endl;

char flag;
cout << "Do you want to see the 16 blocks of keys? :) (y/n)";
cin >> flag;

int index = 3, tmp_key[64];
for(int i=0; i<16; i++)
{
int tmp = key_seed[i];
for(int j=0; j<4; j++)
{
tmp_key[index--] = tmp % 2;
tmp /= 2;
}
index += 8;
}

int C[17][28], D[17][28];
if(flag == 'y') cout << "C0 = ";
for(int i=0; i<28; i++)
{
C[0][i] = tmp_key[pc_1[i]-1];

if(flag == 'y')
{
cout << C[0][i];
if((i+1) % 7 == 0)
cout << " ";
}
}
if(flag == 'y') cout << endl << "D0 = ";
for(int i=28; i<56; i++)
{
D[0][i-28] = tmp_key[pc_1[i]-1];

if(flag == 'y')
{
cout << D[0][i-28];
if((i+1) % 7 == 0)
cout << " ";
}
}
if(flag == 'y') cout << endl;

for(int i=1; i<=16; i++)
{
if(num_left_shift[i-1] == 1)
{
int j=0, tmpC, tmpD;
tmpC = C[i-1][j];
tmpD = D[i-1][j];

for(j=0; j<27; j++)
{
C[i][j] = C[i-1][j+1];
D[i][j] = D[i-1][j+1];
}
C[i][27] = tmpC;
D[i][27] = tmpD;
}
else
{
int j=0, tmpC, tmpD, tmpC2, tmpD2;
tmpC = C[i-1][j];
tmpD = D[i-1][j];
tmpC2 = C[i-1][j+1];
tmpD2 = D[i-1][j+1];

for(j=0; j<26; j++)
{
C[i][j] = C[i-1][j+2];
D[i][j] = D[i-1][j+2];
}
C[i][26] = tmpC;
D[i][26] = tmpD;
C[i][27] = tmpC2;
D[i][27] = tmpD2;
}

if(flag == 'y')
{
cout << "C" << i << " = ";
for(int k=0; k<28; k++)
{
cout << C[i][k];
if((k+1) % 7 == 0)
cout << " ";
}
cout << endl;
cout << "D" << i << " = ";
for(int k=0; k<28; k++)
{
cout << D[i][k];
if((k+1) % 7 == 0)
cout << " ";
}
cout << endl;
}
}

for(int i=0; i<16; i++)
{
for(int j=0; j<48; j++)
{
if(pc_2[j] > 28)
key[i][j] = D[i+1][pc_2[j]-29];
else
key[i][j] = C[i+1][pc_2[j]-1];
}
if(flag == 'y')
{
cout << "K" << i << " = ";
for(int j=0; j<48; j++)
{
cout << key[i][j];
if((j+1) % 6 == 0)
cout << " ";
}
cout << endl;
}
}

}

void ip_plain(int plain_text[], int key[16][48], int ciphertext[])
{
cout << "---------- Encrypting... ----------" << endl;
cout << "plaintext = " << endl;
for(int i=0; i<4; i++)
{
cout << bitset<sizeof(int)>(plain_text[2*i]);
cout << bitset<sizeof(int)>(plain_text[2*i+1]);
cout << " ";
}
cout << endl;
for(int i=4; i<8; i++)
{
cout << bitset<sizeof(int)>(plain_text[2*i]);
cout << bitset<sizeof(int)>(plain_text[2*i+1]);
cout << " ";
}
cout << endl << endl;

int tmp_plain[64];
int index = 3;
for(int i=0; i<16; i++)
{
int tmp = plain_text[i];
for(int j=0; j<4; j++)
{
tmp_plain[index--] = tmp % 2;
tmp /= 2;
}
index += 8;
}

int L[17][32], R[17][32];
cout << "Do you want to see the procedure? (y/n)";
char flag;
cin >> flag;
if(flag == 'y')
cout << "after confusion: " << endl;
for(int i=0; i<64; i++)
{
if(i < 32)
L[0][i] = tmp_plain[ip[i]-1];
else
R[0][i-32] = tmp_plain[ip[i]-1];

if(flag == 'y')
{
cout << tmp_plain[ip[i]-1];
if((i+1) % 8 == 0)
cout << " ";
if((i+1) % 32 == 0)
cout << endl;
}
}

for(int i=1; i<=16; i++)
{
for(int j=0; j<32; j++)
{
L[i][j] = R[i-1][j];
}
f(R[i], L[i-1], key[i-1], R[i-1]);

if(flag == 'y')
{
cout << "L" << i << "=";
for(int j=0; j < 32; j++)
{
cout << L[i][j];
if((j+1) % 8 == 0)
cout << " ";
}
cout << endl;
cout << "R" << i << "=";
for(int j=0; j < 32; j++)
{
cout << R[i][j];
if((j+1) % 8 == 0)
cout << " ";
}
cout << endl;
}
}

int ip[64];
for(int i=0; i<64; i++)
{
if(fp[i] < 32)
ip[i] = R[16][fp[i]-1];
else
ip[i] = L[16][fp[i]-33];
if(flag == 'y')
{
cout << ip[i];
if((i+1) % 8 == 0)
cout << " ";
}
}
cout << endl;

for(int i=0; i<16; i++)
ciphertext[i] = ip[i*4]<<3 | ip[i*4+1]<<2 | ip[i*4+2]<<1 | ip[i*4+3];
}

void f(int R_out[32], int L[32], int K[48], int R[32])
{
int E[48];

for(int i=0; i<48; i++)
{
E[i] = R[E_bit_selections[i]-1] ^ K[i];
}

char s[32];
int index = 3;
for(int i=0; i<8; i++)
{
int num;
int row = 2*E[i*6] + E[(i+1)*6-1];
int column = 8*E[i*6+1] + 4*E[i*6+2] + 2*E[i*6+3] + E[i*6+4];
num = sbox[i][row*16 + column];
for(int j=0; j<4; j++)
{
s[index--] = num % 2;
num /= 2;
}
index += 8;
}

for(int i=31; i>=0; i--)
{
R_out[i] = L[i] ^ s[sbox_perm_table[i]-1];
}
}

void reverse_ip_plain(int plain_text[], int key[16][48], int ciphertext[])
{
cout << "---------- Decrypting... ----------" << endl;
cout << "ciphertext = " << endl;
for(int i=0; i<4; i++)
{
cout << bitset<sizeof(int)>(ciphertext[2*i]);
cout << bitset<sizeof(int)>(ciphertext[2*i+1]);
cout << " ";
}
cout << endl;
for(int i=4; i<8; i++)
{
cout << bitset<sizeof(int)>(ciphertext[2*i]);
cout << bitset<sizeof(int)>(ciphertext[2*i+1]);
cout << " ";
}
cout << endl << endl;

int tmp_cipher[64];
int index = 3;
for(int i=0; i<16; i++)
{
int tmp = ciphertext[i];
for(int j=0; j<4; j++)
{
tmp_cipher[index--] = tmp % 2;
tmp /= 2;
}
index += 8;
}

int L[17][32], R[17][32];
cout << "Do you want to see the procedure? (y/n)";
char flag;
cin >> flag;
if(flag == 'y')
cout << "after confusion: " << endl;
for(int i=0; i<64; i++)
{
if(i < 32)
L[0][i] = tmp_cipher[ip[i]-1];
else
R[0][i-32] = tmp_cipher[ip[i]-1];

if(flag == 'y')
{
cout << tmp_cipher[ip[i]-1];
if((i+1) % 8 == 0)
cout << " ";
if((i+1) % 32 == 0)
cout << endl;
}
}

for(int i=1; i<=16; i++)
{
for(int j=0; j<32; j++)
{
L[i][j] = R[i-1][j];
}
f(R[i], L[i-1], key[16-i], R[i-1]);

if(flag == 'y')
{
cout << "L" << i << "=";
for(int j=0; j < 32; j++)
{
cout << L[i][j];
if((j+1) % 8 == 0)
cout << " ";
}
cout << endl;
cout << "R" << i << "=";
for(int j=0; j < 32; j++)
{
cout << R[i][j];
if((j+1) % 8 == 0)
cout << " ";
}
cout << endl;
}
}

int ip[64];
for(int i=0; i<64; i++)
{
if(fp[i] < 32)
ip[i] = R[16][fp[i]-1];
else
ip[i] = L[16][fp[i]-33];
if(flag == 'y')
{
cout << ip[i];
if((i+1) % 8 == 0)
cout << " ";
}
}
cout << endl;

for(int i=0; i<16; i++)
plain_text[i] = ip[i*4]<<3 | ip[i*4+1]<<2 | ip[i*4+2]<<1 | ip[i*4+3];
}

这份代码唯一不满意的地方就是我用了 int 来存二进制,最好还是按 bool 这种一位的类型来计算。