CVE-2026-22698
RustCrypto SM2-PKE has 32-bit Biased Nonce Vulnerability
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.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.7
RustCrypto SM2-PKE has 32-bit Biased Nonce Vulnerability
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.
- Record
CVE-2026-22698- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-331
- Updated
- 2026-11-02
EUVDEUVD-2026-1876
8.7
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.
- Record
EUVD-2026-1876- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-w3g8-fp6j-wvqw
8.7
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.
As a result, the ephemeral noncefn 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)?; // ... }kis 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
//! Example: Recover low-entropy nonce k via Baby-Step Giant-Step (BSGS)
//!
//! This example intentionally demonstrates an attack on the vulnerable
//! `EncryptingKey::encrypt` implementation which (in the current repository
//! state) may generate k with only 32 bits of entropy. The example:
//! - Generates a key pair and encrypts a short plaintext.
//! - Extracts C1 from the ciphertext (ephemeral public key [k]G).
//! - Runs BSGS over the reduced search space 2^32 to recover k and decrypt: time O(2^16), space O(2^16).
//!
use std::collections::HashMap;
use std::error::Error;
use rand_core::OsRng;
use sm2::{
pke::Mode,
pke::EncryptingKey,
PublicKey,
SecretKey,
AffinePoint,
ProjectivePoint,
Scalar,
};
use elliptic_curve::bigint::U256;
use elliptic_curve::{Group, Curve};
use elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
use sm3::{Sm3, Digest};
/// Baby-step giant-step over the 32-bit search space.
fn bsgs_recover_k(c1: &AffinePoint) -> Option<U256> {
//…
- Record
GHSA-w3g8-fp6j-wvqw- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-331
- Updated
- 2026-11-02
NVD
8.7
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.
- Record
CVE-2026-22698- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-331
- Updated
- 2026-11-02
OSV
8.7
RustCrypto SM2-PKE has 32-bit Biased Nonce Vulnerability
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.
- Record
CVE-2026-22698- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-331
- Updated
- 2026-11-02
OSVGHSA-w3g8-fp6j-wvqw
8.7
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.
As a result, the ephemeral noncefn 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)?; // ... }kis 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
//! Example: Recover low-entropy nonce k via Baby-Step Giant-Step (BSGS)
//!
//! This example intentionally demonstrates an attack on the vulnerable
//! `EncryptingKey::encrypt` implementation which (in the current repository
//! state) may generate k with only 32 bits of entropy. The example:
//! - Generates a key pair and encrypts a short plaintext.
//! - Extracts C1 from the ciphertext (ephemeral public key [k]G).
//! - Runs BSGS over the reduced search space 2^32 to recover k and decrypt: time O(2^16), space O(2^16).
//!
use std::collections::HashMap;
use std::error::Error;
use rand_core::OsRng;
use sm2::{
pke::Mode,
pke::EncryptingKey,
PublicKey,
SecretKey,
AffinePoint,
ProjectivePoint,
Scalar,
};
use elliptic_curve::bigint::U256;
use elliptic_curve::{Group, Curve};
use elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
use sm3::{Sm3, Digest};
/// Baby-step giant-step over the 32-bit search space.
fn bsgs_recover_k(c1: &AffinePoint) -> Option<U256> {
//…
- Record
GHSA-w3g8-fp6j-wvqw- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-331
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
sm2crates.io |
0.14.0-pre.0 to 0.14.0-rc.4 | None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-22698 is a high vulnerability (CVSS 8.7) in Rustcrypto Elliptic-curves, published January 9, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.27%, the 19th percentile. No source names a fixed version.
References
github.com/RustCrypto/elliptic-curves/security/advisories/GHSA-w3g8-fp6j-wvqw
github.com/RustCrypto/elliptic-curves/pull/1600
github.com/RustCrypto/elliptic-curves/commit/4781762f23ff22ab34763410f648128055c93731
github.com/RustCrypto/elliptic-curves/commit/e4f77788130d065d760e57fb109370827110a525
crates.io/crates/sm2/0.14.0-pre.0
crates.io/crates/sm2/0.14.0-rc.0
Left out here: the rest of 2 source descriptions. The JSON record has them.