1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
|
import sys
from typing import List
# =============================================================================
# AES 常量定义
# =============================================================================
# S-Box (Substitution Box): 用于 SubBytes 步骤的非线性替换表
# 它是基于 GF(2^8) 上的乘法逆元和仿射变换构造的
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
]
# Inverse S-Box: 用于解密时的逆字节代换
INV_SBOX = [
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
]
# Rcon (Round Constant): 轮常数,用于密钥扩展
# Rcon[i] 代表 x^(i-1) 在 GF(2^8) 中的值
RCON = [
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
]
BLOCK_SIZE = 16 # AES 分组大小固定为 128 位 (16 字节)
# =============================================================================
# 辅助函数:填充与数据转换
# =============================================================================
def pkcs7_pad(data: bytes, block_size: int = BLOCK_SIZE) -> bytes:
"""
PKCS#7 填充:将数据填充到 block_size 的倍数。
填充的值等于填充的字节数。
例如:如果缺 3 个字节,就填充 0x03 0x03 0x03。
"""
pad_len = block_size - (len(data) % block_size)
if pad_len == 0:
pad_len = block_size
return data + bytes([pad_len] * pad_len)
def pkcs7_unpad(data: bytes) -> bytes:
"""
PKCS#7 去填充:读取最后一个字节确定填充长度,并移除填充。
"""
if not data:
raise ValueError("空数据不支持去填充")
pad_len = data[-1]
if pad_len < 1 or pad_len > BLOCK_SIZE:
raise ValueError("填充长度非法")
if data[-pad_len:] != bytes([pad_len] * pad_len):
raise ValueError("填充内容非法")
return data[:-pad_len]
def zero_pad_key_to_16(key: bytes) -> bytes:
"""
将密钥处理为 16 字节 (128 位)。
如果不足 16 字节,右侧补 0;如果超过,截断。
(仅用于演示,生产环境应使用 KDF)
"""
if len(key) >= 16:
return key[:16]
return key + bytes(16 - len(key))
def bytes_to_state(block: bytes) -> List[List[int]]:
"""
将 16 字节的输入块转换为 4x4 的状态矩阵 (State)。
AES 规定按【列优先】顺序填充。
"""
return [list(block[i::4])[:4] for i in range(4)]
def state_to_bytes(state: List[List[int]]) -> bytes:
"""
将 4x4 状态矩阵转换回 16 字节数据 (列优先读取)。
"""
out = bytearray(16)
for r in range(4):
for c in range(4):
out[c * 4 + r] = state[r][c]
return bytes(out)
# =============================================================================
# AES 核心变换函数
# =============================================================================
def sub_bytes(state: List[List[int]]):
"""
SubBytes (字节代换):
使用 S-Box 对状态矩阵中的每个字节进行非线性替换。
提供了算法的混淆性 (Confusion)。
"""
for r in range(4):
for c in range(4):
state[r][c] = SBOX[state[r][c]]
def inv_sub_bytes(state: List[List[int]]):
"""
InvSubBytes (逆字节代换):
使用逆 S-Box 还原字节,用于解密。
"""
for r in range(4):
for c in range(4):
state[r][c] = INV_SBOX[state[r][c]]
def shift_rows(state: List[List[int]]):
"""
ShiftRows (行移位):
对状态矩阵的每一行进行循环左移。
第0行不移,第1行左移1位,第2行左移2位,第3行左移3位。
提供了算法的扩散性 (Diffusion)。
"""
state[1] = state[1][1:] + state[1][:1]
state[2] = state[2][2:] + state[2][:2]
state[3] = state[3][3:] + state[3][:3]
def inv_shift_rows(state: List[List[int]]):
"""
InvShiftRows (逆行移位):
对状态矩阵的每一行进行循环右移,用于解密。
"""
state[1] = state[1][-1:] + state[1][:-1]
state[2] = state[2][-2:] + state[2][:-2]
state[3] = state[3][-3:] + state[3][:-3]
# --- GF(2^8) 数学运算辅助函数 ---
def xtime(a: int) -> int:
"""
xtime 函数:计算 a * x (在 GF(2^8) 域上)。
相当于左移一位,如果溢出则异或不可约多项式 0x1B。
"""
return ((a << 1) & 0xFF) ^ (0x1B if (a & 0x80) else 0)
def mul(a: int, b: int) -> int:
"""
GF(2^8) 上的乘法:计算 a * b。
通过重复 xtime 和条件异或实现 (类似快速幂/俄罗斯农民乘法)。
"""
res = 0
for i in range(8):
if b & 1:
res ^= a
a = xtime(a)
b >>= 1
return res
def mix_single_column(col: List[int]) -> List[int]:
"""
MixColumns 的单列计算。
将列向量与固定多项式 c(x) = 03x^3 + 01x^2 + 01x + 02 相乘。
"""
a0, a1, a2, a3 = col
return [
mul(a0, 2) ^ mul(a1, 3) ^ a2 ^ a3,
a0 ^ mul(a1, 2) ^ mul(a2, 3) ^ a3,
a0 ^ a1 ^ mul(a2, 2) ^ mul(a3, 3),
mul(a0, 3) ^ a1 ^ a2 ^ mul(a3, 2)
]
def mix_columns(state: List[List[int]]):
"""
MixColumns (列混合):
对状态矩阵的每一列进行线性变换,进一步增强扩散性。
"""
for c in range(4):
col = [state[r][c] for r in range(4)]
new_col = mix_single_column(col)
for r in range(4):
state[r][c] = new_col[r]
def inv_mix_single_column(col: List[int]) -> List[int]:
"""
InvMixColumns 的单列计算。
乘以 c(x) 的逆多项式 d(x) = 0Bx^3 + 0Dx^2 + 09x + 0E。
"""
a0, a1, a2, a3 = col
return [
mul(a0, 0x0e) ^ mul(a1, 0x0b) ^ mul(a2, 0x0d) ^ mul(a3, 0x09),
mul(a0, 0x09) ^ mul(a1, 0x0e) ^ mul(a2, 0x0b) ^ mul(a3, 0x0d),
mul(a0, 0x0d) ^ mul(a1, 0x09) ^ mul(a2, 0x0e) ^ mul(a3, 0x0b),
mul(a0, 0x0b) ^ mul(a1, 0x0d) ^ mul(a2, 0x09) ^ mul(a3, 0x0e)
]
def inv_mix_columns(state: List[List[int]]):
"""
InvMixColumns (逆列混合):用于解密。
"""
for c in range(4):
col = [state[r][c] for r in range(4)]
new_col = inv_mix_single_column(col)
for r in range(4):
state[r][c] = new_col[r]
def add_round_key(state: List[List[int]], round_key: bytes):
"""
AddRoundKey (轮密钥加):
将状态矩阵与当前的轮密钥进行按位异或 (XOR)。
"""
for r in range(4):
for c in range(4):
state[r][c] ^= round_key[c * 4 + r]
# =============================================================================
# 密钥扩展 (Key Expansion)
# =============================================================================
def rot_word(w: List[int]) -> List[int]:
"""字循环左移:[a0, a1, a2, a3] -> [a1, a2, a3, a0]"""
return w[1:] + w[:1]
def sub_word(w: List[int]) -> List[int]:
"""字代换:对字中的每个字节应用 S-Box"""
return [SBOX[b] for b in w]
def key_expansion(key: bytes) -> List[bytes]:
"""
密钥扩展算法 (AES-128):
将 16 字节初始密钥扩展为 11 组轮密钥 (每组 16 字节)。
"""
Nk = 4 # 密钥长度 (字数),AES-128 为 4
Nb = 4 # 分组长度 (字数),固定为 4
Nr = 10 # 轮数,AES-128 为 10
# w 存储扩展后的所有字 (4 * (Nr + 1) = 44 个字)
w = [[0, 0, 0, 0] for _ in range(Nb * (Nr + 1))]
# 前 Nk 个字直接取自初始密钥
for i in range(Nk):
w[i] = [key[4 * i + 0], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]
# 生成剩余的字
for i in range(Nk, Nb * (Nr + 1)):
temp = w[i - 1][:]
if i % Nk == 0:
# 每 Nk 个字进行一次复杂变换:RotWord + SubWord + XOR Rcon
temp = sub_word(rot_word(temp))
temp[0] ^= RCON[i // Nk]
# W[i] = W[i-Nk] XOR temp
w[i] = [ (w[i - Nk][j] ^ temp[j]) & 0xFF for j in range(4) ]
# 将字数组重新组合成 11 个 16 字节的轮密钥
round_keys = []
for r in range(Nr + 1):
rk = []
for c in range(Nb):
rk.extend(w[r * Nb + c])
round_keys.append(bytes(rk))
return round_keys
# =============================================================================
# 调试与输出辅助
# =============================================================================
def bytes_hex(b: bytes) -> str:
return b.hex().upper()
def state_hex(state: List[List[int]]) -> str:
return state_to_bytes(state).hex().upper()
# =============================================================================
# AES 加密与解密流程 (Block Level)
# =============================================================================
def aes_encrypt_block(block: bytes, round_keys: List[bytes], verbose: bool = False) -> bytes:
"""
加密单个 16 字节分组。
流程:AddRoundKey(Initial) -> 9轮(Sub/Shift/Mix/Add) -> 最终轮(Sub/Shift/Add)
"""
state = bytes_to_state(block)
if verbose:
print("\n==================== 开始 AES 加密 (单块) ===================")
print(f"输入数据 (Hex): {block.hex().upper()}")
print(f"初始轮密钥 (Hex): {bytes_hex(round_keys[0])}")
# 初始轮:只做 AddRoundKey
add_round_key(state, round_keys[0])
# 第 1 到 9 轮
for round_idx in range(1, 10):
if verbose:
print(f"\n-- Round {round_idx} --")
sub_bytes(state)
if verbose:
print(f"After SubBytes: {state_hex(state)}")
shift_rows(state)
if verbose:
print(f"After ShiftRows: {state_hex(state)}")
mix_columns(state)
if verbose:
print(f"After MixColumns: {state_hex(state)}")
add_round_key(state, round_keys[round_idx])
if verbose:
print(f"AddRoundKey ({round_idx}): {bytes_hex(round_keys[round_idx])}")
print(f"State: {state_hex(state)}")
# 最终轮 (第 10 轮):无 MixColumns
if verbose:
print("\n-- Final Round (10) --")
sub_bytes(state)
if verbose:
print(f"After SubBytes: {state_hex(state)}")
shift_rows(state)
if verbose:
print(f"After ShiftRows: {state_hex(state)}")
add_round_key(state, round_keys[10])
if verbose:
print(f"AddRoundKey (10): {bytes_hex(round_keys[10])}")
print(f"[加密结果] (Hex): {state_hex(state)}")
print("==================== 结束 AES 加密 ====================\n")
return state_to_bytes(state)
def aes_decrypt_block(block: bytes, round_keys: List[bytes], verbose: bool = False) -> bytes:
"""
解密单个 16 字节分组。
流程是加密的逆过程,注意轮密钥顺序相反。
"""
state = bytes_to_state(block)
if verbose:
print("\n==================== 开始 AES 解密 (单块) ===================")
print(f"输入数据 (Hex): {block.hex().upper()}")
print(f"终止轮密钥 (Hex): {bytes_hex(round_keys[10])}")
# 初始逆变换:先异或最后一轮密钥
add_round_key(state, round_keys[10])
inv_shift_rows(state)
inv_sub_bytes(state)
# 第 9 到 1 轮 (逆序)
for round_idx in range(9, 0, -1):
if verbose:
print(f"\n-- Round {round_idx} --")
add_round_key(state, round_keys[round_idx])
if verbose:
print(f"AddRoundKey ({round_idx}): {bytes_hex(round_keys[round_idx])}")
print(f"State: {state_hex(state)}")
inv_mix_columns(state)
if verbose:
print(f"After InvMixColumns: {state_hex(state)}")
inv_shift_rows(state)
if verbose:
print(f"After InvShiftRows: {state_hex(state)}")
inv_sub_bytes(state)
if verbose:
print(f"After InvSubBytes: {state_hex(state)}")
# 最终逆变换
add_round_key(state, round_keys[0])
if verbose:
print(f"AddRoundKey (0): {bytes_hex(round_keys[0])}")
print(f"[解密结果] (Hex): {state_hex(state)}")
print("==================== 结束 AES 解密 ====================\n")
return state_to_bytes(state)
# =============================================================================
# ECB 模式封装
# =============================================================================
def aes_encrypt_ecb(plaintext: bytes, key: bytes, verbose: bool = False) -> bytes:
"""
AES-128 ECB 模式加密。
1. 处理密钥
2. 填充明文 (PKCS#7)
3. 分块加密
"""
key16 = zero_pad_key_to_16(key)
round_keys = key_expansion(key16)
padded = pkcs7_pad(plaintext, BLOCK_SIZE)
if verbose:
print("开始加密...")
print(f"原始长度: {len(plaintext)}, 填充后长度: {len(padded)}")
out = bytearray()
for i in range(0, len(padded), BLOCK_SIZE):
blk = padded[i:i+BLOCK_SIZE]
if verbose:
try:
print(f"\n>>> 处理第 {i//BLOCK_SIZE + 1} 块: {blk.decode('utf-8', 'ignore')}")
except Exception:
print(f"\n>>> 处理第 {i//BLOCK_SIZE + 1} 块 (Hex): {blk.hex().upper()}")
ct = aes_encrypt_block(blk, round_keys, verbose)
out.extend(ct)
return bytes(out)
def aes_decrypt_ecb(ciphertext: bytes, key: bytes, verbose: bool = False) -> bytes:
"""
AES-128 ECB 模式解密。
1. 处理密钥
2. 分块解密
3. 去填充 (PKCS#7)
"""
key16 = zero_pad_key_to_16(key)
round_keys = key_expansion(key16)
out = bytearray()
if verbose:
print("开始解密...")
for i in range(0, len(ciphertext), BLOCK_SIZE):
blk = ciphertext[i:i+BLOCK_SIZE]
if verbose:
print(f"\n>>> 处理第 {i//BLOCK_SIZE + 1} 块 (Hex): {blk.hex().upper()}")
pt = aes_decrypt_block(blk, round_keys, verbose)
out.extend(pt)
return pkcs7_unpad(bytes(out))
def main():
raw_text = "hello fanshanng"
raw_key = "secret"
print(f"原始明文: {raw_text}")
print(f"原始密钥: {raw_key}")
pt = raw_text.encode("utf-8")
key_bytes = raw_key.encode("utf-8")
# 加密
ct = aes_encrypt_ecb(pt, key_bytes, verbose=True)
print(f"\n最终密文 (Hex): {ct.hex().upper()}")
# 解密
dec = aes_decrypt_ecb(ct, key_bytes, verbose=True)
dec_str = dec.decode("utf-8")
print("\n最终验证:")
print(f" 原始明文: {raw_text}")
print(f" 解密明文: {dec_str}")
print(f" 匹配成功: {raw_text == dec_str}")
if __name__ == "__main__":
main()
|