
wolfSSL의 부분적 Fujisaki-Okamoto 비교로부터 ML-KEM-1024 전체 키 복구 (CVE-2026-6330 NEON, CVE-2026-10097 AVX2)
CVE-2026-6330 (NEON) 및 CVE-2026-10097 (AVX2). wolfSSL 5.9.2에서 수정됨.
전체 기술 문서는
Cryptology ePrint Archive, Paper 2026/1682로 게시됨
(paper/에 로컬 사본). 아래 인용 참조.
ML-KEM (Kyber, FIPS 203)은 선택 암호문 공격에 저항합니다. 그 이유는 복호화 내부의 한 검사 때문입니다: 수신자는 방금 복호화한 메시지를 다시 암호화하고, 결과가 입력 암호문과 정확히 일치하는 경우에만 실제 공유 비밀을 반환합니다. 불일치가 발생하면 암시적 거부가 트리거되고, 대신 의사난수 값이 반환됩니다. 이 검사가 바로 Fujisaki-Okamoto 변환으로, IND-CCA2 체계를 그 아래의 가변적인 IND-CPA 체계와 구분하는 단일 게이트입니다.
wolfSSL은 이 비교를 손으로 작성한 SIMD 어셈블리로 구현했으며, 두 백엔드에서는 암호문의 일부만 비교했습니다. ARM64 NEON에서는 약 절반을 비교했으며, 이를 Nicholas Carlini ()가 발견하여 보고했습니다 (). x86-64 에서는 ML-KEM-1024의 1568바이트 중 1536바이트를 비교했습니다 ().
두 백엔드 모두에서 변조된 암호문이 진짜로 수용되며, 이는 IND-CCA2 보안의 약화로 보고되었습니다.
이 문서는 두 백엔드 모두에서 결함이 더 나아간다는 것을 보여줍니다. 검사가 건너뛰는 바이트는
복호화의 복호화 노이즈를 누출하며, 이 노이즈는 비밀 키의 선형 함수이므로
최소제곱 회귀로 키를 복구할 수 있습니다.
이는 격자 문제가 아니며, 고전적인 키 불일치 공격도 아닙니다: AVX2 백엔드에서는
결함이 u 전체를 검증하므로, 해당 공격에 필요한 선택된 u 암호문은 거부됩니다.
대신 복호화 노이즈 회귀는 검사되지 않은 v-계수에서 키를 복구합니다.
전체 ML-KEM-1024 개인 키는 AVX2 및 NEON 백엔드 모두에서 실제 취약한 바이너리에 대해
엔드투엔드로 복구됩니다.
이 공격은 재사용된 ML-KEM 키가 필요합니다: HPKE 수신자, KEMTLS, 또는 고정 및 내장 키. 임시 하이브리드 TLS 1.3 키 공유는 핸드셰이크마다 새 키를 사용하며 이 방식으로 키를 복구할 수 없습니다. 그 경우 결함은 단지 구별 공격일 뿐입니다. 두 결함 모두 수정되었고 공개되었으며, 이는 공개 후 문서입니다.
| NEON (CVE-2026-6330) | AVX2 (CVE-2026-10097) | |
|---|---|---|
| 백엔드 | ARM64 NEON | x86-64 AVX2 |
| 결함 | 암호문의 약 절반 비교 | 1568바이트 중 1536바이트 비교 |
| 보고자 | Nicholas Carlini (Anthropic) | 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 | PR #10430 |
"실제"는 실제 바이너리에서 입증된 결과입니다: NEON은 계수당 측정이 훨씬 더 시끄럽기 때문에 (약 4배) 더 많은 암호문이 필요합니다 (600 vs 350). "모델"은 회귀가 전체 키를 복구하는지 (2048개 계수 모두, 100%) 확인하는 노이즈 없는 검사입니다. 그 암호문 수는 노이즈가 아닌 각 암호문이 생성하는 방정식 수에 의해 결정되므로 실제 수치와 비교할 수 없으며 공격 난이도를 반영하지 않습니다.
두 결함은 동일한 wolfSSL 릴리스 기간에 독립적으로 발견되었으며
5.9.2에서 함께 수정되었습니다
(두 CVE 항목 모두 wolfSSL
보안 취약점 페이지 참조).
Carlini의 NEON 버그는 IND-CCA2 약화로 문서화되었고, AVX2 버그는 키 복구로 CVE가 지정되었습니다.
이 저장소의 복호화 노이즈 회귀 공격은 두 백엔드 모두에서 키를 복구합니다.
백엔드별 세부 사항은
neon-cve-2026-6330/ 및
avx2-cve-2026-10097/에 있습니다.
wolfSSL의 ML-KEM 암시적 거부 검사에서의 불완전한 비교로, 두 SIMD 어셈블리 백엔드에 존재합니다. 암호문 바이트 전체보다 적은 양을 비교하므로, 올바른 구현이 거부하는 암호문을 복호화가 수용합니다. 검사되지 않은 바이트는 복호화를 복호화 노이즈에 대한 오라클로 만들며, 키가 재사용될 때 개인 키를 복구하기에 충분합니다.
취약한 SIMD 어셈블리가 포함된 빌드에서 wolfSSL을 ML-KEM과 함께 사용했다면 영향을 받습니다: AVX2 (x86-64) 5.7.0-5.9.1, 또는 ARM64 NEON 5.7.4-5.9.1. 키 복구 공격은 추가로 ML-KEM 개인 키가 복호화 간에 재사용되어야 합니다. 예를 들어 HPKE 수신자, KEMTLS, 또는 고정 또는 내장 키가 있습니다. 임시 하이브리드 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의 압축 값을 스윕하고 변경되는 하나의 복호화 출력을 관찰하면 반올림 경계를 찾을 수 있으며,
경계 위치는 복호화 노이즈 δ_j를 약 ±q/64의 정밀도로 측정합니다. 비밀 (s, e) 및
공격자가 선택한 암호화 난수 측면에서:
δ_j = ( e^T y - s^T(e1 + c_u) + e2 + c_v )_j (정확히 검증됨; 작음; mod q로 래핑되지 않음)
이는 2048-계수 비밀 (s, e)의 선형 방정식이며, 계수는 공격자가 알고 있습니다.
각 암호문은 검사되지 않은 계수당 하나의 방정식을 제공합니다. 충분한 암호문을 쌓고
정규 방정식을 풀면 전체 키가 복구되며, 마지막 몇 개의 계수는 공개 키 관계
e = t - A·s ∈ CBD(η)로 고정됩니다. 이는 격자 문제가
아닌 일반적인 최소제곱입니다.
두 백엔드는 누출량이 다릅니다. NEON은 암호문의 약 50%를 검사하지 않습니다 (세 밴드에서 125개 계수), AVX2는 약 2% (한 밴드에서 51개 계수)입니다. NEON은 여전히 더 많은 암호문이 필요합니다. 검사되지 않은 바이트가 비연속적이고 계수당 측정이 더 시끄럽기 때문에, 더 많이 누출해도 여기서 복구가 더 쉬워지지 않습니다.
평문 확인 및 키 불일치 공격 (Ravi et al. 2020, Qin et al. 2021, Băetu et al. 2019)은
공격자가 선택한 희소 u를 가진 암호문을 제출하여 쿼리당 하나의 비밀 계수를 분리함으로써
수천 개의 쿼리로 키를 복구합니다. AVX2 결함은 이를 모두 거부합니다: v의 32바이트만 건너뛰고
u 전체를 검증하므로, 실제 바이너리에서 희소 u 암호문은 거부되고 단일 u 비트를 뒤집는 것은
30번 중 30번 거부됩니다. NEON 결함은 더 광범위하여 u의 약 절반도 검사하지 않으므로
그 논증은 AVX2에만 해당됩니다. 그러나 공격은 이에 의존하지 않습니다.
복호화 노이즈 회귀는 두 백엔드 모두에서 검사되지 않은 v-계수에서 키를 복구하며,
각 버그가 온전하게 남겨둔 검사 부분을 통과합니다.
따라서 관련 선례는 키 불일치 공격이 아니라 복호화 실패 공격입니다 (D'Anvers et al. 2019, ref 6). 이들은 동일한 복호화 노이즈 항, 즉 비밀의 선형 함수를 활용하지만, 해당 항이 디코딩 경계를 넘어 복호화 실패를 일으키는 드문 사건을 통해서만 활용하므로 복구는 통계적이며 훨씬 더 많은 암호문이 필요합니다. 반면 불완전한 비교는 동일한 항을 약 ±q/64로 직접 측정 가능하게 만들므로 실패가 필요 없고 공격은 위의 일반적인 최소제곱 회귀로 축소됩니다.
두 백엔드 모두에 대한 충실한 참조 모델 (kyber-py)에서 위의 항등식이 정확히 검증되었고 회귀가 2048개 비밀 계수를 모두 복구합니다. 수정 전 실제 wolfSSL 바이너리에 대해 재사용된 내보낸 키를 공격할 때, 각 하네스는 숫자를 보고하기 전에 오라클의 내보낸 실측 키에 대한 자체 검사를 실행합니다:
(s, e)의 98.0%에 도달. 비밀 s 단독은 350 ct에서 1005/1024 = 98.1%로,
CVE에 기록된 수치입니다.(s, e)의 2018/2048 = 98.5%에 도달, 솔버 오류가 단조롭게 정확으로 수렴.복구된 키는 오라클이 내보내는 wolfSSL 생성 키페어이며, 공격은 모델이 아닌
배포된 형태의 SIMD 어셈블리에 대해 실행됩니다. 전체 기록:
avx2-cve-2026-10097/live_recover_avx2.out,
neon-cve-2026-6330/live_recover_neon.out.
높음, 그러나 치명적이지는 않습니다. 재사용된 키, 수락/거부 오라클, 그리고 크지만 실용적인 수의 쿼리가 필요합니다. 이는 부채널이 아닙니다: 타이밍이나 전력 측정이 없으며, 비교의 논리 버그일 뿐입니다. 올바른 구현이나 ML-KEM 표준 자체에는 영향을 미치지 않습니다. 비교를 위해, liboqs의 ML-KEM 복호화에서 컴파일러 유발 타이밍 누출 (CVE-2024-36405)은 KyberSlash와 함께 2024년 ML-KEM 타이밍 누출 물결의 관련 전체 비밀 키 복구 문제로, NIST에서 CVSS 7.5로 평가되었습니다.
백엔드별 공격 코드, 분석 및 재현 단계는
avx2-cve-2026-10097/ 및
neon-cve-2026-6330/에 있습니다.
이 저장소는 동일한 wolfSSL 릴리스 기간의 두 형제 발견과 둘 다를 깨는 하나의 공격을 문서화합니다.
두 문제 모두 이 문서 작성 전에 비공개로 보고되고 수정되었으며 CVE가 지정되었습니다. wolfSSL 5.9.2에서 수정됨.
전체 문서는
Cryptology ePrint Archive, Paper 2026/1682로 게시됨
(로컬 사본: paper/).
@misc{cryptoeprint:2026/1682,
author = {Bhabani Sankar Das},
title = {Incomplete Ciphertext Comparison in {ML}-{KEM}: From an {IND}-{CCA2} Break to Key Recovery},
howpublished = {Cryptology {ePrint} Archive, Paper 2026/1682},
year = {2026},
url = {https://eprint.iacr.org/2026/1682}
}