Skip to content

ml-kem: encapsulation keys are not validated #172

@karalabe

Description

@karalabe

I've found a discrepancy between this implementation of ML-KEM and the Go one. There's a repro below for a case which is rejected by Go but accepted by Rust. Seems the issue is that public keys loaded from bytes are not validated, but they could be invalid.

//! Reproduction case: ml-kem accepts invalid encapsulation keys
//!
//! ML-KEM encapsulation keys contain polynomial coefficients encoded as 12-bit
//! values. Per FIPS 203, each coefficient must be in the range [0, 3329) where
//! 3329 is the modulus q. The ml-kem crate does not validate this, accepting
//! arbitrary bytes as valid encapsulation keys.
//!
//! Go's crypto/mlkem implementation validates coefficients and rejects invalid keys.

use ml_kem::{EncodedSizeUser, MlKem768Params};
use ml_kem::kem::EncapsulationKey;

fn main() {
    // Create an invalid key: all bytes set to 0xFF
    // When decoded as 12-bit coefficients, this produces values of 0xFFF = 4095 > 3329
    let invalid_key = [0xFFu8; 1184];

    // ml-kem accepts this without error
    let ek = EncapsulationKey::<MlKem768Params>::from_bytes(&invalid_key.into());

    println!("ml-kem accepted invalid key with coefficients >= 3329");
    println!("Encapsulation key bytes: {:?}...", &ek.as_bytes()[..16]);

    // Demonstrate the issue: the first 3 bytes [0xFF, 0xFF, 0xFF] decode as:
    // - coeff1 = 0xFF | ((0xFF & 0x0F) << 8) = 0xFF | 0xF00 = 0xFFF = 4095
    // - coeff2 = (0xFF >> 4) | (0xFF << 4) = 0x0F | 0xFF0 = 0xFFF = 4095
    // Both exceed q=3329, making this an invalid ML-KEM key

    let bytes: [u8; 3] = [0xFF, 0xFF, 0xFF];
    let coeff1 = u16::from(bytes[0]) | ((u16::from(bytes[1]) & 0x0F) << 8);
    let coeff2 = (u16::from(bytes[1]) >> 4) | (u16::from(bytes[2]) << 4);

    println!("\nDecoded coefficients from [0xFF, 0xFF, 0xFF]:");
    println!("  coeff1 = {} (max valid: 3328)", coeff1);
    println!("  coeff2 = {} (max valid: 3328)", coeff2);
    println!("\nBoth exceed q=3329, but ml-kem accepts this key.");
}
ml-kem accepted invalid key with coefficients >= 3329
Encapsulation key bytes: [254, 226, 47, 254, 226, 47, 254, 226, 47, 254, 226, 47, 254, 226, 47, 254]...

Decoded coefficients from [0xFF, 0xFF, 0xFF]:
  coeff1 = 4095 (max valid: 3328)
  coeff2 = 4095 (max valid: 3328)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions