汇编使用AES指令集实现AES解密

一、使用在线加密网站计算密文

为简单演示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 可以用一条指令同时对多组数据进行相同的运算,极大地提升了图形处理、科学计算、音视频编解码等领域的性能。
相关推荐
SilentSamsara1 小时前
闭包的本质:Python 如何捕获自由变量
开发语言·python·青少年编程·pycharm
段一凡-华北理工大学2 小时前
【高炉炼铁领域炉温监测、预警、调控智能体设计与应用】~系列文章10:实时预警机制:跑在问题前面!
网络·人工智能·python·知识图谱·高炉炼铁·工业智能体
小熊Coding2 小时前
童年游戏冒险岛(Python版本)
python·游戏·pygame
WJ.Polar2 小时前
Scapy基本应用
linux·运维·网络·python
H_unique3 小时前
LangChain:调用工具Ⅲ
python·langchain
醉舞经阁半卷书13 小时前
深入掌握LangChain
python·langchain
CDN3603 小时前
[硬核] 你的DNS正在“裸奔”?用Python手撕DNS劫持与隧道检测逻辑
开发语言·网络·python
kybs19913 小时前
springboot视频推荐系统--附源码72953
java·spring boot·python·eclipse·asp.net·php·idea
BU摆烂会噶5 小时前
【LangGraph】运行时上下文(Runtime Context)
人工智能·python·langchain