AES加解密基础实现

AES加解密基础实现

第3章 分组密码.ppt 下载

课本参考:现代密码学(第四版) 杨波编著 清华大学出版社 P58

前言

非常让人恼火的一个加密算法。

书上介绍了下GF(28)有限域,随后AES过程混着伪C代码讲完了,讲得很细但是不形象。所以照着课堂上的PPT敲的,边看别写,一页讲一个步骤敲一个函数,慢慢把整个加密过程敲出来了。一轮下来的数据结构是按照矩阵存的,当时对numpy这个库不是很熟,所以代码里矩阵没有用numpy对象存,单纯地套几个列表。

对了,列表填入矩阵是按列填入的,填满一列后填第二列…直到填满整个矩阵。所以看到代码里对矩阵反复转置移位什么的,当没看到就行了,嗯,就是这样。

代码

AES.py

仅由加密部分,本想实现128,192,256,另外两个会error,有时间再改。

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
def dec2bin(n):
"""0~15整数转二进制字符串
返回的是四位二进制字符串 4->0100"""
bit = []
for i in range(0, 4):
bit.insert(0, str(n % 2))
n = int(n / 2)
return ''.join(bit)


def hex2bin(text):
"""十六进制字符串转二进制字符串"""
result = []
for i in range(len(text)):
result.extend(dec2bin(int(text[i], 16)))
return ''.join(result)


def bin2hex(text):
"""二进制字符串转十六进制字符串"""
result = []
q = len(text) // 4
for i in range(q):
dec = int(text[4 * i]) * 8 + int(text[4 * i + 1]) * 4 + \
int(text[4 * i + 2]) * 2 + int(text[4 * i + 3]) * 1
x = hex(dec)[2:].upper()
result.extend(x)
return ''.join(result)


def xor(bit1, bit2):
"""比特字符串异或运算"""
xor_result = ['' for i in range(len(bit1))]
for i in range(len(bit1)):
xor_result[i] = str(int(bit1[i]) ^ int(bit2[i]))
return ''.join(xor_result)


def left_move(bin, step):
"""循环左移,step为左移位数"""
return bin[step:] + bin[:step]


def x_time(bin):
"""x乘 x *b(x)=xtime(b)"""
result = left_move(bin, 1)
if result[-1] != "0":
result = result[:3] + str(1 ^ int(result[3])) + str(1 ^ int(result[4])) + result[5] + str(1 ^ int(result[6])) + \
result[7]
return result


def x_sqr_y_time(bin, sqr):
"""次方x乘 x2*b(x)=xtime(xtime(b)) sqr表示次方
实际上这个函数并不需要,因为cx=(03)x3+(01)x2+(01)x+(02)"""
for i in range(sqr):
bin = x_time(bin)
return bin


def multi(bin1, bin2):
"""倍乘函数"""
sqr_list, bin, result = [], [], ""
for i in range(len(bin1)):
if bin1[i] == "1":
sqr_list.append(len(bin1) - i - 1)
if not sqr_list:
return xor(bin2, bin1)
for i in range(len(sqr_list)):
bin.append(x_sqr_y_time(bin2, sqr_list[i]))
result = bin[0]
for i in range(len(bin) - 1):
result = xor(result, bin[i + 1])
return result


def matrix_str(bin, col):
"""将原始的01字符列转化为 4行Nb列的矩阵 矩阵一个单位是8bit"""
# 矩阵填数是按照一列一列填的
b_unit = []
for i in range(0, len(bin), 8):
b_unit.append(bin[i:(i + 8)])
return matrix_li(b_unit, col)


def matrix_li(b_unit, col):
"""将8bit单位的列表转化为 4行row列的矩阵 矩阵一个单位是8bit"""
# print("b_unit:",b_unit)
b_list = []
count, j = 0, 0
while count < len(b_unit):
row = []
for i in range(col):
# print(j)
row.append(b_unit[j])
j += col
count += 1
j -= len(b_unit) - 1
b_list.append(row)
return b_list


"""明文和密钥"""
message = ''.join(['0' for i in range(128)])
key = ''.join(['1' for i in range(128)]) # 128 192 256
# message = hex2bin("3243F6A8885A308D313198A2E0370734")
# key = hex2bin("2b7e151628aed2a6abf7158809cf4f3c")
Nb = len(message) // 32 # 明文一行的单元个数 一个单元8位 4.6.8
Nk = len(key) // 32 # 密文一行的单元个数 4.6.8
Nr = (lambda Nb, Nk: Nb + 6 if Nb > Nk else Nk + 6)(Nb, Nk) # 迭代轮数
"""S盒加密"""
sbox = (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)


def byte_sub(num):
"""给8位二进制数进行s盒字节代换"""
x, y = int(num[:4], 2), int(num[4:], 2)
return bin(sbox[16 * x + y])[2:].zfill(8)


def get_Ci(i):
"""Ci(Ci,Nb)行移位字节数,抱歉我找不到规律了,直接抄表"""
Ci = {
(0, 4): 0, (1, 4): 1, (2, 4): 2, (3, 4): 3,
(0, 4): 0, (1, 6): 1, (2, 6): 2, (3, 6): 3,
(0, 4): 0, (1, 8): 1, (2, 8): 3, (3, 8): 4,
}
return Ci[i, Nb]


def shift_row(matrix):
"""行移位:将状态矩阵的每行进行循环左移"""
result = []
for i in range(len(matrix)):
result.append(left_move(matrix[i], get_Ci(i)))
return result


def mix_column(matrix):
"""列混合常数 cx=(03)x3+(01)x2+(01)x+(02)"""
b0, b1, b2, b3 = ["00000010", "00000001", "00000001", "00000011"] # 次幂依次为x0,x1,x2,x3
col_c = []
for a0, a1, a2, a3 in zip(matrix[0], matrix[1], matrix[2], matrix[3]):
col_c.append(xor(xor(xor(multi(a0, b0), multi(a3, b1)), multi(a2, b2)), multi(a1, b3)))
col_c.append(xor(xor(xor(multi(a1, b0), multi(a0, b1)), multi(a3, b2)), multi(a2, b3)))
col_c.append(xor(xor(xor(multi(a2, b0), multi(a1, b1)), multi(a0, b2)), multi(a3, b3)))
col_c.append(xor(xor(xor(multi(a3, b0), multi(a2, b1)), multi(a1, b2)), multi(a0, b3)))
i, count, result = 0, 0, [[] for i in range(Nb)]
while count < len(col_c):
for j in range(Nk):
result[count // Nk].append(col_c[i])
# print("i",i)
i += 4
count += 1
i -= len(col_c) - 1
return result


def add_round_key(message, key):
"""将状态矩阵与子密钥矩阵的对应字节进行逐比特异或 row(4) * col(4,6,8)"""
result, result_row = [], []
for m_row, k_row in zip(message, key):
for m_unit, k_unit in zip(m_row, k_row):
result_row.append(xor(m_unit, k_unit))
result.append(result_row)
result_row = []
# print(result)
return result


def build_RC():
"""根据Nb生成RC 128位、196位、256位的明文RC对应10,12,14个二进制队"""
result = ["" for i in range(Nr)]
result[0] = hex2bin("01")
for i in range(1, Nr):
result[i] = x_time(result[i - 1])
return result


RC = build_RC() # RC的值 2进制字符串


def build_Rcon():
"""Rcon常量,Rcon每个元素都是2进制的"""
result = []
for i in range(Nr):
result.append([RC[i], '00000000', '00000000', '00000000'])
return result


Rcon = build_Rcon() # Rcon的值 2进制字符串


def T(W, nr):
"""扩展密匙里的T运算,输入的数为 8位二进制字符*4
nr表示轮数,从第零轮开始"""
W = left_move(W, 1)
sub_li, result = [], []
for str in W:
sub_li.append(byte_sub(str))
for li, r in zip(sub_li, Rcon[nr]):
result.append(xor(li, r))
return result


def key_expansion(key):
"""密钥扩展,Nk<=6和Nk>6又不同的扩展方法"""
W = [[] for i in range(Nb * (Nr + 1))]
matrix_key = matrix_str(key, Nk)
print(matrix_key)
for col in range(Nk): # row的值可能为4,6,8
for i in range(len(matrix_key)):
W[col].append(matrix_key[i][col])
if Nk <= 6:
for i in range(Nk, len(W)):
temp = W[i - 1]
if i % Nk == 0:
temp = T(W[i - 1], i // Nk - 1)
for x, y in zip(W[i - Nk], temp):
W[i].append(xor(x, y))
if Nk > 6:
for i in range(Nk, len(W)):
temp = W[i - 1]
if i % Nk == 0:
temp = T(W[i - 1], i // Nk - 1)
elif i % Nk == 4:
sub_li = []
for str in temp:
sub_li.append(byte_sub(str))
temp = sub_li
for x, y in zip(W[i - Nk], temp):
W[i].append(xor(x, y))
# print(len(W), len(W) / 4)
# 将每一轮的密钥矩阵转置
result = []
for i in range(0, len(W), Nk):
temp = W[i:i + Nk]
extend_temp = []
for i in temp:
extend_temp.extend(i)
result.append(matrix_li(extend_temp, Nk))
return result


def round_bin2hex(round):
row_li, result = [], []
for row in round:
for col in row:
row_li.append(bin2hex(col))
result.append(row_li)
row_li = []
return result


def encode(message, key):
"""加密函数"""
key = key_expansion(key)
message = matrix_str(message, Nb)
# "因为debug滴完了还是数不清一堆的0101是对是错,所以加了很多的print"
print("message\n", round_bin2hex(message), "\n------------")
print("key[0]\n", round_bin2hex(key[0]), "\n------------")
round = add_round_key(message, key[0])
print("B1\n", round_bin2hex(round), "\n------------")
for i in range(Nr):
replace_row, replace_matrix = [], []
for row in round:
for unit in row:
replace_row.append(byte_sub(unit))
replace_matrix.append(replace_row)
replace_row = []
round = replace_matrix
if i == 0:
print("byte_sub\n", round_bin2hex(round), "\n------------")
round = shift_row(round)
if i == 0:
print("shift_row\n", round_bin2hex(round), "\n------------")
if not i == Nr - 1:
round = mix_column(round)
if i == 0:
print("mix_column\n", round_bin2hex(round), "\n------------")
print("key[1]\n", round_bin2hex(key[1]), "\n------------")
round = add_round_key(round, key[i + 1])
print("add_round_key",i,"\n", round_bin2hex(round), "\n------------")
return round_bin2hex(round)


print("加密结果:", encode(message, key))

jump_text = 0 # 测试函数功能
# print(hex2bin("ba"))
# print(bin2hex("10111010"))
# print(dec2bin(20))
# print(x_time("10000000"))
# print(x_sqr_y_time("10000000", 0))
# print(bin2hex(multi(hex2bin("57"), hex2bin("13"))))
# print(Nr(4,6))
# print(byte_sub("00010001"))
# print(round_bin2hex(matrix_str(message,Nb)))
# print(shift_row(matrix_str(message,Nb)))
# print(mix_column(matrix_str(message,Nb)))
# print(add_round_key(matrix_str(message,Nb),matrix_str(key,Nb)))
# ---------
# T函数 应该输出79 C5 7A 91
# w3 = [hex2bin("ac"), hex2bin("c1"), hex2bin("07"), hex2bin("bd")]
# for i in T(w3,0):
# print(bin2hex(i),end=" ")
# ---------
# RC生成值 RC = {00, 01, 02, 04, 08, 10, 20, 40, 80, 1B, 36}
# for i in RC:
# print(bin2hex(i),end=" ")
# ---------
# Rcon生成值
# print(round_bin2hex(Rcon))
# print(key_expansion(key))

思考

这是128位的,196位和256位似乎有bug,但我暂时没时间调。

在上面的代码里,你可以看到:

  • 矩阵已然是按列存入,之后跑列混合函数,又需要将每一列的数据拉出来做倍乘。也就是说,比起按行填入矩阵时一个下标就能搞定的数据提取,我需要用两个循环来把每一个元素做遍历,再将一列数据存入到一个新列表里…

  • c(x)=(03)x3+(01)x2+(01)x+(02)

    GF(28)有限域概念里提到xytime,例如x2b(x)=xtime( xtime(b) )函数,在后续根本用不到,因为最高也只有
    x1b(x)次幂,即xtime()这一个函数就够了。

    大费周章地用两个变量进行多项式相乘也没必要,因为最终给出的c(x)是一个常数多项式

总而言之,照着这个教程PPT写出的代码各种复杂冗余绕来绕去,我最后自己都被自己的代码逗笑了。

可以考虑的优化方法有:

  1. 使用按行填入矩阵的方式,此时直接用矩阵的行代表列,省去遍历矩阵取列元素的步骤。使用矩阵的最大好处是函数的功能显得比较清晰,传入特定的数据类型参数,返回特定的数据类型值。同时控制台调试代码也人性化一些。当然,自己对一个列表套几个框框肯定不是真正的矩阵,不仅不能优化算法反而有可能加了时间复杂度。

  2. 不使用矩阵的数据结构,改用线性的列表进行操作,下标访问即可,省去各种转倒腾挪。要求数学不错。

  3. 不需要将公式定理写的一板一眼,能省则省。固定的结果直接定义好就行了,像通过完整的公式套上固定的常量进一步得出值这样的做法,应该是说明书教科书做的内容,实际应用里完全没有必要。

  4. 导入numpy,一行搞定各种花里胡哨的要求,代码清晰跑得飞快,码字人省出大量for…in数下标的时间。

对了,对C版本感兴趣的可以看这位老哥的AES/aes.c at master · dhuertas/AES (github.com),C实现难度比python更大,但毫无疑问效率会更高。不过我没跑过就是了。

对Java实现感兴趣的话可以看这位老哥的Encryption-And-Decryption-By-Yu/src/encryption at master · szluyu99/Encryption-And-Decryption-By-Yu (github.com),这老哥比较骚,基本密码学课程教的全来了,还写了一个GUI,着实顶呱呱。

别人的代码,交个作业救急:

Python 实现AES算法 - Kerne0 - 博客园 (cnblogs.com)

写的比我好,底层数据应该就是确确实实的整数,计算机视作二进制计算。而不是我的’0’,’1’,’0’,’1’假序列。

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
# coding:utf-8
class AESE():
def __init__(self, blk, key, Nr):
self.blk = blk
self.key = key
self.Nr = Nr
self.sbox = (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)

# xtime process
def xtime(self, x):
if (x & 0x80):
return (((x << 1) ^ 0x1b) & 0xff)
return x << 1

# MixColumns: Process the entire block
def MixColumns(self):
tmp = [0 for t in range(4)]
xt = [0 for q in range(4)]
n = 0
for x in range(4):
xt[0] = self.xtime(self.blk[n])
xt[1] = self.xtime(self.blk[n + 1])
xt[2] = self.xtime(self.blk[n + 2])
xt[3] = self.xtime(self.blk[n + 3])
tmp[0] = xt[0] ^ xt[1] ^ self.blk[n + 1] ^ self.blk[n + 2] ^ self.blk[n + 3]
tmp[1] = self.blk[n] ^ xt[1] ^ xt[2] ^ self.blk[n + 2] ^ self.blk[n + 3]
tmp[2] = self.blk[n] ^ self.blk[n + 1] ^ xt[2] ^ xt[3] ^ self.blk[n + 3]
tmp[3] = xt[0] ^ self.blk[n] ^ self.blk[n + 1] ^ self.blk[n + 2] ^ xt[3]
self.blk[n] = tmp[0]
self.blk[n + 1] = tmp[1]
self.blk[n + 2] = tmp[2]
self.blk[n + 3] = tmp[3]
n = n + 4

# ShiftRows:Shifts the entire block
def ShiftRows(self):
# 2nd row
t = self.blk[1]
self.blk[1] = self.blk[5]
self.blk[5] = self.blk[9]
self.blk[9] = self.blk[13]
self.blk[13] = t
# 3nd row
t = self.blk[2]
self.blk[2] = self.blk[10]
self.blk[10] = t
t = self.blk[6]
self.blk[6] = self.blk[14]
self.blk[14] = t
# 4nd row
t = self.blk[15]
self.blk[15] = self.blk[11]
self.blk[11] = self.blk[7]
self.blk[7] = self.blk[3]
self.blk[3] = t

# SubBytes
def SubBytes(self):
for x in range(16):
self.blk[x] = self.sbox[self.blk[x]]

# AddRoundKey
def AddRoundKey(self, key):
x = 0
k = [0 for m in range(16)]
for c in range(4):
for r in range(4):
k[x] = key[r][c]
x = x + 1
for y in range(16):
self.blk[y] ^= int(k[y])

def show(self):
for i in range(16):
print(hex(self.blk[i]))

# Schedule a secret key for use.
def ScheduleKey(self, w, Nk):
Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]
for r in range(4):
for c in range(4):
w[0][r][c] = self.key[r + c * 4]
for i in range(1, self.Nr + 1, 1): # 问题1
for j in range(Nk):
t = [0 for x in range(4)]
for r in range(4):
if j:
t[r] = w[i][r][j - 1]
else:
t[r] = w[i - 1][r][3]
if j == 0:
temp = t[0]
for r in range(3):
t[r] = self.sbox[t[(r + 1) % 4]]
t[3] = self.sbox[temp]
t[0] ^= int(Rcon[i - 1])
for r in range(4):
w[i][r][j] = w[i - 1][r][j] ^ t[r]

# 加密函数
def AesEncrypt(self):
outkey = []
outkey = [[[0 for col in range(4)] for row in range(4)] for s in range(11)]
self.ScheduleKey(outkey, 4)
self.AddRoundKey(outkey[0])
for x in range(1, self.Nr, 1):
self.SubBytes()
self.ShiftRows()
self.MixColumns()
self.AddRoundKey(outkey[x])
self.SubBytes()
self.ShiftRows()
self.AddRoundKey(outkey[10])
print("密文的16进制:")
cText = ""
for i in range(16):
xxl = hex(self.blk[i])
cText += xxl[2:]
print(cText)
return blk


class AESD():
def __init__(self, blk, key, Nr):
self.blk = blk
self.key = key
self.Nr = Nr
self.sbox = (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)

def xtime(self, x):
if (x & 0x80):
return (((x << 1) ^ 0x1b) & 0xff)
return x << 1

def ReMixColumns(self):
tmp = [0 for q in range(4)]
xt1 = [0 for w in range(4)]
xt2 = [0 for e in range(4)]
xt3 = [0 for r in range(4)]
n = 0
for x in range(4):
xt1[0] = self.xtime(self.blk[n])
xt1[1] = self.xtime(self.blk[n + 1])
xt1[2] = self.xtime(self.blk[n + 2])
xt1[3] = self.xtime(self.blk[n + 3])
xt2[0] = self.xtime(self.xtime(self.blk[n]))
xt2[1] = self.xtime(self.xtime(self.blk[n + 1]))
xt2[2] = self.xtime(self.xtime(self.blk[n + 2]))
xt2[3] = self.xtime(self.xtime(self.blk[n + 3]))
xt3[0] = self.xtime(self.xtime(self.xtime(self.blk[n])))
xt3[1] = self.xtime(self.xtime(self.xtime(self.blk[n + 1])))
xt3[2] = self.xtime(self.xtime(self.xtime(self.blk[n + 2])))
xt3[3] = self.xtime(self.xtime(self.xtime(self.blk[n + 3])))
tmp[0] = xt1[0] ^ xt2[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt1[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt2[2] ^ xt3[2] ^ \
self.blk[n + 3] ^ xt3[3]
tmp[1] = self.blk[n] ^ xt3[0] ^ xt1[1] ^ xt2[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt1[2] ^ xt3[2] ^ self.blk[
n + 3] ^ xt2[3] ^ xt3[3]
tmp[2] = self.blk[n] ^ xt2[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt3[1] ^ xt1[2] ^ xt2[2] ^ xt3[2] ^ self.blk[
n + 3] ^ xt1[3] ^ xt3[3]
tmp[3] = self.blk[n] ^ xt1[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt2[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt3[2] ^ xt1[
3] ^ xt2[3] ^ xt3[3]
self.blk[n] = tmp[0]
self.blk[n + 1] = tmp[1]
self.blk[n + 2] = tmp[2]
self.blk[n + 3] = tmp[3]
n = n + 4

def ReShiftRows(self):
# 2nd row
t = self.blk[13]
self.blk[13] = self.blk[9]
self.blk[9] = self.blk[5]
self.blk[5] = self.blk[1]
self.blk[1] = t
# 3rd row
t = self.blk[2]
self.blk[2] = self.blk[10]
self.blk[10] = t
t = self.blk[6]
self.blk[6] = self.blk[14]
self.blk[14] = t
# 4th row
t = self.blk[3]
self.blk[3] = self.blk[7]
self.blk[7] = self.blk[11]
self.blk[11] = self.blk[15]
self.blk[15] = t

def ReSubBytes(self):
for i in range(16):
for j in range(256):
if (self.sbox[j] == self.blk[i]):
self.blk[i] = j
break

def AddRoundKey(self, key):
x = 0
k = [0 for m in range(16)]
for c in range(4):
for r in range(4):
k[x] = key[r][c]
x = x + 1
for y in range(16):
self.blk[y] ^= k[y]

def ScheduleKey(self, w, Nk):
Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]
for r in range(4):
for c in range(4):
w[0][r][c] = self.key[r + c * 4]
for i in range(1, self.Nr + 1, 1):
for j in range(Nk):
t = [0 for x in range(4)]
for r in range(4):
if j:
t[r] = w[i][r][j - 1]
else:
t[r] = w[i - 1][r][3]
if j == 0:
temp = t[0]
for r in range(3):
t[r] = self.sbox[t[(r + 1) % 4]]
t[3] = self.sbox[temp]
t[0] ^= int(Rcon[i - 1])
for r in range(4):
w[i][r][j] = w[i - 1][r][j] ^ t[r]

def AesDecrpyt(self):
outkey = [[[0 for col in range(4)] for row in range(4)] for s in range(11)] # 改
self.ScheduleKey(outkey, 4)
self.AddRoundKey(outkey[10])
self.ReShiftRows()
self.ReSubBytes()
for x in range(self.Nr - 1, 0, -1):
self.AddRoundKey(outkey[x])
self.ReMixColumns() # 第二次循环出问题了
self.ReShiftRows()
self.ReSubBytes()
self.AddRoundKey(outkey[0])
print("解密结果:")
mText = ""
for x in range(16):
mText += chr(self.blk[x])
print(mText)


def StringToListN(string):
s = [0 for x in range(16)]
l = len(string)
for x in range(l):
s[x] = int(ord(string[x]))
return s


if __name__ == "__main__":
# 加密
plainText = input("请输入待加密的字符串:")
blk = StringToListN(plainText)
skey = input("请输入待加密的秘钥:")
key = StringToListN(skey)
a = AESE(blk, key, 10)
rblk = a.AesEncrypt()
# 解密
b = AESD(rblk, key, 10)
b.AesDecrpyt()