RE中的密码学

流密码

特征就是密文仅由明文与密钥流经过异或运算得到。只要识别出流密码,我们就可以选择动态调试获取密钥流或者直接把目标密文 patch 进去拿输出就可以了,常见的有 RC4、Salsa20 以及 ChaCha20.

RC4

特征识别

  • 长度为 256 的 S 盒,且在每一步生成与加密过程中都伴随着 S 盒的 swap 操作
  • 很多取模操作
  • 有多个次数为 256 的循环
  • 最后的操作为异或

加密流程简述

  • 先创建一个长度为 256 的 S 盒,初始值为 0~255升序排列,然后根据密钥,用 ksa (密钥调度算法)对 S 盒进行替换,完成后将不再使用密钥
  • PRGA (伪随机生成算法)使用两个变量 i 和 j,循环动态变化,在每步中:i 自增 1,j 根据 S[i]变化;交换 S[i] 和 S[j];从 S[(S[i] + S[j]) % 256] 位置取出一个字节作为密钥流字节 K。最后用这个密钥流字节 K,和明文字节做异或

代码实现

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

//初始化 S 盒(0~255)并根据密钥打乱
void KSA(vector<unsigned char>& S,const vector<unsigned char>& key){
int key_length=key.size();
//初始化 S
for(int i=0;i<256;++i){
S[i]=i;
}
//根据密钥打乱 S
for(int j=0;j<256;++j){
j=(j+S[j]+key[j%key_length])%256;
swap(S[j],S[j]);
}
}

//生成密钥流,并加密/解密输入数据
vector<unsigned char> RC4(const vector<unsigned char>& key,const vector<unsigned char>& data){
vector<unsigned char> S(256);
KSA(S,key);
int i=0,j=0;
vector<unsigned char> output;
output.reserve(data.size());

for(size_t k=0;k<data.size();++k){
i=(i+1)%256;
j=(j+S[i])%256;
swap(S[i],S[j]);
int t=(S[i]+S[j])%256;
unsigned char K=S[t];
output.push_back(data[k]^K); //明文字节 XOR 密钥流字节
}
return output;
}
void print_hex(const vector<unsigned char>& data){
for(unsigned char c:data){
printf("%02X ",c);
}
printf("\n");
}

int main(){
string key_str="OceanBlue";
string plaintext_str="ISeeYourSecretMessage"; //明文
vector<unsigned char> key(key_str.begin(),key_str.end());
vector<unsigned char> plaintext(plaintext_str.begin(),plaintext_str.end());
//加密
vector<unsigned char> ciphertext=RC4(key,plaintext);
cout<<"hex:";
print_hex(ciphertext);
//解密
vector<unsigned char> decryptedtext=RC4(key,ciphertext);
cout << "encoded: ";
for (unsigned char c : decryptedtext) {
cout << c;
}
cout << endl;
return 0;
}

ChaCha20

  • 20 表示该算法有 20 轮加密
  • 有一个初始矩阵,矩阵的输入为一个256位的密钥、64位随机数、64位计数器值以及4×32位的常数,它们均填充在32位整型数组中作为初始矩阵
  • 识别ChaCha20的主要特征是四个常数0x61707865 0x3320646e 0x79622d32 0x6b206574按小端存储转为ASCII字符是”expand 32-byte k”

块密码

块密码是一种对固定长度的明文数据块进行加密的对称加密算法,基本思想是:将明文分成若干个固定长度的数据块(如64位或128位);
每个数据块独立或依赖某种模式(如CBC、EBC等)进行加密;加密和解密使用相同的密钥;常见的块加密算法包括:DES、AES、TEA等

TEA

特征识别

  • 有一个 delta 常量,值是0x9e3779b9(可能会被魔改)
  • 每轮先进行 sum+=delta,再进行 左移4,异或,右移5

加密流程简述

  • 将64位明文分成两个部分,v0 和 v1,各32位
  • 将128位的密钥分成四个32位(4字节)的子密钥 k1,k2,k3,k4
  • 初始化常量 delta,初始化sum=0
  • 加密通常为 32 轮循环,每次包括两轮,共64轮

代码实现

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
#include <bits/stdc++.h>
void encrypt(uint32_t *v, uint32_t *k)
{
uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
uint32_t delta = 0x9e3779b9;
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);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
}
v[0] = v0;
v[1] = v1;
}

void decrypt(uint32_t *v, uint32_t *k)
{
uint32_t v0 = v[0], v1 = v[1], i;
uint32_t delta = 0x9e3779b9;
uint32_t sum = delta * 32;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (i = 0; i < 32; i++)
{
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
}

XTEA

XTEA 是 TEA 的改进版,增加了更多的密钥表,移位和异或操作等,TEA 的子密钥是通过下标取的,XTEA 的子密钥是通过计算来取,注意sum+key[sum&3]sum+key[(sum>>11)&3]
代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <bits/stdc++.h>
using namespace std;

void encrypt(unsigned int num_rounds,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<num_rounds;i++){
v0+=(((v1<<4)^(v1>>5))+v1)^(sum+key[sum&3]);
sum+=delta;
v1+=(((v0<<4)^(v0>>5))+v0)^(sum+key[(sum>>11)&3]);
}
v[0]=v0;
v[1]=v1;
}


void decrypt(unsigned int num_rounds,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;
}

XXTEA

  • 明文块的大小可以是任意的(最少两个32位即64位),被分割为若干个32位的整数(即4字节为一个单位),形成一个数组 v[0] … v[n-1]
  • 采用以下混合函数来确保扩散和混淆:
    MX = ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));

解密脚本

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
#define DELTA 0x9e3779b9 
int main()
{
unsigned int v[] = {0xE74EB323, 0xB7A72836, 0x59CA6FE2, 0X967CC5C1, 0XE7802674, 0X3D2D54E6, 0X8A9D0356, 0X99DCC39C, 0X7026D8ED, 0x6A33FDAD, 0xF496550A, 0x5C9C6F9E, 0x1BE5D04C, 0x6723AE17, 0x5270A5C2, 0xAC42130A, 0x84BE67B2, 0x705CC779, 0x5C513D98, 0xFB36DA2D, 0x22179645, 0x5CE3529D, 0XD189E1FB, 0XE85BD489, 0X73C8D11F, 0X54B5C196, 0XB67CB490, 0X2117E4CA, 0X9DE3F994, 0X2F5AA1AA, 0XA7E801FD, 0XC30D6EAB, 0X1BADDC9C, 0X3453B04A, 0X92A406F9};
unsigned int key[] = {1, 2, 3, 4};
unsigned int sum = 0;
unsigned int y, z, p, rounds, e;
int n = 35; // 35个32位整数
int i = 0;
rounds = 6 + 52 / n;
y = v[0];
sum = (rounds * DELTA) & 0xffffffff; // 取后八位
do
{
e = sum >> 2 & 3;
for (p = n - 1; p > 0; p--) // 34次循环
{
z = v[p - 1];
v[p] = (v[p] - ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((key[(p ^ e) & 3] ^ z) + (y ^ sum)))) & 0xffffffff;
y = v[p];
}
z = v[n - 1];
v[0] = (v[0] - (((key[(p ^ e) & 3] ^ z) + (y ^ sum)) ^ (((y << 2) ^ (z >> 5)) + ((z << 4) ^ (y >> 3))))) & 0xffffffff;
y = v[0];
sum = (sum - DELTA) & 0xffffffff;
} while (--rounds);
for (i = 0; i < n; i++)
{
printf("%c", v[i]);
}
return 0;
}

DES

分组加密算法,明文为64位(8字节)一组,密钥的长度为64位(8字节)(3DES用192位密钥),但每8位中的最后一位用于奇偶校验,实际有效密钥长度为56位

特征识别

  • DES共有8个不同的S盒(S1~S8),每个S盒是一个4行×16列的查找表
  • 多个置换表对数据位进行重新排列:32位P盒、48位E盒、56位PC-1、64位IP/IP⁻¹

代码实现

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
#include <bits/stdc++.h>
using namespace std;

bitset<48> subkey[16];

bitset<64> CharsToBitset(const char str[8]);
string BitsetToString(bitset<64> bits);
bitset<64> IP(bitset<64> &src);
bitset<64> InverseIP(bitset<64> &src);
bitset<56> PCOne(bitset<56> src);
bitset<48> PCTwo(bitset<56> src);
void Subkey(bitset<64> key);
bitset<28> leftShift(bitset<28> temKey, int r);
bitset<32> f(bitset<32> right, bitset<48> subkey);
bitset<48> Expend(bitset<32> src);
bitset<4> SBox(bitset<6> tem, int *sbox);
bitset<32> P(bitset<32> src);
void Decrypt(string &c);
void Encrypt(string &c);

bitset<64> CharsToBitset(const char str[8])
{
bitset<64> bits;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
bits[i * 8 + j] = ((str[i] >> j) & 1);
}
}

return bits;
}

string BitsetToString(bitset<64> bits)
{
char ch[8];
bitset<8> e[8];

for (int i = 0; i < 8; i++)
{
e[0][i] = bits[i];
}
for (int i = 8; i < 16; i++)
{
e[1][i - 8] = bits[i];
}
for (int i = 16; i < 24; i++)
{
e[2][i - 16] = bits[i];
}
for (int i = 24; i < 32; i++)
{
e[3][i - 24] = bits[i];
}
for (int i = 32; i < 40; i++)
{
e[4][i - 32] = bits[i];
;
}
for (int i = 40; i < 48; i++)
{
e[5][i - 40] = bits[i];
}
for (int i = 48; i < 56; i++)
{
e[6][i - 48] = bits[i];
}
for (int i = 56; i < 64; i++)
{
e[7][i - 56] = bits[i];
}
string s;

for (int i = 0; i < 8; i++)
{

int l = e[i].to_ulong();
ch[i] = (char)l;
s = s + ch[i];
}

return s;
}

bitset<64> IP(bitset<64> &src)
{
bitset<64> output;

int IP_TABLE[] = {
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};

for (int i = 0; i < 64; i++)
{
output[63 - i] = src[64 - IP_TABLE[i]];
}

return output;
}

bitset<64> InverseIP(bitset<64> &src)
{
bitset<64> output;

int IIP_TABLE[] = {
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};

for (int i = 0; i < 64; i++)
{
output[63 - i] = src[64 - IIP_TABLE[i]];
}

return output;
}

bitset<56> PCOne(bitset<64> src)
{
bitset<56> output;

int PC1_TABLE[] = {
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};

for (int i = 0; i < 56; i++)
{
output[55 - i] = src[64 - PC1_TABLE[i]];
}

return output;
}
bitset<48> PCTwo(bitset<56> src)
{
bitset<48> output;

int PC2_TABLE[] = {
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};

for (int i = 0; i < 48; i++)
{
output[47 - i] = src[56 - PC2_TABLE[i]];
}

return output;
}

void Subkey(bitset<64> key)
{
bitset<56> realKey;
bitset<28> leftKey;
bitset<28> rightKey;
bitset<48> compressKey;

//PC one
realKey = PCOne(key);

for (int r = 0; r < 16; r++)
{
for (int i = 28; i < 56; i++)
{
leftKey[i - 28] = realKey[i];
}
for (int i = 0; i < 28; i++)
{
rightKey[i] = realKey[i];
}

leftKey = leftShift(leftKey, r);
rightKey = leftShift(rightKey, r);

for (int i = 0; i < 28; i++)
{
realKey[i] = rightKey[i];
}
for (int i = 28; i < 56; i++)
{
realKey[i] = leftKey[i - 28];
}

//PC two
compressKey = PCTwo(realKey);

subkey[r] = compressKey;
}
}

bitset<28> leftShift(bitset<28> temKey, int r)
{
int shift = 0;
bitset<28> tem = temKey;
if (r == 0 || r == 1 || r == 8 || r == 15)
{
shift = 1;
}
else
{
shift = 2;
}
for (int i = 27; i >= 0; i--)
{
if ((i - shift) < 0)
{
tem[i] = temKey[i - shift + 28];
}
else
{
tem[i] = temKey[i - shift];
}
}

return tem;
}

bitset<32> f(bitset<32> right, bitset<48> subkey)
{
int SBox1[] = {
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 15, 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 SBox2[] = {
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 SBox3[] = {
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 SBox4[] = {
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
12, 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 SBox5[] = {
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 SBox6[] = {
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 SBox7[] = {
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 SBox8[] = {
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};

bitset<48> rightExpend;
bitset<6> e1, e2, e3, e4, e5, e6, e7, e8;
bitset<4> sbox1, sbox2, sbox3, sbox4, sbox5, sbox6, sbox7, sbox8;
//Extend
rightExpend = Expend(right);

rightExpend = rightExpend ^ subkey;

for (int i = 0; i < 6; i++)
{
e1[i] = rightExpend[47 - 0 - i];
e2[i] = rightExpend[47 - 6 - i];
e3[i] = rightExpend[47 - 12 - i];
e4[i] = rightExpend[47 - 18 - i];
e5[i] = rightExpend[47 - 24 - i];
e6[i] = rightExpend[47 - 30 - i];
e7[i] = rightExpend[47 - 36 - i];
e8[i] = rightExpend[47 - 42 - i];
}

sbox1 = SBox(e1, SBox1);
sbox2 = SBox(e2, SBox2);
sbox3 = SBox(e3, SBox3);
sbox4 = SBox(e4, SBox4);
sbox5 = SBox(e5, SBox5);
sbox6 = SBox(e6, SBox6);
sbox7 = SBox(e7, SBox7);
sbox8 = SBox(e8, SBox8);

bitset<32> result;

for (int i = 0; i < 4; i++)
{
result[i + 0] = sbox1[i];
result[i + 4] = sbox2[i];
result[i + 8] = sbox3[i];
result[i + 12] = sbox4[i];
result[i + 16] = sbox5[i];
result[i + 20] = sbox6[i];
result[i + 24] = sbox7[i];
result[i + 28] = sbox8[i];
}

bitset<32> temp = result;
for (int i = 0; i < 32; i++)
{
result[i] = temp[31 - i];
}

//P
result = P(result);
return result;
}

bitset<48> Expend(bitset<32> src)
{

bitset<48> output;

int E_TABLE[] = {
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};

for (int i = 0; i < 48; i++)
{
output[47 - i] = src[32 - E_TABLE[i]];
}

return output;
}

bitset<4> SBox(bitset<6> tem, int *sbox)
{

int row = 0, col = 0;
int box = 0;
row = tem[0] * 2 + tem[5];
col = tem[1] * 2 * 2 * 2 + tem[2] * 2 * 2 + tem[3] * 2 + tem[4];

box = sbox[row * 16 + col];

bitset<4> temp(box);
bitset<4> output;
for (int i = 0; i < 4; i++)
{
output[i] = temp[3 - i];
}

return output;
}

bitset<32> P(bitset<32> src)
{
bitset<32> output;

int P_TABLE[] = {
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};

for (int i = 0; i < 32; i++)
{
output[31 - i] = src[32 - P_TABLE[i]];
}

return output;
}

//DES 解密
void Decrypt(string &c)
{
string text = c;
string key;

cout << "Input password:(8 char)" << endl;
cin >> key;
while (key.length() != 8)
{
cout << "Input error( need 8 char )" << endl;
cout << "Input password:(8 char)" << endl;
cin >> key;
}

bitset<64> textBits;
bitset<64> keyBits;
bitset<32> leftBits;
bitset<32> rightBits;
bitset<32> newLeftBits;
bitset<32> newRightBits;
bitset<64> cipher;
bitset<64> tem;

textBits = CharsToBitset(c.c_str());
keyBits = CharsToBitset(key.c_str());
Subkey(keyBits);
cout << "ciph" << textBits.to_string() << endl;
cout << "pass" << keyBits.to_string() << endl;
tem = textBits;
textBits = IP(tem); //IP 置换

for (int i = 32; i < 64; i++)
{
leftBits[i - 32] = textBits[i];
}
for (int i = 0; i < 32; i++)
{
rightBits[i] = textBits[i];
}

//16次迭代
for (int i = 0; i < 16; i++)
{
newLeftBits = rightBits;
newRightBits = leftBits ^ f(rightBits, subkey[15 - i]);
leftBits = newLeftBits;
rightBits = newRightBits;
}

//W 置换
for (int i = 0; i < 32; i++)
{
tem[i] = leftBits[i];
}
for (int i = 32; i < 64; i++)
{
tem[i] = rightBits[i - 32];
}

//IP 逆置换
cipher = InverseIP(tem);
c = cipher.to_string();
cout << "text" << c << endl;
c = BitsetToString(cipher);
cout << "text" << c << endl;
}

//DES 加密
void Encrypt(string &c)
{
string text;
string key;
cout << "Input text:(8 char)" << endl;
cin >> text;
cout << "Input password:(8 char)" << endl;
cin >> key;
while (text.length() != 8 || key.length() != 8)
{
cout << "Input error( need 8 char )" << endl;
cout << "Input text:(8 char)" << endl;
cin >> text;
cout << "Input password:(8 char)" << endl;
cin >> key;
}

bitset<64> textBits;
bitset<64> keyBits;
bitset<32> leftBits;
bitset<32> rightBits;
bitset<32> newLeftBits;
bitset<32> newRightBits;
bitset<64> cipher;
bitset<64> tem;

textBits = CharsToBitset(text.c_str());
keyBits = CharsToBitset(key.c_str());
Subkey(keyBits);

cout << "text" << textBits.to_string() << endl;
cout << "pass" << keyBits.to_string() << endl;
tem = textBits;
textBits = IP(tem); //IP 置换
for (int i = 32; i < 64; i++)
{
leftBits[i - 32] = textBits[i];
}
for (int i = 0; i < 32; i++)
{
rightBits[i] = textBits[i];
}

//16次迭代
for (int i = 0; i < 16; i++)
{
newLeftBits = rightBits;
newRightBits = leftBits ^ f(rightBits, subkey[i]);
leftBits = newLeftBits;
rightBits = newRightBits;
}

//W 置换
for (int i = 0; i < 32; i++)
{
tem[i] = leftBits[i];
}
for (int i = 32; i < 64; i++)
{
tem[i] = rightBits[i - 32];
}

//IP 逆置换
cipher = InverseIP(tem);

c = cipher.to_string();
cout << "ciph" << c << endl;
c = BitsetToString(cipher);
}

int main()
{

string cipher;
Encrypt(cipher);

Decrypt(cipher);
getchar();
system("pause");
return 0;
}

AES

分组加密算法,明文为128位(16字节)一组,密钥的长度有128位(16字节)、192位(24字节)、256位(32字节)三种,分别对应加密轮数为 10、12、14

特征识别

  • 16字节分组,明文长度除以16或者右移4位
  • 256个元素的 S 盒(16x16),例如S盒{0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F……},逆S盒{0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38……}
  • 左移右移 24/16/8 或者 & ff000000,&00ff0000,&0000ff00,&000000ff

加密流程简述

  • 128位明文与拓展密钥进行异或
  • 执行(n-1)轮加密:
    • S 盒变换:使用 S 盒对每个字节进行替换
    • 行变换:对每一行进行循环左移
    • 列变换:对每一列进行线性变换
    • 添加轮密钥:将当前状态与轮密钥进行异或
  • 执行最后一轮加密:
    • S 盒变换
    • 行变换
    • 与拓展密钥进行异或

ECB 模式 和 CBC 模式

  • ECB 模式:
    • 将明文分成固定大小的块,每个块独立加密
    • 相同的明文块加密后生成相同的密文块
    • 不需要初始化向量(IV)。
  • CBC 模式
    • 每个明文块在加密前会与前一个密文块进行异或(XOR),再加密
    • 第一个块需要与初始化向量(IV)异或
    • 相同的明文块加密后生成不同的密文块(依赖前一块的密文)

代码实现

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
#include <bits/stdc++.h>
using namespace std;


typedef bitset<8> byte;
typedef bitset<32> word;

const int Nr = 10;//以 AES-128为例,加密轮数为10
const int Nk = 4; //初始密钥字数(128位=16字节=4字)

byte Sbox[16][16]={
{0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76},
{0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0},
{0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15},
{0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75},
{0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84},
{0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF},
{0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8},
{0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2},
{0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73},
{0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB},
{0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79},
{0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08},
{0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A},
{0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E},
{0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF},
{0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16}
};

byte Inv_Sbox[16][16] = {
{0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB},
{0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB},
{0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E},
{0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25},
{0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92},
{0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84},
{0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06},
{0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B},
{0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73},
{0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E},
{0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B},
{0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4},
{0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F},
{0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF},
{0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61},
{0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D}
};


//轮常数
word Rcon[10]={0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,
0x20000000,0x40000000,0x80000000,0x1B000000,0x36000000};


// S 盒变换-字节替换
void SubBytes(byte mtx[4*4])
{
for(int i=0; i<16; ++i)
{
int row = mtx[i][7]*8 + mtx[i][6]*4 + mtx[i][5]*2 + mtx[i][4];
int col = mtx[i][3]*8 + mtx[i][2]*4 + mtx[i][1]*2 + mtx[i][0];
mtx[i] = Sbox[row][col];
}
}

//行变换-按字节循环移位
void ShiftRows(byte mtx[4*4])
{
// 第二行循环左移一位
byte temp = mtx[4];
for(int i=0; i<3; ++i)
mtx[i+4] = mtx[i+5];
mtx[7] = temp;
// 第三行循环左移两位
for(int i=0; i<2; ++i)
{
temp = mtx[i+8];
mtx[i+8] = mtx[i+10];
mtx[i+10] = temp;
}
// 第四行循环左移三位
temp = mtx[15];
for(int i=3; i>0; --i)
mtx[i+12] = mtx[i+11];
mtx[12] = temp;
}

//有限域上的乘法 GF(2^8)
byte GFMul(byte a, byte b) {
byte p = 0;
byte hi_bit_set;
for (int counter = 0; counter < 8; counter++) {
if ((b & byte(1)) != 0) {
p ^= a;
}
hi_bit_set = (byte) (a & byte(0x80));
a <<= 1;
if (hi_bit_set != 0) {
a ^= 0x1b; /* x^8 + x^4 + x^3 + x + 1 */
}
b >>= 1;
}
return p;
}

//列变换
void MixColumns(byte mtx[4*4])
{
byte arr[4];
for(int i=0; i<4; ++i)
{
for(int j=0; j<4; ++j)
arr[j] = mtx[i+j*4];

mtx[i] = GFMul(0x02, arr[0]) ^ GFMul(0x03, arr[1]) ^ arr[2] ^ arr[3];
mtx[i+4] = arr[0] ^ GFMul(0x02, arr[1]) ^ GFMul(0x03, arr[2]) ^ arr[3];
mtx[i+8] = arr[0] ^ arr[1] ^ GFMul(0x02, arr[2]) ^ GFMul(0x03, arr[3]);
mtx[i+12] = GFMul(0x03, arr[0]) ^ arr[1] ^ arr[2] ^ GFMul(0x02, arr[3]);
}
}

//轮密钥加变换 - 将每一列与扩展密钥进行异或
void AddRoundKey(byte mtx[4*4], word k[4])
{
for(int i=0; i<4; ++i)
{
word k1 = k[i] >> 24;
word k2 = (k[i] << 8) >> 24;
word k3 = (k[i] << 16) >> 24;
word k4 = (k[i] << 24) >> 24;

mtx[i] = mtx[i] ^ byte(k1.to_ulong());
mtx[i+4] = mtx[i+4] ^ byte(k2.to_ulong());
mtx[i+8] = mtx[i+8] ^ byte(k3.to_ulong());
mtx[i+12] = mtx[i+12] ^ byte(k4.to_ulong());
}
}

//解密的逆变换函数
//逆 S 盒变换
void InvSubBytes(byte mtx[4*4])
{
for(int i=0; i<16; ++i)
{
int row = mtx[i][7]*8 + mtx[i][6]*4 + mtx[i][5]*2 + mtx[i][4];
int col = mtx[i][3]*8 + mtx[i][2]*4 + mtx[i][1]*2 + mtx[i][0];
mtx[i] = Inv_Sbox[row][col];
}
}

//逆行变换-以字节为单位循环右移
void InvShiftRows(byte mtx[4*4])
{
// 第二行循环右移一位
byte temp = mtx[7];
for(int i=3; i>0; --i)
mtx[i+4] = mtx[i+3];
mtx[4] = temp;
// 第三行循环右移两位
for(int i=0; i<2; ++i)
{
temp = mtx[i+8];
mtx[i+8] = mtx[i+10];
mtx[i+10] = temp;
}
// 第四行循环右移三位
temp = mtx[12];
for(int i=0; i<3; ++i)
mtx[i+12] = mtx[i+13];
mtx[15] = temp;
}

void InvMixColumns(byte mtx[4*4])
{
byte arr[4];
for(int i=0; i<4; ++i)
{
for(int j=0; j<4; ++j)
arr[j] = mtx[i+j*4];

mtx[i] = GFMul(0x0e, arr[0]) ^ GFMul(0x0b, arr[1]) ^ GFMul(0x0d, arr[2]) ^ GFMul(0x09, arr[3]);
mtx[i+4] = GFMul(0x09, arr[0]) ^ GFMul(0x0e, arr[1]) ^ GFMul(0x0b, arr[2]) ^ GFMul(0x0d, arr[3]);
mtx[i+8] = GFMul(0x0d, arr[0]) ^ GFMul(0x09, arr[1]) ^ GFMul(0x0e, arr[2]) ^ GFMul(0x0b, arr[3]);
mtx[i+12] = GFMul(0x0b, arr[0]) ^ GFMul(0x0d, arr[1]) ^ GFMul(0x09, arr[2]) ^ GFMul(0x0e, arr[3]);
}
}


//密钥拓展
//将4个8位的字节组成一个32位的字
word Word (byte&k1,byte&k2,byte&k3,byte&k4){
word result(0x00000000);
word temp;
temp=k1.to_ulong();
temp<<=24;
result|=temp;
temp=k2.to_ulong();
temp<<=16;
result|=temp;
temp=k3.to_ulong();
temp<<=8;
result|=temp;
temp=k4.to_ulong();
result|=temp;
return result;
}

//把一个4字节的word中的字节左移一位
//[a,b,c,d]=>[b,c,d,a]
word RotWord(const word&rw){
word high=rw<<8;
word low=rw>>24;
return high|low;
}

//对输入word中的每一个字节进行S盒变换
word SubWord(const word& sw){
word temp;
for(int i=0;i<32;i+=8){
int row=sw[i+7]*8+sw[i+6]*4+sw[i+5]*2+sw[i+4];
int col=sw[i+3]*8+sw[i+2]*4+sw[i+1]*2+sw[i];
byte val =Sbox[row][col];
for(int j=0;j<8;++j){
temp[i+j]=val[j];
}
}
return temp;
}

//密钥扩展函数-对128位密钥拓展得到 w[4*(Nr+1)]
void KeyExpansion(byte key[4*Nk],word w[4*(Nr+1)]){
word temp;
int i=0;

while(i<Nk){
// w[]的前4个就是输入的key
w[i]=Word(key[4*i],key[4*i+1],key[4*i+2],key[4*i+3]);
++i;
}

i=Nk;
while(i<4*(Nr+1)){
temp=w[i-1]; // 记录前一个word
if(i%Nk==0)
w[i]=w[i-Nk]^SubWord(RotWord(temp))^Rcon[i/Nk-1];
else
w[i]=w[i-Nk]^temp;
++i;
}
}


//加解密函数
//加密
void encrypt(byte in[4*4], word w[4*(Nr+1)])
{
word key[4];
for(int i=0; i<4; ++i)
key[i] = w[i];
AddRoundKey(in, key);

for(int round=1; round<Nr; ++round)
{
SubBytes(in);
ShiftRows(in);
MixColumns(in);
for(int i=0; i<4; ++i)
key[i] = w[4*round+i];
AddRoundKey(in, key);
}

SubBytes(in);
ShiftRows(in);
for(int i=0; i<4; ++i)
key[i] = w[4*Nr+i];
AddRoundKey(in, key);
}

//解密
void decrypt(byte in[4*4], word w[4*(Nr+1)])
{
word key[4];
for(int i=0; i<4; ++i)
key[i] = w[4*Nr+i];
AddRoundKey(in, key);

for(int round=Nr-1; round>0; --round)
{
InvShiftRows(in);
InvSubBytes(in);
for(int i=0; i<4; ++i)
key[i] = w[4*round+i];
AddRoundKey(in, key);
InvMixColumns(in);
}

InvShiftRows(in);
InvSubBytes(in);
for(int i=0; i<4; ++i)
key[i] = w[i];
AddRoundKey(in, key);
}


//test
int main(){
byte key[16] = {0x2b, 0x7e, 0x15, 0x16,
0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c};

byte plain[16] = {0x32, 0x88, 0x31, 0xe0,
0x43, 0x5a, 0x31, 0x37,
0xf6, 0x30, 0x98, 0x07,
0xa8, 0x8d, 0xa2, 0x34};
//输出密钥
cout<<"key is: ";
for(int i=0;i<16;++i){
cout<<hex<<key[i].to_ulong()<<" ";
}
cout<<endl;

word w[4*(Nr+1)];
KeyExpansion(key, w);

//输出待加密的明文
cout<<"plaintext is: "<<endl;
for(int i=0; i<16; ++i)
{
cout << hex << plain[i].to_ulong() << " ";
if((i+1)%4 == 0)
cout << endl;
}
cout << endl;

//加密
encrypt(plain, w);
//输出加密后的密文
cout<<"encodetext is: "<<endl;
for(int i=0; i<16; ++i)
{
cout << hex << plain[i].to_ulong() << " ";
if((i+1)%4 == 0)
cout << endl;
}
cout << endl;

//解密
decrypt(plain, w);
//输出解密后的明文
cout<<"decodetext is: "<<endl;
for(int i=0; i<16; ++i)
{
cout << hex << plain[i].to_ulong() << " ";
if((i+1)%4 == 0)
cout << endl;
}
cout << endl;
return 0;
}

SM4

  • 明文分组长度为128位,密钥长度为128位
  • 16x16的S盒
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static const unsigned char SboxTable[16][16] =
{
{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}
};

RE中的密码学
http://example.com/2025/05/02/crypto/
作者
Eleven
发布于
2025年5月2日
许可协议