一、使用在线加密网站计算密文
为简单演示AES解密的过程,而非使用模式,先实现简单的AES-128-ECB模式。
原始密钥:00112233445566778899AABBCCDDEEFF
原始分组:'AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB'
明文和密钥均为128bit

二、编写密钥拓展脚本(python)
对于密钥的拓展手搓可能比较复杂,故使用python脚本生成并硬编码入汇编的数据段中
python
def aes128_key_expansion_cpp_vector(hex_key: str) -> str:
# ---------- AES 基础数据 ----------
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
]
rcon = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]
# ---------- 辅助函数 ----------
def subword(word: list[int]) -> list[int]:
return [sbox[b] for b in word]
def rotword(word: list[int]) -> list[int]:
return word[1:] + word[:1]
def xor_words(a: list[int], b: list[int]) -> list[int]:
return [x ^ y for x, y in zip(a, b)]
# ---------- 解析密钥 ----------
key_bytes = bytes.fromhex(hex_key)
assert len(key_bytes) == 16, "密钥长度必须为 16 字节 (32 个十六进制字符)"
# 将 16 字节密钥转为 4 个 32 位字(列优先,每个字 4 字节)
w = []
for i in range(0, 16, 4):
w.append(list(key_bytes[i:i+4])) # 按原始字节顺序,不做端序转换
# ---------- 密钥扩展 ----------
for i in range(4, 44): # 总共需要 44 个字
temp = w[i-1][:]
if i % 4 == 0:
temp = subword(rotword(temp))
temp[0] ^= rcon[i // 4]
w.append(xor_words(w[i-4], temp))
# 将 44 个字展平为 176 字节的顺序列表
expanded_bytes = []
for word in w:
expanded_bytes.extend(word)
# ---------- 格式化输出 ----------
lines = []
for i in range(0, len(expanded_bytes), 16):
chunk = expanded_bytes[i:i+16]
hex_chunk = ", ".join(f"0x{b:02X}" for b in chunk)
lines.append(f" {hex_chunk}")
inner = ",\n".join(lines)
return "{\n" + inner + "\n}"
if __name__ == "__main__":
key_hex = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
cpp_vec = aes128_key_expansion_cpp_vector(key_hex)
print(cpp_vec)
密钥拓展结果,一个11个轮密钥,因为对于AES-128而言总共进行的轮密钥加次数为11

三、编写汇编并硬编码密文和各轮密钥
分别将密文和拓展密钥放入汇编代码数据段中

完整汇编代码
asm
global main
extern puts
section .text
;-----------------------------------------------------------
; 主函数
;-----------------------------------------------------------
main:
sub rsp, 28h ; 1. 开辟栈帧 (影子空间+对齐)
call get_rip
get_rip:
pop rdi ; RDI 现在指向 call 指令的下一条指令地址
lea rcx, [rel ciphertext] ; 密文
lea rdx, [rel round_keys] ; 轮密钥
lea r8, [rel decrypted_data] ; 输出缓冲
; 调用解密
call AES128_Decrypt
; 打印结果
lea rcx, [rel msg_done]
call puts
add rsp, 28h
xor rax, rax
ret
;-----------------------------------------------------------
; AES-128 解密核心 11轮,其中第一个密钥加使用pxor指令,之后进行9轮换行列加使用aesdec指令,最后进行一轮没有列混合的轮使用aesdeclast指令
;-----------------------------------------------------------
AES128_Decrypt:
movdqu xmm0, [rcx] ; 加载密文
; 初始轮密钥加
movdqu xmm1, [rdx + 160] ; 取第10轮密钥
pxor xmm0, xmm1
; 主循环
mov r9, 9
mov r10, rdx
add r10, 144 ; 指向第9轮密钥
.loop_dec:
movdqu xmm1, [r10]
aesimc xmm1, xmm1
aesdec xmm0, xmm1
sub r10, 16
dec r9
jnz .loop_dec
; 最后一轮
movdqu xmm1, [rdx] ; 取第0轮密钥
aesdeclast xmm0, xmm1
; 输出
movdqu [r8], xmm0
ret
section .data
;-----------------------------------------------------------
; 数据段
;-----------------------------------------------------------
ciphertext: db 0x1F, 0x53, 0x56, 0xD7, 0x1B, 0x42, 0xB7, 0xF2, 0x61, 0x22, 0x6D, 0x97, 0x3A, 0xB8, 0xCA, 0x0C
round_keys:
db 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
db 0xC0, 0x39, 0x34, 0x78, 0x84, 0x6C, 0x52, 0x0F, 0x0C, 0xF5, 0xF8, 0xB4, 0xC0, 0x28, 0x16, 0x4B,
db 0xF6, 0x7E, 0x87, 0xC2, 0x72, 0x12, 0xD5, 0xCD, 0x7E, 0xE7, 0x2D, 0x79, 0xBE, 0xCF, 0x3B, 0x32,
db 0x78, 0x9C, 0xA4, 0x6C, 0x0A, 0x8E, 0x71, 0xA1, 0x74, 0x69, 0x5C, 0xD8, 0xCA, 0xA6, 0x67, 0xEA,
db 0x54, 0x19, 0x23, 0x18, 0x5E, 0x97, 0x52, 0xB9, 0x2A, 0xFE, 0x0E, 0x61, 0xE0, 0x58, 0x69, 0x8B,
db 0x2E, 0xE0, 0x1E, 0xF9, 0x70, 0x77, 0x4C, 0x40, 0x5A, 0x89, 0x42, 0x21, 0xBA, 0xD1, 0x2B, 0xAA,
db 0x30, 0x11, 0xB2, 0x0D, 0x40, 0x66, 0xFE, 0x4D, 0x1A, 0xEF, 0xBC, 0x6C, 0xA0, 0x3E, 0x97, 0xC6,
db 0xC2, 0x99, 0x06, 0xED, 0x82, 0xFF, 0xF8, 0xA0, 0x98, 0x10, 0x44, 0xCC, 0x38, 0x2E, 0xD3, 0x0A,
db 0x73, 0xFF, 0x61, 0xEA, 0xF1, 0x00, 0x99, 0x4A, 0x69, 0x10, 0xDD, 0x86, 0x51, 0x3E, 0x0E, 0x8C,
db 0xDA, 0x54, 0x05, 0x3B, 0x2B, 0x54, 0x9C, 0x71, 0x42, 0x44, 0x41, 0xF7, 0x13, 0x7A, 0x4F, 0x7B,
db 0x36, 0xD0, 0x24, 0x46, 0x1D, 0x84, 0xB8, 0x37, 0x5F, 0xC0, 0xF9, 0xC0, 0x4C, 0xBA, 0xB6, 0xBB
;解密数据的缓冲区
decrypted_data: times 16 db 0
msg_done: db 'Decryption Finished!', 0
四、测试解密
1.解密效果
这里汇编中没有输出解密后的内容,使用x64dbg进行调试
解密结果如下

解密过程大致如下:
- 第一轮密钥加,使用最后一个轮密钥
- 9轮完整的迭代,完整进行字节代换,行移位,列混合,轮密钥加
- 最后一轮迭代,进行字节代换,行移位,轮密钥加
具体实现过程可参考标准AES的实现,网上也有许多手搓版AES代码
2.一些指令说明
- pxor xmm0, xmm1 xmm0异或上xmm1
- aesimc xmm1, xmm1 xmm1进行列混合
- aesdec xmm0, xmm1 使用xmm1作为轮密钥进行各轮解密迭代,自动完成字节代换,行移位,列混合,轮密钥加
- aesdeclast xmm0, xmm1 最后一轮解密,缺少列混合
3.xmm寄存器说明
xmm0 是 x86 和 x64 架构 CPU 中的一个128 位宽的寄存器,它是 SSE(Streaming SIMD Extensions,流式 SIMD 扩展)指令集的一部分。
你可以把它理解为一个专门用来进行高效并行计算的"高速工作区"
由于它有 128 位的宽度,可以一次性存储和处理多组数据,这正是 SIMD(单指令多数据流)技术的核心。它可以同时存放:
- 4 个 单精度浮点数(float)
- 2 个 双精度浮点数(double)
- 16 个 字节(char)
- 2 个 64 位整数
- 以及其他多种数据组合
这使得 CPU 可以用一条指令同时对多组数据进行相同的运算,极大地提升了图形处理、科学计算、音视频编解码等领域的性能。