AES (Advanced Encryption Standard)是一种区块加密标准算法,它的提出是为了升级替换原有的DES加密算法。因此它的安全强度高于DES算法。

1简介

AES的加密模式

AES的加密模式 说明
密钥长度 AES128AES192AES256
加密模式 ECBCBCCFBOFBCTRCCMGCMXTS
填充模式 NONEPKCS7ZEROANS1923ISO7816_4ISO10126

现在的加密库一般会提供一些默认值,所以用户使用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相结合。

参考

[1] TimeShatter, AES加密算法原理的详细介绍与实现, 2023.

[2] 刘扬俊, 什么是Base64算法?——全网最详细讲解, 2023.