Описание
SM2-PKE has 32-bit Biased Nonce Vulnerability
Summary
A critical vulnerability exists in the SM2 Public Key Encryption (PKE) implementation where the ephemeral nonce k is generated with severely reduced entropy. A unit mismatch error causes the nonce generation function to request only 32 bits of randomness instead of the expected 256 bits. This reduces the security of the encryption from a 128-bit level to a trivial 16-bit level, allowing a practical attack to recover the nonce k and decrypt any ciphertext given only the public key and ciphertext.
Affected Versions
- sm2 0.14.0-rc.0 (https://crates.io/crates/sm2/0.14.0-rc.0)
- sm2 0.14.0-pre.0 (https://crates.io/crates/sm2/0.14.0-pre.0)
This vulnerability is introduced in commit: Commit 4781762 on Sep 6, 2024, which is over a year ago.
Details
The root cause of this vulnerability is a unit mismatch in the encrypt function located in sm2/src/pke/encrypting.rs.
- The code correctly calculates the byte-length of the curve order (256 bits / 8 = 32 bytes) and stores it in a constant
N_BYTES.const N_BYTES: u32 = Sm2::ORDER.as_ref().bits().div_ceil(8); // Value is 32 (bytes) - However, this
N_BYTESvalue is then passed to thenext_khelper function, which incorrectly interprets this value as a bit length.let k = Scalar::from_uint(&next_k(rng, N_BYTES)?).unwrap(); - Inside
next_k, thebit_lengthparameter (which holds the value 32) is passed directly toU256::try_random_bits, a function that generates a random number with the specified number of bits.fn next_k<R: TryCryptoRng + ?Sized>(rng: &mut R, bit_length: u32) -> Result<U256> { let k = U256::try_random_bits(rng, bit_length).map_err(|_| Error)?; // ... }As a result, the ephemeral noncekis generated with only 32 bits of entropy, with its upper 224 bits being zero. This catastrophic loss of randomness makes the encryption scheme insecure.
PoC
A proof-of-concept demonstrating the feasibility of this attack is provided in examples/bsgs_recover.rs. The PoC performs the following steps:
- Encrypt a Message: It uses the vulnerable
EncryptingKey::encryptfunction to encrypt a sample message. - Extract Ephemeral Public Key: It parses the ciphertext to extract
C1, which is the ephemeral public key[k]G. - Recover Nonce
k: It runs a Baby-Step Giant-Step (BSGS) algorithm to search the reduced 2^32 search space for the noncek. This attack is computationally feasible on modern hardware in seconds with time complexityO(2^16). - Decrypt without Secret Key: Once
kis recovered, it computes the shared secret[k]PB(wherePBis the recipient's public key) and successfully decrypts the ciphertext without access to the recipient's secret key.
examples/bsgs_recover.rs
To run the PoC (tested on Apple M3):
Impact
This vulnerability leads to a complete loss of confidentiality for all data encrypted using the SM2 PKE implementation in this library. Any attacker who obtains a ciphertext can recover the plaintext in a feasible amount of time (several seconds).
The severity is Critical, as it breaks the core security promise of the public key encryption scheme. All versions of the sm2 crate with the vulnerable PKE implementation are affected.
-
Fix 1: Modify the input parameter to the correct 256 bits
let k_uint = next_k(rng, N_BYTES * 8)?; -
Fix 2: We believe that the
next_kfunction should only generate a 256-bit nonce to ensure security, therefore the parameter is unnecessary.fn next_k<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<U256> { loop { let k = U256::try_random_bits(rng, 256).map_err(|_| Error)?; if !bool::from(k.is_zero()) && k < *Sm2::ORDER { return Ok(k); } } }
Credit
This vulnerability was discovered by:
- XlabAI Team of Tencent Xuanwu Lab
- Atuin Automated Vulnerability Discovery Engine
CVE and credit are preferred.
If developers have any questions regarding the vulnerability details, please feel free to reach out for further discussion via email at xlabai@tencent.com.
Note
SM2 follows the security industry standard disclosure policy—the 90+30 policy (reference: https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-policy.html). If the aforementioned vulnerabilities cannot be fixed within 90 days of submission, the organization reserves the right to publicly disclose all information about the issues after this timeframe.
Ссылки
- https://github.com/RustCrypto/elliptic-curves/security/advisories/GHSA-w3g8-fp6j-wvqw
- https://nvd.nist.gov/vuln/detail/CVE-2026-22698
- https://github.com/RustCrypto/elliptic-curves/pull/1600
- https://github.com/RustCrypto/elliptic-curves/commit/4781762f23ff22ab34763410f648128055c93731
- https://github.com/RustCrypto/elliptic-curves/commit/e4f77788130d065d760e57fb109370827110a525
- https://crates.io/crates/sm2/0.14.0-pre.0
- https://crates.io/crates/sm2/0.14.0-rc.0
Пакеты
sm2
>= 0.14.0-pre.0, <= 0.14.0-rc.4
Отсутствует
Связанные уязвимости
RustCrypto: Elliptic Curves is general purpose Elliptic Curve Cryptography (ECC) support, including types and traits for representing various elliptic curve forms, scalars, points, and public/secret keys composed thereof. In versions 0.14.0-pre.0 and 0.14.0-rc.0, a critical vulnerability exists in the SM2 Public Key Encryption (PKE) implementation where the ephemeral nonce k is generated with severely reduced entropy. A unit mismatch error causes the nonce generation function to request only 32 bits of randomness instead of the expected 256 bits. This reduces the security of the encryption from a 128-bit level to a trivial 16-bit level, allowing a practical attack to recover the nonce k and decrypt any ciphertext given only the public key and ciphertext. This issue has been patched via commit e4f7778.