第 56 章 后量子密码(PQC)逆向
2025 年,NIST 正式发布 FIPS 203/204/205(ML-KEM/ML-DSA/SLH-DSA),后量子密码从论文走进现实。未来十年,逆向工程师会越来越多地在程序里见到这些新算法。本章讲 PQC 基础、逆向识别方法、以及与经典密码学的对比。
📍 知识点地图 | 主题:后量子密码 | 前置:第34章 | 后续:— | 核心概念:ML-KEM/DSA、识别信号、审计要点
56.1 为什么需要 PQC(背景知识)
问题: 量子计算机(尤其 Shor 算法)可以多项式时间破解:
RSA(大整数分解)
ECDSA/ECDH(离散对数)
→ 所有基于 RSA/ECC 的 TLS/签名/加密都将失效
时间线(2025-2030):
□ 2024: NIST 选定 ML-KEM/ML-DSA/SLH-DSA
□ 2025: FIPS 203/204/205 正式发布
□ 2025-2028: 过渡期(混合模式: 经典+量子混合)
□ 2030s: 全面迁移目标
"先收集后解密"威胁: 攻击者现在收集密文,等量子计算机可用时再解密
→ 高价值数据需要立即开始迁移
56.2 三大标准化算法(认识它们)
ML-KEM(FIPS 203,原 CRYSTALS-Kyber)
类型: 密钥封装机制(KEM)——替代 ECDH
数学基础: 格(Lattice)上的 MLWE 问题(Module-LWE)
参数: ML-KEM-512 / ML-KEM-768 / ML-KEM-1024
核心操作:
KeyGen: 生成公私钥(矩阵 A + 秘密向量)
Encaps: 封装共享密钥(生成封装+共享密钥)
Decaps: 解封装(拿回共享密钥)
特征: 公钥 ~800-1568 字节(比 RSA 小但比 ECC 大)
ML-DSA(FIPS 204,原 CRYSTALS-Dilithium)
类型: 数字签名——替代 ECDSA/RSA 签名
数学基础: 格上的 Fiat-Shamir(MLWE+MSIS)
核心操作: KeyGen / Sign / Verify
特征: 签名 ~2.4-4.6 KB(比 ECDSA 大得多)
SLH-DSA(FIPS 205,原 SPHINCS+)
类型: 数字签名(无状态哈希签名)
数学基础: 哈希函数(唯一纯哈希方案)
核心操作: 多叉树 Merkle + Winternitz OTS
特征: 签名大(~7-49 KB)、密钥小、安全保守
用途: 高安全场景/防御纵深
56.3 在二进制中识别 PQC(逆向视角)
识别信号
□ 库/API 名称: liboqs / OpenSSL 3.5+ / AWS-LC / BoringSSL
(字符串: OQS_、ML-KEM、Kyber、Dilithium、SLH-DSA)
□ 大数据结构: ML-KEM 公钥 800-1568 字节
→ 看到 0x320/0x3C0/0x620 大小的密钥结构
□ 多项式运算特征: 大量 NTT(数论变换)循环、模运算
(q = 3329 for ML-KEM / 8380417 for ML-DSA——独特的素数!)
□ 采样操作: 中心二项分布采样(CBD)、拒绝采样
□ 哈希使用: SHA3/SHAKE(Keccak 家族,ML-KEM/DSA 的内核)
□ TLS 场景: 混合握手(X25519MLKEM768 等 TLS 组名)
关键魔数速查(一眼识别的"指纹")
ML-KEM 模数: q = 3329(16 位素数)
ML-DSA 模数: q = 8380417(23 位素数)
NTT 根/尺寸: 256 点 NTT
SHA3 状态: Keccak-1600(0x1600/576 字节状态)
Kyber 向量 k: 2(512)/ 3(768)/ 4(1024)
反编译中的典型模式
// NTT 循环(多项式乘法核心)——循环里有模乘
for (i = 0; i < 256; i++)
z[i] = (long)z[i] * zeta[i] % 3329;
// CBD 采样——从随机种子生成秘密向量
// 拒绝采样——查找表 + 条件分支
// Keccak/SHAKE——大状态数组 + 多轮置换
56.4 PQC 逆向目标(分析什么)
| 场景 | 逆向目标 | 方法 |
|---|---|---|
| 确认算法 | 识别 ML-KEM/DSA 及参数 | 魔数+结构+库名 |
| 密钥提取 | 私钥结构(秘密向量) | 找 KeyGen/内存布局 |
| 协议分析 | TLS 混合握手格式 | 抓包+结构解析 |
| 恶意样本 | 是否用 PQC(隐蔽通信) | 库特征+魔数 |
| 审计 | 实现是否安全 | 常数时间/随机数源 |
| 取证 | 签名/封装数据提取 | 结构偏移表 |
56.5 PQC 与经典密码学的对比(逆向影响)
| 维度 | 经典(RSA/ECC) | PQC(格/哈希) |
|---|---|---|
| 密钥/签名大小 | 小(256B-1KB) | 大(1-49KB) |
| 数学基础 | 数论(因子/离散对数) | 格(向量)/哈希 |
| 逆向难度 | 中等(结构简单) | 较高(矩阵/多项式) |
| 攻击面 | 实现错误/参数弱 | 实现错误(拒绝采样/NTT) |
| 侧信道 | 模幂/标量乘 | 多项式乘/采样(时间侧信道敏感) |
| 识别难度 | 低(魔数明确) | 中(需要知识) |
逆向注意点:
□ 大小写敏感: 大密钥 = 大内存区域 → 内存取证更容易发现
□ 采样函数是侧信道重点(非恒定时间 → 时序攻击)
□ NTT/多项式循环是性能瓶颈 → 反编译里最热的函数
□ 混合模式: 先找经典部分(X25519 等)再找 PQC 部分
56.6 PQC 安全审计要点(逆向工程师的增值点)
□ 随机数源: 密钥生成是否用安全 RNG(可预测种子 = 密钥泄露)
□ 恒定时间: NTT/采样是否有分支依赖秘密(时序侧信道)
□ 内存清零: 私钥/共享密钥是否及时擦除
□ 实现正确性: 拒绝采样边界/模数处理(错误 = 漏洞或拒绝服务)
□ 混合模式配置: 是否真的包含 PQC 部分(降级攻击检查)
□ 版本: 使用预发布参数还是 FIPS 正式参数
56.7 实战场景:TLS 混合握手分析
场景: 2026 年的 HTTPS 流量里看到未知的公钥格式
1. 抓包识别(Wireshark 新版支持):
TLS 1.3 的 key_share 扩展里:
组名 0x11EC = X25519MLKEM768(混合模式)
组名 0x11ED = X25519MLKEM1024
2. 解析公钥:
ML-KEM 公钥 = 12*32 字节(k=3 时 384 字节)+ 32 字节种子
3. 确认: 服务器是否真正使用 PQC(降级攻击测试: 只发经典组)
4. 评估: 客户端是否支持纯 PQC(未来兼容性)
56.8 学习路径建议
1. 数学基础: 线性代数(向量/矩阵)+ 模运算(不需要深入格理论)
2. 理解算法: 读 FIPS 203 概述 + 参考实现(kyber/ref 代码可读)
3. 动手: 用 liboqs 生成密钥对 → 观察输出结构(大小/布局)
4. 识别训练: 在二进制里找魔数/结构(56.3)
5. 审计练习: 分析参考实现的恒定时间问题
6. 持续: 关注 OpenSSL 3.5+/工具链的 PQC 支持更新
56.9 检查清单(PQC 逆向)
□ 识别算法(ML-KEM/ML-DSA/SLH-DSA)与参数等级
□ 定位库/API(liboqs/OpenSSL)
□ 提取密钥/签名结构(大小+布局)
□ 分析混合模式配置(TLS/协议层)
□ 审计随机数源与恒定时间
□ 评估降级风险(经典-only fallback)
□ 报告: 算法/参数/实现安全评估
动手练习
- 用 liboqs(或 OpenSSL 3.5+)生成 ML-KEM-768 密钥对,对比公钥大小(~1184 字节),建立"大小直觉"。
- 写一个 Python 脚本:在任意二进制里搜索 3329 和 8380417 的 16/32 位表示,练习魔数识别。
- 反编译一个使用 liboqs 的程序(编译个 demo),在反编译输出里找 NTT 循环和模数常量。
- 抓取一段使用 X25519MLKEM768 的 TLS 流量(现代浏览器+服务器),分析 key_share 结构。
深入阅读
- 仓库:
skills/reverse-engineering/crypto-decode-tools.md(密码工具基础) - 仓库:
skills/reverse-engineering/patterns*.md(算法模式识别方法论) - 仓库:
CTF-Sandbox-Orchestrator/competition-crypto-mobile/(密码学 CTF) - 外部: NIST FIPS 203/204/205、liboqs(GitHub)、OpenSSL 3.5+ 文档