AES加密和解密流程
6600 Words|Read in about 31 Min|本文总阅读量次
AES (Advanced Encryption Standard)是一种区块加密标准算法,它的提出是为了升级替换原有的DES加密算法。因此它的安全强度高于DES算法。
1简介
AES的加密模式
AES的加密模式 | 说明 |
---|---|
密钥长度 | AES128 、AES192 、AES256 |
加密模式 | ECB 、CBC 、CFB 、OFB 、CTR 、CCM 、GCM 、XTS |
填充模式 | NONE 、PKCS7 、ZERO 、ANS1923 、ISO7816_4 、ISO10126 |
现在的加密库一般会提供一些默认值,所以用户使用AES加密的时候,并没有去做这方面的配置。
密钥长度
这些密钥长度是以bit为单位的,一个字节为8个bit,所以128对应是16个字节,192对应24个字节,256对应是32个字节。
AES128
规定用于的秘钥是16个字节,超过16个字节,它不会被使用就当做没看见(截断处理)
然后,会把整个数据分成四行四列
AES192
AES256
以AES-256为例,假如现在我们想破解它,其难易程度如何呢?2^256^就是256位AES的密钥空间的组合数,远大于地球所有沙子的总数量(3×10^23)^。2^256^ > 2^(1025)^ > 10^(325)^=10^75^»3×10^23^。现在问题来了:假设你能够把每一粒沙子做出一个存储设备,存一个值。你只能存储3*10^23^*个不同的答案。而你没法全部试一遍,这样破解难度依靠现有技术资源和时间长度,几乎是无法进行计算破解,难度系数等同于不可能。
加密模式
AES有很多加密模式,其中ECB是最经典的加密模式,其他很多模式都是通过ECB改变过来的,本文主要以ECB为主,后续顺带说一下CBC的加密模式。
填充模式
AES加密数据是以16字节为一组进行分组加密。要求明文的长度一定要是16个字节的倍数。如果不够16个字节的倍数的话,需要填充至16个字节倍数。
填充模式注意事项
除了NONE模式填充以外的任何填充模式下,就算原始明文长度已经是16个字节的倍数,也一定要进行填充
AES排列方式
在AES当中,它的排列方式是以列从上往下进行排列的,如下图所示
1加密
1.1加密流程
1.2加密器内部流程
AES128加密器(10轮)
AES192加密器(12轮)
AES256加密器(14轮)
1.3秘钥扩展
秘钥扩展就是把用户输入的(16/24/32)字节的秘钥扩展到(176,208,240)字节的轮秘钥。通俗的来讲,将用户输入的秘钥,扩展成比较长的秘钥。
176/208/240这三个数是怎么来的
(
11*16 = 176
),(13*16 = 208
),(15*16 = 240
)
nk值(秘钥的列数)
AES128的nk值为4(16/4=4)
AES192的nk值为6(24/4=6)
AES256的nk值为8(32/4=8)
1.4秘钥扩展公式
这里以秘钥是0102030405060708090A0B0C0D0E0F10为例子
1.4.1情况1
情况1:[当前列] % nk值 == 0
1公式:[当前列-nk值] ⊕ 轮常量异或(字节代换(列位移([当前列-1])))
其中涉及到了字节代换表
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 63 | 7C | 77 | 7B | F2 | 6B | 6F | C5 | 30 | 01 | 67 | 2B | FE | D7 | AB | 76 |
1 | CA | 82 | C9 | 7D | FA | 59 | 47 | F0 | AD | D4 | A2 | AF | 9C | A4 | 72 | C0 |
2 | B7 | FD | 93 | 26 | 36 | 3F | F7 | CC | 34 | A5 | E5 | F1 | 71 | D8 | 31 | 15 |
3 | 04 | C7 | 23 | C3 | 1 | 96 | 05 | 9A | 07 | 12 | 80 | E2 | EB | 27 | B2 | 75 |
4 | 09 | 83 | 2C | 1A | 1B | 6E | 5A | A0 | 52 | 3B | D6 | B3 | 29 | E3 | 2F | 84 |
5 | 53 | D1 | 00 | ED | 20 | FC | B1 | 5B | 6A | CB | BE | 39 | 4A | 4C | 58 | CF |
6 | D0 | EF | AA | FB | 43 | 4D | 33 | 85 | 45 | F9 | 02 | 7F | 50 | 3C | 9F | A8 |
7 | 51 | A3 | 40 | 8F | 92 | 9D | 38 | F5 | BC | B6 | DA | 21 | 10 | FF | F3 | D2 |
8 | CD | 0C | 13 | EC | 5F | 97 | 44 | 17 | C4 | A7 | 7E | 3D | 64 | 5D | 19 | 73 |
9 | 60 | 81 | 4F | DC | 22 | 2A | 90 | 88 | 46 | EE | B8 | 14 | DE | 5E | 0B | DB |
A | E0 | 32 | 3A | 0A | 49 | 06 | 24 | 5C | C2 | D3 | AC | 62 | 91 | 95 | E4 | 79 |
B | E7 | C8 | 37 | 6D | 8D | D5 | 4E | A9 | 6C | 56 | F4 | EA | 65 | 7A | AE | 08 |
C | BA | 78 | 25 | 2E | 1C | A6 | B4 | C6 | E8 | DD | 74 | 1F | 4B | BD | 8B | 8A |
D | 70 | 3E | B5 | 66 | 48 | 03 | F6 | 0E | 61 | 35 | 57 | B9 | 86 | C1 | 1D | 9E |
E | E1 | F8 | 98 | 11 | 69 | D9 | 8E | 94 | 9B | 1E | 87 | E9 | CE | 55 | 28 | DF |
F | 8C | A1 | 89 | 0D | BF | E6 | 42 | 68 | 41 | 99 | 2D | 0F | B0 | 54 | BB | 16 |
另外,还有常量轮值表
01 | 02 | 04 | 08 | 10 | 20 | 40 | 80 | 1B | 36 | 6C | db | ab | 4d |
---|
1.4.1.1AES128
对于AES128而言,10轮循环,每轮循环正好对应一次常量轮值表中的元素
[当前列] % nk值 == 0,这里的nk值为4,所以就是04的倍数,总共扩展16*16*10
的大小
104,08,0C,10,14,18,1C,20,24,28
1第04列计算
2当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
30D 0E AB AB ⊕ 01 =AA 01 = AB
40E 0F 76 76 02 = 74
50F 10 CA CA 03 = C9
610 0D D7 D7 04 = D3
7第08列计算
8当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
9AA 76 38 38 ⊕ 02 = 3A AB = 91
1076 CA 74 74 74 = 0
11CA C7 C6 C6 C9 = 0F
12C7 AA AC AC D3 = 7F
13第0C列计算
14当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
1532 7C 10 10 ⊕ 04 = 14 91 = 85
167C CE 8B 8B 0 = 8B
17CE B4 8D 8D 0F = 82
18B4 32 23 23 7F = 5C
19第10列计算
20当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
2110 8F 73 73 ⊕ 08 = 7B 85 = FE
228F 89 A7 A7 8B = 2C
2389 3F 75 75 82 = F7
243F 10 CA CA 5C = 96
25第14列计算
26当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
2776 A9 D3 D3 ⊕ 10 = C3 FE = 3D
28A9 7A DA DA 2C = F6
297A DA 57 57 F7 = A0
30DA 76 38 38 96 = AE
31第18列计算
32当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
3369 AC 91 91 ⊕ 20 = B1 3D = 8C
34AC 9D 5E 5E F6 = A8
359D FF 16 16 A0 = B6
36FF 69 F9 F9 AE = 57
37第1C列计算
38当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
3983 22 93 93 ⊕ 40 = D3 8C = 5F
4022 D8 61 61 A8 = C9
41D8 4D E3 E3 B6 = 55
424D 83 EC EC 57 = BB
43第20列计算
44当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
45C3 EE 28 28 ⊕ 80 = A8 5F = F7
46EE 6A 02 02 C9 = CB
476A D3 66 66 55 = 33
48D3 C3 2E 2E BB = 95
49第24列计算
50当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
51DE AB 62 62 ⊕ 1B = 79 F7 = 8E
52AB 1C 9C 9C CB = 57
531C F4 BF BF 33 = 8C
54F4 DE 1D 1D 95 = 88
55第28列计算
56当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
5710 30 04 04 ⊕ 36 = 32 8E = BC
5830 22 93 93 57 = C4
5922 E2 98 98 8C = 14
60E2 10 CA CA 88 = 42
1.4.1.2AES256
同理,对于对于AES256而言,14轮循环,每轮循环正好对应一次常量轮值表中的元素
因为本身AES256就有16*16*2
的大小,所以需要拓展16*16*13
的大小
[当前列] % nk值 == 0,这里的nk值为8,所以就是08的倍数,这里扩展16*16*7
的大小
108,10,18,20,28,30,38
1第08列计算
2当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
31D 1E 72 72 ⊕ 01 = 73 01 = 72
41E 1F C0 C0 02 = C2
51F 20 B7 B7 03 = B4
620 1D A4 A4 04 = A0
7第10列计算
8当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
98F BA F4 F4 ⊕ 02 = F6 72 = 84
10BA A9 D3 D3 C2 = 11
11A9 BD 7A 7A B4 = CE
12BD 8F 73 73 A0 = D3
13第18列计算
14当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
15B3 B1 C8 C8 ⊕ 04 = CC 84 = 48
16B1 48 52 52 11 = 43
1748 47 A0 A0 CE = 6E
1847 B3 6D 6D D3 = BE
19第20列计算
20当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
21EC B5 D5 D5 ⊕ 08 = DD 48 = 95
22B5 4D E3 E3 43 = A0
234D 9F DB DB 6E = B5
249F EC CE CE BE = 70
25第28列计算
26当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
276D 4B B3 B3 ⊕ 10 = A3 95 = 36
284B 57 5B 5B A0 = FB
2957 3D 27 27 B5 = 92
303D 6D 3C 3C 70 = 4C
31第30列计算
32当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
33FF AE E4 E4 ⊕ 20 = C4 36 = F2
34AE C9 DD DD FB = 26
35C9 79 B6 B6 92 = 24
3679 FF 16 16 4C = 5A
37第38列计算
38当前列-1 列位移 字节代换 轮常量异或 异或当前列-nk
3933 DE 1D 1D ⊕ 40 = 5D F2 = AF
40DE 54 20 20 26 = 06
4154 B8 6C 6C 24 = 48
42B8 33 C3 C3 5A = 99
1.4.2情况2
情况2比较特殊,只有在AES256存在。
情况2:在AES256中,[当前列]%nk值 != 0 && [当前列]%4 == 0
1公式:[当前列-nk值] ⊕ 字节代换([当前列-1])
[当前列]%nk值 != 0 && [当前列]%4 == 0,这里的nk值为8,所以就是08的倍数,这里扩展16*16*6
的大小
10C,14,1C,24,2C,34
1第0C列计算
2当前列-1 字节代换 异或当前列-nk
373 8F 11 = 9E
4C0 BA 12 = A8
5B7 A9 13 = BA
6B4 8D 14 = 99
7第14列计算
8当前列-1 字节代换 异或当前列-nk
9FE BB 9E = 25
10DB B9 A8 = 11
1172 40 BA = FA
126B 7F 99 = E6
13第1C列计算
14当前列-1 字节代换 异或当前列-nk
15C8 E8 25 = CD
1656 B1 11 = A0
17A4 49 FA = B3
1871 A3 E6 = 45
19第24列计算
20当前列-1 字节代换 异或当前列-nk
21D0 70 CD = BD
22ED 55 A0 = F5
23D4 48 B3 = FB
24DE 1D 45 = 58
25第2C列计算
26当前列-1 字节代换 异或当前列-nk
27D0 70 BD = CD
289B 14 F5 = E1
2990 60 FB = 9B
3088 C4 58 = 9C
31第34列计算
32当前列-1 字节代换 异或当前列-nk
333A 80 CD = 4D
3406 6F E1 = 8E
35C4 1C 9B = 87
367D FF 9C = 63
1.4.3情况3
情况3,不属于情况1和情况2的其余情况
1公式:[当前列-nk值] ⊕ [当前列-1]
1.4.3.1AES128
1第05列计算
2当前列-1 异或当前列-nk
3AB 05 = AE
474 06 = 72
5C9 07 = CE
6D3 08 = DB
7第06列计算
8当前列-1 异或当前列-nk
9AE 09 = A7
1072 0A = 78
11CE 0B = C5
12DB 0C = D7
13第07列计算
14当前列-1 异或当前列-nk
15A7 0D = AA
1678 0E = 76
17C5 0F = CA
18D7 10 = C7
19
20第09列计算
21当前列-1 异或当前列-nk
2291 AE = 3F
2300 72 = 72
240F CE = C1
257F DB = A4
26第0A列计算
27当前列-1 异或当前列-nk
283F A7 = 98
2972 78 = 0A
30C1 C5 = 04
31A4 D7 = 73
32第0B列计算
33当前列-1 异或当前列-nk
3498 AA = 32
350A 76 = 7C
3604 CA = CE
3773 C7 = 84
38
39第0D列计算
40当前列-1 异或当前列-nk
4185 3F = BA
428B 72 = F9
4382 C1 = 43
445C A4 = F8
45第0E列计算
46当前列-1 异或当前列-nk
47BA 98 = 22
48F9 0A = F3
4943 04 = 47
50F8 73 = 8B
51第0F列计算
52当前列-1 异或当前列-nk
5322 32 = 10
54F3 7C = 8F
5547 CE = 89
568B B4 = 3F
57
58第11列计算
59当前列-1 异或当前列-nk
60FE BA = 44
612C F9 = D5
62F7 43 = B4
6396 F8 = 6E
64第12列计算
65当前列-1 异或当前列-nk
6644 22 = 66
67D5 F3 = 26
68B4 47 = F3
696E 8B = E5
70第13列计算
71当前列-1 异或当前列-nk
7266 10 = 76
7326 8F = A9
74F3 89 = 7A
75E5 3F = DA
76
77第15列计算
78当前列-1 异或当前列-nk
793D 44 = 79
80F6 D5 = 23
81A0 B4 = 14
82AE 6E = C0
83第16列计算
84当前列-1 异或当前列-nk
8579 66 = 1F
8623 26 = 05
8714 F3 = E7
88C0 E5 = 25
89第17列计算
90当前列-1 异或当前列-nk
911F 76 = 69
9205 A9 = AC
93E7 7A = 9D
9425 DA = FF
95
96第19列计算
97当前列-1 异或当前列-nk
988C 79 = F5
99A8 23 = 8B
100B6 14 = A2
10157 C0 = 97
102第1A列计算
103当前列-1 异或当前列-nk
104F5 1F = EA
1058B 05 = 8E
106A2 E7 = 45
10797 25 = B2
108第1B列计算
109当前列-1 异或当前列-nk
110EA 69 = 83
1118E AC = 22
11245 9D = D8
113B2 FF = 4D
114
115第1D列计算
116当前列-1 异或当前列-nk
1175F F5 = AA
118C9 8B = 42
11955 A2 = F7
120BB 97 = 2C
121第1E列计算
122当前列-1 异或当前列-nk
123AA EA = 40
12442 8E = CC
125F7 45 = B2
1262C B2 = 9E
127第1F列计算
128当前列-1 异或当前列-nk
12940 83 = C3
130CC 22 = EE
131B2 D8 = 6A
1329E 4D = D3
133
134第21列计算
135当前列-1 异或当前列-nk
136F7 AA = 5D
137CB 42 = 89
13833 F7 = C4
13995 2C = B9
140第22列计算
141当前列-1 异或当前列-nk
1425D 40 = 1D
14389 CC = 45
144C4 B2 = 76
145B9 9E = 27
146第23列计算
147当前列-1 异或当前列-nk
1481D C3 = DE
14945 EE = AB
15076 6A = 1C
15127 D3 = F4
152
153第25列计算
154当前列-1 异或当前列-nk
1558E 5D = D3
15657 89 = DE
1578C C4 = 48
15888 B9 = 31
159第26列计算
160当前列-1 异或当前列-nk
161D3 1D = CE
162DE 45 = 9B
16348 76 = 3E
16431 27 = 16
165第27列计算
166当前列-1 异或当前列-nk
167CE DE = 10
1689B AB = 30
1693E 1C = 22
17016 F4 = E2
171
172第29列计算
173当前列-1 异或当前列-nk
174BC D3 = 6F
175C4 DE = 1A
17614 48 = 5C
17742 31 = 73
178第2A列计算
179当前列-1 异或当前列-nk
1806F CE = A1
1811A 9B = 81
1825C 3E = 62
18373 16 = 65
184第2B列计算
185当前列-1 异或当前列-nk
186A1 10 = B1
18781 30 = B1
18862 22 = 40
18965 E2 = 87
1.4.3.2AES256
1第09列计算
2当前列-1 异或当前列-nk
372 05 = 77
4C2 06 = C4
5B4 07 = B3
6A0 08 = A8
7第0A列计算
8当前列-1 异或当前列-nk
977 09 = 7E
10C4 0A = CE
11B3 0B = B8
12A8 0C = A4
13第0B列计算
14当前列-1 异或当前列-nk
157E 0D = 73
16CE 0E = C0
17B8 0F = B7
18A4 10 = B4
19
20第0D列计算
21当前列-1 异或当前列-nk
229E 15 = 8B
23A8 16 = 8E
24BA 17 = AD
2599 18 = 81
26第0E列计算
27当前列-1 异或当前列-nk
288B 19 = 92
298E 1A = A4
30AD 1B = B6
3181 1C = 9D
32第0F列计算
33当前列-1 异或当前列-nk
3492 1D = 8F
35A4 1E = BA
36B6 1F = A9
379D 20 = BD
38
39第11列计算
40当前列-1 异或当前列-nk
4184 77 = F3
4211 C4 = D5
43CE B3 = 7D
44D3 A8 = 7B
45第12列计算
46当前列-1 异或当前列-nk
47F3 7E = 8D
48D5 CE = 1B
497D B8 = C5
507B A4 = DF
51第13列计算
52当前列-1 异或当前列-nk
538D 73 = FE
541B 70 = DB
55C5 B7 = 72
56DF B4 = 6B
57
58第15列计算
59当前列-1 异或当前列-nk
6025 8B = AE
6111 8E = AF
62FA AD = 57
63E6 81 = 67
64第16列计算
65当前列-1 异或当前列-nk
66AE 92 = 3C
67AF A4 = 0B
6857 B6 = E1
6967 9D = FA
70第17列计算
71当前列-1 异或当前列-nk
723C 8F = B3
730B BA = B1
74E1 A9 = 48
75FA BD = 47
76
77第19列计算
78当前列-1 异或当前列-nk
7948 F3 = BB
8043 D5 = 96
816E 7D = 13
82BE 7B = C5
83第1A列计算
84当前列-1 异或当前列-nk
85BB 8D = 36
8696 1B = 8D
8713 C5 = D6
88C5 DF = 1A
89第1B列计算
90当前列-1 异或当前列-nk
9136 FE = C8
928D DB = 56
93D6 72 = A4
941A 6B = 71
95
96第1D列计算
97当前列-1 异或当前列-nk
98CD AE = 63
99A0 AF = 0F
100B3 57 = E4
10145 67 = 22
102第1E列计算
103当前列-1 异或当前列-nk
10463 3C = 5F
1050F 0B = 04
106E4 E1 = 05
10722 FA = D8
108第1F列计算
109当前列-1 异或当前列-nk
1105F B3 = EC
11104 B1 = B5
11205 48 = 4D
113D8 47 = 9F
114
115第21列计算
116当前列-1 异或当前列-nk
11795 BB = 2E
118A0 96 = 36
119B5 13 = A6
12070 C5 = B5
121第22列计算
122当前列-1 异或当前列-nk
1232E 36 = 18
12436 8D = BB
125A6 D6 = 70
126B5 1A = AF
127第23列计算
128当前列-1 异或当前列-nk
12918 C8 = D0
130BB 56 = ED
13170 A4 = D4
132AF 71 = DE
133
134第25列计算
135当前列-1 异或当前列-nk
136BD 63 = DE
137F5 0F = FA
138FB E4 = 1F
13958 22 = 7A
140第26列计算
141当前列-1 异或当前列-nk
142DE 5F = 81
143FA 04 = FE
1441F 05 = 1A
1457A DB = A2
146第27列计算
147当前列-1 异或当前列-nk
14881 EC = 6D
149FE B5 = 4B
1501A 4D = 57
151A2 9F = 3D
152
153第29列计算
154当前列-1 异或当前列-nk
15536 2E = 18
156FB 36 = CD
15792 A6 = 34
1584C B5 = F9
159第2A列计算
160当前列-1 异或当前列-nk
16118 18 = 00
162CD BB = 76
16334 70 = 44
164F9 AF = 56
165第2B列计算
166当前列-1 异或当前列-nk
16700 D0 = D0
16876 ED = 9B
16944 D4 = 90
17056 DE = 88
171
172第2D列计算
173当前列-1 异或当前列-nk
174CD DE = 13
175E1 FA = 1B
1769B 1F = 84
1779C 7A = E6
178第2E列计算
179当前列-1 异或当前列-nk
18013 81 = 92
1811B FE = E5
18284 1A = 9E
183E6 A2 = 44
184第2F列计算
185当前列-1 异或当前列-nk
18692 6D = FF
187E5 4B = AE
1889E 57 = C9
18944 3D = 79
190
191第31列计算
192当前列-1 异或当前列-nk
193F2 18 = EA
19426 CD = EB
19524 34 = 10
1965A F9 = A3
197第32列计算
198当前列-1 异或当前列-nk
199EA 00 = EA
200EB 76 = 9D
20110 44 = 54
202A3 56 = F5
203第33列计算
204当前列-1 异或当前列-nk
205EA D0 = 3A
2069D 9B = 06
20754 90 = C4
208F5 88 = 7D
209
210第35列计算
211当前列-1 异或当前列-nk
2124D 13 = 5E
2138E 1B = 95
21487 84 = 03
21563 E6 = 85
216第36列计算
217当前列-1 异或当前列-nk
2185E 92 = CC
21995 E5 = 70
22003 9E = 9D
22185 44 = C1
222第37列计算
223当前列-1 异或当前列-nk
224CC FF = 33
22570 AE = DE
2269D C9 = 54
227C1 79 = B8
228
229第39列计算
230当前列-1 异或当前列-nk
231AF EA = 45
23206 EB = ED
23348 10 = 58
23499 A3 = 3A
235第3A列计算
236当前列-1 异或当前列-nk
23745 EA = AF
238ED 9D = 70
23958 54 = 0C
2403A F5 = CF
241第3B列计算
242当前列-1 异或当前列-nk
243AF 3A = 95
24470 06 = 76
2450C C4 = C8
246CF 7D = B2
1.5轮密钥加
轮秘钥加有两个参数,分别为明文和轮秘钥
对输入数组(16个字节)和轮秘钥的其中16个字节进行异或运算
。
1.5.1AES128
对于AES128而言,正好需要11次轮密钥加跟上述的秘钥拓展对应上了。
对于轮秘钥的选择
1.5.2AES256
对于AES256而言,正好需要15次轮密钥加跟上述的秘钥拓展对应上了。
对于轮秘钥的选择
1.6字节代换
字节代换就是通过字节代换表来替换其中的字符数字
下面为字节代换表
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 63 | 7C | 77 | 7B | F2 | 6B | 6F | C5 | 30 | 01 | 67 | 2B | FE | D7 | AB | 76 |
1 | CA | 82 | C9 | 7D | FA | 59 | 47 | F0 | AD | D4 | A2 | AF | 9C | A4 | 72 | C0 |
2 | B7 | FD | 93 | 26 | 36 | 3F | F7 | CC | 34 | A5 | E5 | F1 | 71 | D8 | 31 | 15 |
3 | 04 | C7 | 23 | C3 | 01 | 96 | 05 | 9A | 07 | 12 | 80 | E2 | EB | 27 | B2 | 75 |
4 | 09 | 83 | 2C | 1A | 1B | 6E | 5A | A0 | 52 | 3B | D6 | B3 | 29 | E3 | 2F | 84 |
5 | 53 | D1 | 00 | ED | 20 | FC | B1 | 5B | 6A | CB | BE | 39 | 4A | 4C | 58 | CF |
6 | D0 | EF | AA | FB | 43 | 4D | 33 | 85 | 45 | F9 | 02 | 7F | 50 | 3C | 9F | A8 |
7 | 51 | A3 | 40 | 8F | 92 | 9D | 38 | F5 | BC | B6 | DA | 21 | 10 | FF | F3 | D2 |
8 | CD | 0C | 13 | EC | 5F | 97 | 44 | 17 | C4 | A7 | 7E | 3D | 64 | 5D | 19 | 73 |
9 | 60 | 81 | 4F | DC | 22 | 2A | 90 | 88 | 46 | EE | B8 | 14 | DE | 5E | 0B | DB |
A | E0 | 32 | 3A | 0A | 49 | 06 | 24 | 5C | C2 | D3 | AC | 62 | 91 | 95 | E4 | 79 |
B | E7 | C8 | 37 | 6D | 8D | D5 | 4E | A9 | 6C | 56 | F4 | EA | 65 | 7A | AE | 08 |
C | BA | 78 | 25 | 2E | 1C | A6 | B4 | C6 | E8 | DD | 74 | 1F | 4B | BD | 8B | 8A |
D | 70 | 3E | B5 | 66 | 48 | 03 | F6 | 0E | 61 | 35 | 57 | B9 | 86 | C1 | 1D | 9E |
E | E1 | F8 | 98 | 11 | 69 | D9 | 8E | 94 | 9B | 1E | 87 | E9 | CE | 55 | 28 | DF |
F | 8C | A1 | 89 | 0D | BF | E6 | 42 | 68 | 41 | 99 | 2D | 0F | B0 | 54 | BB | 16 |
举例说明
1.7行位移
行位移规则
1第一行不变
2第二行向左循环移动1字节
3第三行向做循环移动2字节
4第四行向左循环移动3字节
举例说明
1.8列混淆
列混淆是加密过程中最复杂的一块
1公式:使用GF(2^8)对[列混淆左乘矩阵的行]与[当前字节的列]进行矩阵乘法
举例说明
1上述计算
2[x1,y1] = 0x02 × [x1,y1] ⊕ 0x03 × [x2,y1] ⊕ 0x01 × [x3,y1] ⊕ 0x01 × [x4,y1]
3[x2,y1] = 0x01 × [x1,y1] ⊕ 0x02 × [x2,y1] ⊕ 0x03 × [x3,y1] ⊕ 0x01 × [x4,y1]
4[x3,y3] = 0x01 × [x1,y3] ⊕ 0x01 × [x2,y3] ⊕ 0x02 × [x3,y3] ⊕ 0x03 × [x4,y3]
5[x1,y1] = 0x01 × [x1,y4] ⊕ 0x01 × [x2,y4] ⊕ 0x02 × [x3,y4] ⊕ 0x03 × [x4,y4]
在GF(2^8)中加法和乘法是不一样的
1.加法操作
直接改成异或操作,a+b 等效为 a ⊕ b
2.乘法操作
2.1.定义一个函数f(a)
如果a小于0x80,则返回2*a
否则返货((2*a)mod 0x100) ⊕ 0x1B
2.2乘法操作中的其中一个数值是2的N次方,则可以套用以下公式
10x01 × a = a 20x02 × a = f(a) 30x04 × a = f(0x02 × a) 40x08 × a = f(0x04 × a) 50x10 × a = f(0x08 × a) 6...
2.3.非2的次方可以拆分后相加(这里的相加操作依然为异或操作)
例子
10x0D × a = (0x08 × a) ⊕ (0x04 × a) ⊕ (0x01 × a) = f(0x04 × a)⊕ f(0x02 × a)⊕ a 20x0D × a = (0x08 × a) ⊕ (0x04 × a) ⊕ (0x02 × a) = f(0x04 × a)⊕ f(0x02 × a)⊕ f(a)
直接计算实际例子
1以前面例子中的[x3,y1]为例
2[x3,y1] = 0x01 × [x1,y1] ⊕ 0x01 × [x2,y1] ⊕ 0x02 × [x3,y1] ⊕ 0x03 × [x4,y1]
3= 0x01 × 0x3B ⊕ 0x01 × 0xF7 ⊕ 0x02 × 0xA8 ⊕ 0x03 × 0xB7
40x01 × 0x3B = 0x3B
50x01 × 0xF7 = 0xF7
60x02 × 0xA8 = f(0xA8) = ((2*0xA8)mod 0x100) ⊕ 0x1B = 0x50 ⊕ 0x1B = 0x4B
70x03 × 0xB7 = f(0xB7) ⊕ 0xB7 = ((2*0xB7)mod 0x100) ⊕ 0x1B ⊕ 0xB7 = 0x75 ⊕ 0xB7 = 0xC2
8[x3,y1] = 0x3B ⊕ 0xF7 ⊕ 0x4B ⊕ 0xC2 = 0x45
9再举例[x2,y4]
10[x2,y4] = 0x01 × [x1,y4] ⊕ 0x02 × [x2,y4] ⊕ 0x03 × [x3,y4] ⊕ 0x01 × [x4,y4]
11= 0x01 × 0x27 ⊕ 0x02 × 0x85 ⊕ 0x03 × 0x53 ⊕ 0x01 × 0xD8
120x01 × 0x27 = 0x27
130x02 × 0x85 = f(0x85) = ((2*0x85)mod 0x100) ⊕ 0x1B = A ⊕ 0x1B = 0x11
140x03 × 0x53 = f(0x53) ⊕ 0x53 = (2*0x53) ⊕ 0x53 = A6 ⊕ 0x53 = 0xF5
150x01 × 0xD8 = 0xD8
16[x2,y4] = 0x27 ⊕ 0x11 ⊕ 0xF5 ⊕ 0xD8 = 1B
1.9加密演示
在线AES加减密链接(https://the-x.cn/cryptography/Aes.aspx)
这里的明文是Hello World!,补充为0
密文是Password,补充为0
1.9.1秘钥扩展
1.9.2加密
1.9.2.1第0轮
第0轮只有轮密钥加
第一轮
第二轮
第三轮
第四轮
第五轮
第六轮
第七轮
第八轮
第九轮
第十轮(没有列混淆)
2解密
解密和加密的区别只在于
- 执行顺序相反
- 字节代换的表不一样
- 行位移由加密的向左移动改成解密的向右移动
- 列混淆的左乘数组不一样
里面的解密器流程如下
和加密的流程正好相反
2.1解密的字节代换表
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 52 | 09 | 6A | D5 | 30 | 36 | A5 | 38 | BF | 40 | A3 | 9E | 81 | F3 | D7 | FB |
1 | 7C | E3 | 39 | 82 | 9B | 2F | FF | 87 | 34 | 8E | 43 | 44 | C4 | DE | E9 | CB |
2 | 54 | 7B | 94 | 32 | A6 | C2 | 23 | 3D | EE | 4C | 95 | 0B | 42 | FA | C3 | 4E |
3 | 08 | 2E | A1 | 66 | 28 | D9 | 24 | B2 | 76 | 5B | A2 | 49 | 6D | 8B | D1 | 25 |
4 | 72 | F8 | F6 | 64 | 86 | 68 | 98 | 16 | D4 | A4 | 5C | CC | 5D | 65 | B6 | 92 |
5 | 6C | 70 | 48 | 50 | FD | ED | B9 | DA | 5E | 15 | 46 | 57 | A7 | 8D | 9D | 84 |
6 | 90 | D8 | AB | 00 | 8C | BC | D3 | 0A | F7 | E4 | 58 | 05 | B8 | B3 | 45 | 06 |
7 | D0 | 2C | 1E | 8F | CA | 3F | 0F | 02 | C1 | AF | BD | 03 | 01 | 13 | 8A | 6B |
8 | 3A | 91 | 11 | 41 | 4F | 67 | DC | EA | 97 | F2 | CF | CE | F0 | B4 | E6 | 73 |
9 | 96 | AC | 74 | 22 | E7 | AD | 35 | 85 | E2 | F9 | 37 | E8 | 1C | 75 | DF | 6E |
A | 47 | F1 | 1A | 71 | 1D | 29 | C5 | 89 | 6F | B7 | 62 | 0E | AA | 18 | BE | 1B |
B | FC | 56 | 3E | 4B | C6 | D2 | 79 | 20 | 9A | DB | C0 | FE | 78 | CD | 5A | F4 |
C | 1F | DD | A8 | 33 | 88 | 07 | C7 | 31 | B1 | 12 | 10 | 59 | 27 | 80 | EC | 5F |
D | 60 | 51 | 7F | A9 | 19 | B5 | 4A | 0D | 2D | E5 | 7A | 9F | 93 | C9 | 9C | EF |
E | A0 | E0 | 3B | 4D | AE | 2A | F5 | B0 | C8 | EB | BB | 3C | 83 | 53 | 99 | 61 |
F | 17 | 2B | 04 | 7E | BA | 77 | D6 | 26 | E1 | 69 | 14 | 63 | 55 | 21 | 0C | 7D |
2.2解密逆行位移
1流程说明
2第一行不变
3第二行向右循环移动1字节
4第三行向右循环移动2字节
5第四行向右循环移动3字节
举例说明
2.3解密列混淆左乘矩阵
2.4具体步骤
这里的轮秘钥的顺序跟解密是相反的,解密第一轮的轮秘钥正好对应加密过程的最后一次的轮秘钥。
第一轮(没有逆列混淆)
第二轮
第三轮
第四轮
第五轮
第六轮
第七轮
第八轮
第九轮
第十轮
第0轮
3补充说明
总的来说,上面的例子说加密模式为ecb、填充模式为数字0(0x30)的AES128,对16字节的明文字符串通过秘钥是16个字节进行加密和解密操作流程。
除了上述的ecb模式,还有cbc加密模式。
3.1CBC加密模式
cbc模式多一个16字节初始向量(iv
)参数
加密流程
- 第一次进入加密器之前,先试用iv对明文分组1进行异或运算
- 字后进入加密器之前,使用上一次加密的密文分组对明文分组进行异或运算
举例说明
1iv ⊕ 明文分组1 -> 加密器 -> 密文1
2密文1 ⊕ 明文分组2 -> 加密器 -> 密文2
3密文2 ⊕ 明文分组3 -> 加密器 -> 密文3
解密流程
- 第一次进入解密器之后,先试用当前密文组的前面那块密文组队当前密文组进行异或运算
- 最后一次进入解密器之后用iv对当前密文组进行异或运算
举例说明
1密文3 -> 解密器 -> ⊕ 密文2 -> 明文3
2密文2 -> 解密器 -> ⊕ 密文1 -> 明文2
3密文1 -> 解密器 -> ⊕ iv -> 明文1
3.2base64编码解码
Base64算法生成的字符串可以安全地在任何实现了Base64算法的计算机之间传输。Base64典型的用途是给二进制数据(例如:图片文件)进行编码的,我们为了简化,就不用二进制,而是使用一段ASCII文本字符串来作为例子进行讲解。Base64编码出来的数据只会包含最多64种不同的ASCII字符,因此,使用Base64算法,我们就能避免数据在部分系统传输过程中发生改变。
3.2.1生成Base64索引表
3.2.2加密方式
首先,我们发现字符串“Man”
的Base64编码是“TWFu”
,那么这是怎么转换过来的呢?不急,我们一个一个字符来分析,首先对于“M”
来说,"M"
对应的ASCII编码是77
,二进制形式即01001101
;同理,字符“a”
对应的ASCII编码是97
,二进制表现形式为01100001
;“n”
的ASCII编码为110
,二进制形式为:01101110
。(ASCII编码表可参考:ASCII码对照表)这三个字符的二进制位组合在一起就变成了一个24位的字符串“010011010110000101101110”
,接下来,我们从左至右,每次抽取6位作为1组(因为6位一共有2^6=64种不同的组合),因此每一组的6位又代表一个数字(0~63),接下来,我们查看索引表,找到这个数字对应的字符,就是我们最后的结果,是不是很简单呢?
3.2.3举例说明
上面的AES128的时候,有BASE64的字符串62uCg0QGx/SVxr1iML8iig==
,使用BASE64解码
发现这些解码出来的正好拼接成4*4的AES128加密后的原始的矩阵
4程序demo
另外对于AES而言,代码层面也有对应的写法,这里不具体列出只列出对应的算法demo
1//aes.h
2#ifndef AES_H
3#define AES_H
4
5/**
6 * 参数 p: 明文的字符串数组。
7 * 参数 plen: 明文的长度,长度必须为16的倍数。
8 * 参数 key: 密钥的字符串数组。
9 */
10void aes(char *p, int plen, char *key);
11
12/**
13 * 参数 c: 密文的字符串数组。
14 * 参数 clen: 密文的长度,长度必须为16的倍数。
15 * 参数 key: 密钥的字符串数组。
16 */
17void deAes(char *c, int clen, char *key);
18
19#endif
具体实现
1//aes.c
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include "aes.h"
6
7/**
8 * S盒
9 */
10static const int S[16][16] = {
11 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
12 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
13 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
14 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
15 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
16 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
17 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
18 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
19 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
20 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
21 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
22 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
23 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
24 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
25 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
26 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
27};
28
29/**
30 * 逆S盒
31 */
32static const int S2[16][16] = {
33 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
34 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
35 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
36 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
37 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
38 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
39 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
40 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
41 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
42 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
43 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
44 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
45 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
46 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
47 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
48 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
49};
50
51/**
52 * 获取整形数据的低8位的左4个位
53 */
54static int getLeft4Bit(int num) {
55 int left = num & 0x000000f0;
56 return left >> 4;
57}
58
59/**
60 * 获取整形数据的低8位的右4个位
61 */
62static int getRight4Bit(int num) {
63 return num & 0x0000000f;
64}
65/**
66 * 根据索引,从S盒中获得元素
67 */
68static int getNumFromSBox(int index) {
69 int row = getLeft4Bit(index);
70 int col = getRight4Bit(index);
71 return S[row][col];
72}
73
74/**
75 * 把一个字符转变成整型
76 */
77static int getIntFromChar(char c) {
78 int result = (int) c;
79 return result & 0x000000ff;
80}
81
82/**
83 * 把16个字符转变成4X4的数组,
84 * 该矩阵中字节的排列顺序为从上到下,
85 * 从左到右依次排列。
86 */
87static void convertToIntArray(char *str, int pa[4][4]) {
88 int k = 0;
89 for(int i = 0; i < 4; i++)
90 for(int j = 0; j < 4; j++) {
91 pa[j][i] = getIntFromChar(str[k]);
92 k++;
93 }
94}
95
96/**
97 * 打印4X4的数组
98 */
99static void printArray(int a[4][4]) {
100 for(int i = 0; i < 4; i++){
101 for(int j = 0; j < 4; j++)
102 printf("a[%d][%d] = 0x%x ", i, j, a[i][j]);
103 printf("\n");
104 }
105 printf("\n");
106}
107
108/**
109 * 打印字符串的ASSCI,
110 * 以十六进制显示。
111 */
112static void printASSCI(char *str, int len) {
113 for(int i = 0; i < len; i++)
114 printf("0x%x ", getIntFromChar(str[i]));
115 printf("\n");
116}
117
118/**
119 * 把连续的4个字符合并成一个4字节的整型
120 */
121static int getWordFromStr(char *str) {
122 int one = getIntFromChar(str[0]);
123 one = one << 24;
124 int two = getIntFromChar(str[1]);
125 two = two << 16;
126 int three = getIntFromChar(str[2]);
127 three = three << 8;
128 int four = getIntFromChar(str[3]);
129 return one | two | three | four;
130}
131
132/**
133 * 把一个4字节的数的第一、二、三、四个字节取出,
134 * 入进一个4个元素的整型数组里面。
135 */
136static void splitIntToArray(int num, int array[4]) {
137 int one = num >> 24;
138 array[0] = one & 0x000000ff;
139 int two = num >> 16;
140 array[1] = two & 0x000000ff;
141 int three = num >> 8;
142 array[2] = three & 0x000000ff;
143 array[3] = num & 0x000000ff;
144}
145
146/**
147 * 将数组中的元素循环左移step位
148 */
149static void leftLoop4int(int array[4], int step) {
150 int temp[4];
151 for(int i = 0; i < 4; i++)
152 temp[i] = array[i];
153
154 int index = step % 4 == 0 ? 0 : step % 4;
155 for(int i = 0; i < 4; i++){
156 array[i] = temp[index];
157 index++;
158 index = index % 4;
159 }
160}
161
162/**
163 * 把数组中的第一、二、三和四元素分别作为
164 * 4字节整型的第一、二、三和四字节,合并成一个4字节整型
165 */
166static int mergeArrayToInt(int array[4]) {
167 int one = array[0] << 24;
168 int two = array[1] << 16;
169 int three = array[2] << 8;
170 int four = array[3];
171 return one | two | three | four;
172}
173
174/**
175 * 常量轮值表
176 */
177static const int Rcon[10] = {
178 0x01000000, 0x02000000,
179 0x04000000, 0x08000000,
180 0x10000000, 0x20000000,
181 0x40000000, 0x80000000,
182 0x1b000000, 0x36000000
183};
184/**
185 * 密钥扩展中的T函数
186 */
187static int T(int num, int round) {
188 int numArray[4];
189 splitIntToArray(num, numArray);
190 leftLoop4int(numArray, 1);//字循环
191
192 //字节代换
193 for(int i = 0; i < 4; i++)
194 numArray[i] = getNumFromSBox(numArray[i]);
195
196 int result = mergeArrayToInt(numArray);
197 return result ^ Rcon[round];
198}
199
200//密钥对应的扩展数组
201static int w[44];
202
203/**
204 * 扩展密钥,结果是把w[44]中的每个元素初始化
205 */
206static void extendKey(char *key) {
207 for(int i = 0; i < 4; i++)
208 w[i] = getWordFromStr(key + i * 4);
209
210 for(int i = 4, j = 0; i < 44; i++) {
211 if( i % 4 == 0) {
212 w[i] = w[i - 4] ^ T(w[i - 1], j);
213 j++;//下一轮
214 }else {
215 w[i] = w[i - 4] ^ w[i - 1];
216 }
217 }
218
219}
220
221/**
222 * 轮密钥加
223 */
224static void addRoundKey(int array[4][4], int round) {
225 int warray[4];
226 for(int i = 0; i < 4; i++) {
227
228 splitIntToArray(w[ round * 4 + i], warray);
229
230 for(int j = 0; j < 4; j++) {
231 array[j][i] = array[j][i] ^ warray[j];
232 }
233 }
234}
235
236/**
237 * 字节代换
238 */
239static void subBytes(int array[4][4]){
240 for(int i = 0; i < 4; i++)
241 for(int j = 0; j < 4; j++)
242 array[i][j] = getNumFromSBox(array[i][j]);
243}
244
245/**
246 * 行移位
247 */
248static void shiftRows(int array[4][4]) {
249 int rowTwo[4], rowThree[4], rowFour[4];
250 //复制状态矩阵的第2,3,4行
251 for(int i = 0; i < 4; i++) {
252 rowTwo[i] = array[1][i];
253 rowThree[i] = array[2][i];
254 rowFour[i] = array[3][i];
255 }
256 //循环左移相应的位数
257 leftLoop4int(rowTwo, 1);
258 leftLoop4int(rowThree, 2);
259 leftLoop4int(rowFour, 3);
260
261 //把左移后的行复制回状态矩阵中
262 for(int i = 0; i < 4; i++) {
263 array[1][i] = rowTwo[i];
264 array[2][i] = rowThree[i];
265 array[3][i] = rowFour[i];
266 }
267}
268
269/**
270 * 列混合要用到的矩阵
271 */
272static const int colM[4][4] = { 2, 3, 1, 1,
273 1, 2, 3, 1,
274 1, 1, 2, 3,
275 3, 1, 1, 2 };
276
277static int GFMul2(int s) {
278 int result = s << 1;
279 int a7 = result & 0x00000100;
280
281 if(a7 != 0) {
282 result = result & 0x000000ff;
283 result = result ^ 0x1b;
284 }
285
286 return result;
287}
288
289static int GFMul3(int s) {
290 return GFMul2(s) ^ s;
291}
292
293static int GFMul4(int s) {
294 return GFMul2(GFMul2(s));
295}
296
297static int GFMul8(int s) {
298 return GFMul2(GFMul4(s));
299}
300
301static int GFMul9(int s) {
302 return GFMul8(s) ^ s;
303}
304
305static int GFMul11(int s) {
306 return GFMul9(s) ^ GFMul2(s);
307}
308
309static int GFMul12(int s) {
310 return GFMul8(s) ^ GFMul4(s);
311}
312
313static int GFMul13(int s) {
314 return GFMul12(s) ^ s;
315}
316
317static int GFMul14(int s) {
318 return GFMul12(s) ^ GFMul2(s);
319}
320
321/**
322 * GF上的二元运算
323 */
324static int GFMul(int n, int s) {
325 int result;
326
327 if(n == 1)
328 result = s;
329 else if(n == 2)
330 result = GFMul2(s);
331 else if(n == 3)
332 result = GFMul3(s);
333 else if(n == 0x9)
334 result = GFMul9(s);
335 else if(n == 0xb)//11
336 result = GFMul11(s);
337 else if(n == 0xd)//13
338 result = GFMul13(s);
339 else if(n == 0xe)//14
340 result = GFMul14(s);
341
342 return result;
343}
344/**
345 * 列混合
346 */
347static void mixColumns(int array[4][4]) {
348
349 int tempArray[4][4];
350
351 for(int i = 0; i < 4; i++)
352 for(int j = 0; j < 4; j++)
353 tempArray[i][j] = array[i][j];
354
355 for(int i = 0; i < 4; i++)
356 for(int j = 0; j < 4; j++){
357 array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j])
358 ^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);
359 }
360}
361/**
362 * 把4X4数组转回字符串
363 */
364static void convertArrayToStr(int array[4][4], char *str) {
365 for(int i = 0; i < 4; i++)
366 for(int j = 0; j < 4; j++)
367 *str++ = (char)array[j][i];
368}
369/**
370 * 检查密钥长度
371 */
372static int checkKeyLen(int len) {
373 if(len == 16)
374 return 1;
375 else
376 return 0;
377}
378
379/**
380 * 参数 p: 明文的字符串数组。
381 * 参数 plen: 明文的长度。
382 * 参数 key: 密钥的字符串数组。
383 */
384void aes(char *p, int plen, char *key){
385
386 int keylen = strlen(key);
387 if(plen == 0 || plen % 16 != 0) {
388 printf("明文字符长度必须为16的倍数!\n");
389 exit(0);
390 }
391
392 if(!checkKeyLen(keylen)) {
393 printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
394 exit(0);
395 }
396
397 extendKey(key);//扩展密钥
398 int pArray[4][4];
399
400 for(int k = 0; k < plen; k += 16) {
401 convertToIntArray(p + k, pArray);
402
403 addRoundKey(pArray, 0);//一开始的轮密钥加
404
405 for(int i = 1; i < 10; i++){//前9轮
406
407 subBytes(pArray);//字节代换
408
409 shiftRows(pArray);//行移位
410
411 mixColumns(pArray);//列混合
412
413 addRoundKey(pArray, i);
414
415 }
416
417 //第10轮
418 subBytes(pArray);//字节代换
419
420 shiftRows(pArray);//行移位
421
422 addRoundKey(pArray, 10);
423
424 convertArrayToStr(pArray, p + k);
425 }
426}
427/**
428 * 根据索引从逆S盒中获取值
429 */
430static int getNumFromS1Box(int index) {
431 int row = getLeft4Bit(index);
432 int col = getRight4Bit(index);
433 return S2[row][col];
434}
435/**
436 * 逆字节变换
437 */
438static void deSubBytes(int array[4][4]) {
439 for(int i = 0; i < 4; i++)
440 for(int j = 0; j < 4; j++)
441 array[i][j] = getNumFromS1Box(array[i][j]);
442}
443/**
444 * 把4个元素的数组循环右移step位
445 */
446static void rightLoop4int(int array[4], int step) {
447 int temp[4];
448 for(int i = 0; i < 4; i++)
449 temp[i] = array[i];
450
451 int index = step % 4 == 0 ? 0 : step % 4;
452 index = 3 - index;
453 for(int i = 3; i >= 0; i--) {
454 array[i] = temp[index];
455 index--;
456 index = index == -1 ? 3 : index;
457 }
458}
459
460/**
461 * 逆行移位
462 */
463static void deShiftRows(int array[4][4]) {
464 int rowTwo[4], rowThree[4], rowFour[4];
465 for(int i = 0; i < 4; i++) {
466 rowTwo[i] = array[1][i];
467 rowThree[i] = array[2][i];
468 rowFour[i] = array[3][i];
469 }
470
471 rightLoop4int(rowTwo, 1);
472 rightLoop4int(rowThree, 2);
473 rightLoop4int(rowFour, 3);
474
475 for(int i = 0; i < 4; i++) {
476 array[1][i] = rowTwo[i];
477 array[2][i] = rowThree[i];
478 array[3][i] = rowFour[i];
479 }
480}
481/**
482 * 逆列混合用到的矩阵
483 */
484static const int deColM[4][4] = { 0xe, 0xb, 0xd, 0x9,
485 0x9, 0xe, 0xb, 0xd,
486 0xd, 0x9, 0xe, 0xb,
487 0xb, 0xd, 0x9, 0xe };
488
489/**
490 * 逆列混合
491 */
492static void deMixColumns(int array[4][4]) {
493 int tempArray[4][4];
494
495 for(int i = 0; i < 4; i++)
496 for(int j = 0; j < 4; j++)
497 tempArray[i][j] = array[i][j];
498
499 for(int i = 0; i < 4; i++)
500 for(int j = 0; j < 4; j++){
501 array[i][j] = GFMul(deColM[i][0],tempArray[0][j]) ^ GFMul(deColM[i][1],tempArray[1][j])
502 ^ GFMul(deColM[i][2],tempArray[2][j]) ^ GFMul(deColM[i][3], tempArray[3][j]);
503 }
504}
505/**
506 * 把两个4X4数组进行异或
507 */
508static void addRoundTowArray(int aArray[4][4],int bArray[4][4]) {
509 for(int i = 0; i < 4; i++)
510 for(int j = 0; j < 4; j++)
511 aArray[i][j] = aArray[i][j] ^ bArray[i][j];
512}
513/**
514 * 从4个32位的密钥字中获得4X4数组,
515 * 用于进行逆列混合
516 */
517static void getArrayFrom4W(int i, int array[4][4]) {
518 int index = i * 4;
519 int colOne[4], colTwo[4], colThree[4], colFour[4];
520 splitIntToArray(w[index], colOne);
521 splitIntToArray(w[index + 1], colTwo);
522 splitIntToArray(w[index + 2], colThree);
523 splitIntToArray(w[index + 3], colFour);
524
525 for(int i = 0; i < 4; i++) {
526 array[i][0] = colOne[i];
527 array[i][1] = colTwo[i];
528 array[i][2] = colThree[i];
529 array[i][3] = colFour[i];
530 }
531
532}
533
534/**
535 * 参数 c: 密文的字符串数组。
536 * 参数 clen: 密文的长度。
537 * 参数 key: 密钥的字符串数组。
538 */
539void deAes(char *c, int clen, char *key) {
540
541 int keylen = strlen(key);
542 if(clen == 0 || clen % 16 != 0) {
543 printf("密文字符长度必须为16的倍数!现在的长度为%d\n",clen);
544 exit(0);
545 }
546
547 if(!checkKeyLen(keylen)) {
548 printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
549 exit(0);
550 }
551
552 extendKey(key);//扩展密钥
553 int cArray[4][4];
554 for(int k = 0; k < clen; k += 16) {
555 convertToIntArray(c + k, cArray);
556
557
558 addRoundKey(cArray, 10);
559
560 int wArray[4][4];
561 for(int i = 9; i >= 1; i--) {
562 deSubBytes(cArray);
563
564 deShiftRows(cArray);
565
566 deMixColumns(cArray);
567 getArrayFrom4W(i, wArray);
568 deMixColumns(wArray);
569
570 addRoundTowArray(cArray, wArray);
571 }
572
573 deSubBytes(cArray);
574
575 deShiftRows(cArray);
576
577 addRoundKey(cArray, 0);
578
579 convertArrayToStr(cArray, c + k);
580
581 }
582}
main.c
1#include <stdio.h>
2#include <unistd.h>
3#include <string.h>
4#include <stdlib.h>
5
6#include "aes.h"
7
8#define MAXLEN 1024
9
10void getString(char *str, int len){
11
12 int slen = read(0, str, len);
13 for(int i = 0; i < slen; i++,str++){
14 if(*str == '\n'){
15 *str = '\0';
16 break;
17 }
18 }
19}
20
21void printASCCI(char *str, int len) {
22 int c;
23 for(int i = 0; i < len; i++) {
24 c = (int)*str++;
25 c = c & 0x000000ff;
26 printf("0x%x ", c);
27 }
28 printf("\n");
29}
30
31/**
32 * 从标准输入中读取用户输入的字符串
33 */
34void readPlainText(char *str, int *len) {
35 int plen;
36 while(1) {
37 getString(str, MAXLEN);
38 plen = strlen(str);
39 if(plen != 0 && plen % 16 == 0) {
40 printf("你输入的明文为:%s\n", str);
41 break;
42 }else{
43 printf("明文字符长度必须为16的倍数,现在的长度为%d\n", plen);
44 }
45 }
46 *len = plen;
47}
48/**
49 * 把字符串写进文件
50 */
51void writeStrToFile(char *str, int len, char *fileName) {
52 FILE *fp;
53 fp = fopen(fileName, "wb");
54 for(int i = 0; i < len; i++)
55 putc(str[i], fp);
56 fclose(fp);
57}
58
59
60void aesStrToFile(char *key) {
61
62 char p[MAXLEN];
63 int plen;
64 printf("请输入你的明文,明文字符长度必须为16的倍数\n");
65 readPlainText(p,&plen);
66 printf("进行AES加密..................\n");
67
68 aes(p, plen, key);//AES加密
69
70 printf("加密完后的明文的ASCCI为:\n");
71 printASCCI(p, plen);
72 char fileName[64];
73 printf("请输入你想要写进的文件名,比如'test.txt':\n");
74 if(scanf("%s", fileName) == 1) {
75 writeStrToFile(p, plen, fileName);
76 printf("已经将密文写进%s中了,可以在运行该程序的当前目录中找到它。\n", fileName);
77 }
78}
79/**
80 * 从文件中读取字符串
81 */
82int readStrFromFile(char *fileName, char *str) {
83 FILE *fp = fopen(fileName, "rb");
84 if(fp == NULL) {
85 printf("打开文件出错,请确认文件存在当前目录下!\n");
86 exit(0);
87 }
88
89 int i;
90 for(i = 0; i < MAXLEN && (str[i] = getc(fp)) != EOF; i++);
91
92 if(i >= MAXLEN) {
93 printf("解密文件过大!\n");
94 exit(0);
95 }
96
97 str[i] = '\0';
98 fclose(fp);
99 return i;
100}
101
102
103void deAesFile(char *key) {
104 char fileName[64];
105 char c[MAXLEN];//密文字符串
106 printf("请输入要解密的文件名,该文件必须和本程序在同一个目录\n");
107 if(scanf("%s", fileName) == 1) {
108 int clen = readStrFromFile(fileName, c);
109 printf("开始解密.........\n");
110 deAes(c, clen, key);
111 printf("解密后的明文ASCII为:\n");
112 printASCCI(c, clen);
113 printf("明文为:%s\n", c);
114 writeStrToFile(c,clen,fileName);
115 printf("现在可以打开%s来查看解密后的密文了!\n",fileName);
116 }
117}
118
119void aesFile(char *key) {
120 char fileName[64];
121 char fileP[MAXLEN];
122
123 printf("请输入要加密的文件名,该文件必须和本程序在同一个目录\n");
124 if(scanf("%s", fileName) == 1) {
125 readStrFromFile(fileName, fileP);
126 int plen = strlen(fileP);
127 printf("开始加密.........\n");
128 printf("加密前文件中字符的ASCII为:\n");
129 printASCCI(fileP, plen);
130
131 aes(fileP, plen, key);//开始加密
132
133 printf("加密后的密文ASCII为:\n");
134 printASCCI(fileP, plen);
135 writeStrToFile(fileP,plen,fileName);
136 printf("已经将加密后的密文写进%s中了\n",fileName);
137 }
138}
139
140int main(int argc, char const *argv[]) {
141
142 char key[17];
143 printf("请输入16个字符的密钥:\n");
144 int klen;
145 while(1){
146 getString(key,17);
147 klen = strlen(key);
148 if(klen != 16){
149 printf("请输入16个字符的密钥,当前密钥的长度为%d\n",klen);
150 }else{
151 printf("你输入的密钥为:%s\n",key);
152 break;
153 }
154 }
155
156 printf("输入's'表示要加密输入的字符串,并将加密后的内容写入到文件\n");
157 printf("请输入要功能选项并按回车,输入'f'表示要加密文件\n");
158 printf("输入'p'表示要解密文件\n");
159 char c;
160 if(scanf("%s",&c) == 1) {
161 if(c == 's')
162 aesStrToFile(key);//用AES加密字符串,并将字符串写进文件中
163 else if(c == 'p')
164 deAesFile(key);//把文件中的密文解密,并写回文件中
165 else if(c == 'f')//用AES加密文件
166 aesFile(key);
167 }
168 return 0;
169}
通过下面的gcc命令来编译运行:
1gcc -o aes aes.c main.c
5总结
高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥。总的来说介绍了最基本的AES的ecb的加密模式,另外还有具体的demo可以作为学习参考,不过除此之外AES还会跟base64
相结合。