007bsd/ml-kem-key-recovery
GitHub: 007bsd/ml-kem-key-recovery
针对 wolfSSL 中 ML-KEM 实现的 Fujisaki-Okamoto 对比不完整缺陷,利用解密噪声回归方法从实时二进制文件完整恢复 ML-KEM-1024 私钥的安全研究项目。
Stars: 0 | Forks: 0
# 从 wolfSSL ML-KEM 中部分 Fujisaki-Okamoto 对比中完整恢复密钥
CVE-2026-6330 (NEON) 和 CVE-2026-10097 (AVX2)。已在 wolfSSL 5.9.2 中修复。
## 简介
ML-KEM (Kyber, [FIPS 203](https://csrc.nist.gov/pubs/fips/203/final)) 能够抵御
[选择密文攻击](https://en.wikipedia.org/wiki/Chosen-ciphertext_attack),这得益于解封装内部的一项检查:接收方重新加密其刚刚解密的消息,并且仅当结果与输入密文完全匹配时,才返回真实的共享密钥。任何不匹配都会触发隐式拒绝,并改为返回一个伪随机值。该检查即为 [Fujisaki-Okamoto 转换](https://eprint.iacr.org/2017/604),这是将 [IND-CCA2](https://en.wikipedia.org/wiki/Ciphertext_indistinguishability) 方案与底层可延展的 [IND-CPA](https://en.wikipedia.org/wiki/Ciphertext_indistinguishability) 方案分隔开的唯一屏障。
wolfSSL 使用手写的 [SIMD](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data) 汇编实现了该对比,并且在两个后端上,它仅对比了部分密文。在 ARM64 [NEON](https://en.wikipedia.org/wiki/ARM_architecture_family) 上它对比了大约一半的内容,这部分由 [Nicholas Carlini](https://nicholas.carlini.com/)([维基百科](https://en.wikipedia.org/wiki/Nicholas_Carlini))发现并报告([CVE-2026-6330](https://www.cve.org/CVERecord?id=CVE-2026-6330))。在 x86-64 [AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions) 上,它对比了 ML-KEM-1024 中 1568 字节里的 1536 字节([CVE-2026-10097](https://www.cve.org/CVERecord?id=CVE-2026-10097))。
在上述任一后端上,被篡改的密文都会被当作真实密文接受,这被报告为对 IND-CCA2 安全性的削弱。本文表明该缺陷在两个后端上都具有更深远的影响。检查跳过的字节泄露了解封装的解密噪声,而该噪声是密钥的线性函数,因此可以通过[最小二乘回归](https://en.wikipedia.org/wiki/Least_squares)恢复密钥。这不是一个格问题,也不是经典的密钥不匹配攻击:在 AVX2 后端上,该缺陷验证了全部的 `u`,因此这些攻击所需的选择 `u` 密文会被拒绝。相反,解密噪声回归通过未检查的 `v` 系数恢复密钥。
针对两个 AVX2 和 NEON 后端上的实时易受攻击二进制文件,我们实现了端到端地完整恢复 ML-KEM-1024 私钥。
该攻击需要复用 ML-KEM 密钥:例如 HPKE 接收者、KEMTLS,或固定和嵌入式密钥。临时混合 [TLS 1.3](https://www.rfc-editor.org/rfc/rfc8446) 密钥共享在每次握手时使用全新的密钥,因此无法通过这种方式恢复密钥;在这种情况下,该缺陷仅构成区分性破坏。这两个缺陷均已修复且已公开,本文是一篇漏洞披露后的分析文章。
## 两个实例
| | NEON ([CVE-2026-6330](https://www.cve.org/CVERecord?id=CVE-2026-6330)) | AVX2 ([CVE-2026-10097](https://www.cve.org/CVERecord?id=CVE-2026-10097)) |
|---|---|---|
| 后端 | ARM64 NEON | x86-64 AVX2 |
| 缺陷 | 仅对比了约一半的密文 | 对比了 1568 字节中的 1536 字节 |
| 缺陷报告者 | [Nicholas Carlini](https://nicholas.carlini.com/) (Anthropic) | [007bsd](https://github.com/007bsd) |
| CVE 严重程度 | 中等 (CVSS 4.0 6.3, CWE-327) | 高 (CVSS 4.0 8.3, CWE-697) |
| 密钥恢复,模型 | 完整 (~500 ct) | 完整 (~1300 ct) |
| 密钥恢复,实时二进制 | 98.5% @ 600 ct (QEMU 模拟) | 98.1% @ 350 ct (原生) |
| 修复 | PR [#10192](https://github.com/wolfSSL/wolfssl/pull/10192) | PR [#10430](https://github.com/wolfSSL/wolfssl/pull/10430) |
“实时”指的是在真实二进制文件上的演示结果:NEON 需要更多的密文(600 对比 350),因为其单系数测量值的噪声要大得多(约 4 倍)。“模型”是一个无噪声检查,旨在验证回归能够恢复完整的密钥(全部 2048 个系数,100%);其密文计数取决于每个密文能产生多少方程,而不是取决于噪声,因此它无法与实时数据相提并论,也不能反映攻击的难度。
这两个缺陷是在同一个 wolfSSL 发布窗口期被独立发现的,并在 [5.9.2](https://github.com/wolfSSL/wolfssl/releases/tag/v5.9.2-stable) 版本中一并修复(两个 CVE 条目请参见 wolfSSL 的[安全漏洞页面](https://www.wolfssl.com/docs/security-vulnerabilities/))。Carlini 发现的 NEON 漏洞被记录为对 IND-CCA2 的削弱,而 AVX2 漏洞则被分配了用于密钥恢复的 CVE 编号。本仓库中的解密噪声回归攻击可在两者上恢复密钥。针对特定后端的详细信息请参阅
[`neon-cve-2026-6330/`](neon-cve-2026-6330/) 和
[`avx2-cve-2026-10097/`](avx2-cve-2026-10097/)。
## 常见问题解答
### 漏洞是什么?
wolfSSL 的 ML-KEM 隐式拒绝检查中存在不完整的对比,该问题存在于两个 SIMD 汇编后端中。由于它对比的密文字节数少于全部,因此解封装会接受正确实现本应拒绝的密文。未检查的字节将解封装变成了一个解密噪声的预言机,当密钥被复用时,这就足以恢复私钥。
### 我受到影响吗?
如果您在带有易受攻击的 SIMD 汇编构建(5.7.0-5.9.1 版本的 AVX2 (x86-64),或 5.7.4-5.9.1 版本的 ARM64 NEON)的 wolfSSL 中使用了 ML-KEM,您就会受到影响。密钥恢复攻击还需要在多次解封装中复用 ML-KEM 私钥,例如 [HPKE](https://www.rfc-editor.org/rfc/rfc9180) 接收者、[KEMTLS](https://eprint.iacr.org/2020/534),或者固定的、嵌入的密钥。临时混合 TLS 1.3 密钥共享在每次握手时使用全新的密钥,无法通过这种方式恢复密钥;在这种情况下,该缺陷仅构成区分性破坏。修复方案包含在 wolfSSL 5.9.2 版本中。
### 攻击者能做什么?
在任一后端上恢复完整的 ML-KEM-1024 密钥,方法是发送精心构造的解封装查询,并观察每次查询返回的是真实密钥还是拒绝值。针对实时二进制文件,这可以通过大约 10^5 到 10^6 次解封装查询来恢复密钥。
### 攻击是如何运作的?
以未检查区域内的一个密文系数为例。其明文位由舍入决定,即 `m'_j = Compress_1(v_j - (s^T u)_j)`。由于这些字节没有被对比,通过扫描 `v_j` 的压缩值并观察唯一发生变化的解封装输出,可以定位到一个舍入边界,而该边界位置以大约 ±q/64 的精度测量解密噪声 `δ_j`。用密钥 `(s, e)` 和攻击者选择的加密随机数表示为:
```
δ_j = ( e^T y - s^T(e1 + c_u) + e2 + c_v )_j (verified exact; small; never wraps mod q)
```
这是一个关于 2048 系数密钥 `(s, e)` 的线性方程,其系数是攻击者已知的。每个密文为每个未检查的系数提供了一个这样的方程。堆叠足够的密文并求解正规方程即可恢复整个密钥,最后几个系数由公钥关系 `e = t - A·s ∈ CBD(η)` 确定。这是普通的最小二乘法,而不是[格问题](https://en.wikipedia.org/wiki/Lattice-based_cryptography)。
这两个后端的泄露程度有所不同。NEON 留下了约 50% 的密文未被检查(分布在三个频带的 125 个系数),而 AVX2 约为 2%(分布在一个频带的 51 个系数)。NEON 仍然需要更多的密文,因为其未检查的字节是不连续的,且单系数测量的噪声更大,因此在这里泄露更多信息并不能使恢复变得更容易。
### 为什么常规的 ML-KEM 密钥恢复攻击在此不适用?
明文检查和密钥不匹配攻击(Ravi 等人 2020,Qin 等人 2021,Băetu 等人 2019)通过提交带有攻击者选择的稀疏 `u` 的密文来隔离每次查询中的一个密钥系数,从而能在几千次查询中恢复密钥。AVX2 漏洞拒绝了所有这些密文:它仅跳过了 `v` 的 32 个字节并验证了整个 `u`,因此在实时二进制文件上,稀疏 `u` 密文会被拒绝,并且翻转 `u` 的单个位在 30 次测试中有 30 次被拒绝。NEON 漏洞范围更广,还留下了约一半的 `u` 未被检查,因此该论点仅适用于 AVX2;但该攻击并不依赖于此。解密噪声回归通过两个后端上未检查的 `v` 系数恢复密钥,能够抵御每个漏洞留下的完好检查部分。
### 该漏洞是如何被演示的?
在两个后端的忠实参考模型 中,上述等式被验证为精确的,并且回归恢复了全部 2048 个密钥系数。针对修复前的实时 wolfSSL 二进制文件,在攻击导出的复用密钥时,每个测试工具在报告任何数据之前,都会针对预言机导出的真实密钥运行自检:
- AVX2(原生 x86-64):65.5% (100 ct),87.8% (200 ct),96.9% (350 ct),在 400 个密文时达到了完整密钥 `(s, e)` 的 98.0%。仅密钥 `s` 在 350 ct 时为 1005/1024 = 98.1%,这是记录在 CVE 中的数据。
- NEON(QEMU 模拟下的 ARM64):45.7% (50 ct),85.2% (200 ct),在 600 个密文时达到了完整密钥 `(s, e)` 的 2018/2048 = 98.5%,求解器误差单调收敛至精确值。
恢复的密钥是预言机导出的、由 wolfSSL 生成的密钥对,并且该攻击针对的是发布版本的 SIMD 汇编,而不是它的模型。完整记录:
[`avx2-cve-2026-10097/live_recover_avx2.out`](avx2-cve-2026-10097/live_recover_avx2.out),
[`neon-cve-2026-6330/live_recover_neon.out`](neon-cve-2026-6330/live_recover_neon.out)。
### 我该如何修复它?
升级到 wolfSSL 5.9.2 或更高版本(针对 AVX2 的 PR #10430,针对 NEON 的 PR #10192)。
### 这有多严重?
严重程度高,但不是灾难性的。它需要复用密钥、接受/拒绝预言机以及大量但实际可行的查询。它不是[侧信道](https://en.wikipedia.org/wiki/Side-channel_attack)攻击:没有时间或功耗测量,仅仅是对比中的逻辑漏洞。它不影响正确的实现或 ML-KEM 标准本身。作为对比,liboqs 的 ML-KEM 解封装中编译器引起的时间泄露([CVE-2024-36405](https://www.cve.org/CVERecord?id=CVE-2024-36405)),即 2024 年伴随着 [KyberSlash](https://eprint.iacr.org/2024/1049) 出现的一波 ML-KEM 时间泄露中相关的完整私钥恢复问题,被 NIST 评级为 CVSS 7.5。
## 复现
各后端的攻击代码、分析和复现步骤位于
[`avx2-cve-2026-10097/`](avx2-cve-2026-10097/) 和
[`neon-cve-2026-6330/`](neon-cve-2026-6330/)。
## 参考文献
1. wolfSSL. [CVE-2026-6330](https://www.cve.org/CVERecord?id=CVE-2026-6330) (NEON, N. Carlini) · [NVD](https://nvd.nist.gov/vuln/detail/CVE-2026-6330) · PR [#10192](https://github.com/wolfSSL/wolfssl/pull/10192).
2. wolfSSL. [CVE-2026-10097](https://www.cve.org/CVERecord?id=CVE-2026-10097) (AVX2) · [NVD](https://nvd.nist.gov/vuln/detail/CVE-2026-10097) · PR [#10430](https://github.com/wolfSSL/wolfssl/pull/10430).
3. P. Ravi, S. S. Roy, A. Chattopadhyay, S. Bhasin. Generic Side-channel Attacks on CCA-secure lattice-based PKE and KEMs. TCHES 2020(3).
4. Y. Qin, C. Cheng, X. Zhang, Y. Pan, L. Hu, J. Ding. A Systematic Approach and Analysis of Key Mismatch Attacks on Lattice-Based NIST Candidate KEMs. ASIACRYPT 2021.
5 C. Băetu, F. B. Durak, L. Huguenin-Dumittan, A. Talayhan, S. Vaudenay. Misuse Attacks on Post-Quantum Cryptosystems. EUROCRYPT 2019.
6. J.-P. D'Anvers et al. Decryption Failure Attacks on IND-CCA Secure Lattice-Based Schemes. PKC 2019.
7. NIST. [FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard](https://csrc.nist.gov/pubs/fips/203/final).
8. liboqs ML-KEM compiler-induced timing leak. [CVE-2024-36405](https://www.cve.org/CVERecord?id=CVE-2024-36405) (NIST CVSS 7.5). Distinct from but concurrent with KyberSlash (secret-dependent division timing), D. J. Bernstein et al., [ePrint 2024/1049](https://eprint.iacr.org/2024/1049).
## 披露
这两个问题均已被私下报告、修复,并在本文发布前分配了 CVE 编号。已在 wolfSSL 5.9.2 中修复。
标签:身份验证强制, 逆向工具