diff --git a/ml-kem/src/decapsulation_key.rs b/ml-kem/src/decapsulation_key.rs index 47f25b50..6b60fdec 100644 --- a/ml-kem/src/decapsulation_key.rs +++ b/ml-kem/src/decapsulation_key.rs @@ -8,6 +8,7 @@ use array::{ Array, ArraySize, sizes::{U32, U64}, }; +use core::fmt; use kem::{ Ciphertext, Decapsulate, Decapsulator, Generate, InvalidKey, Kem, KeyExport, KeyInit, KeySizeUser, @@ -23,7 +24,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; /// A `DecapsulationKey` provides the ability to generate a new key pair, and decapsulate an /// encapsulated shared key. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct DecapsulationKey

where P: KemParams, @@ -128,6 +129,18 @@ where } } +// Only show the public encapsulation key so secrets don't end up in logs +impl

fmt::Debug for DecapsulationKey

+where + P: KemParams, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DecapsulationKey") + .field("ek", &self.ek) + .finish_non_exhaustive() + } +} + // Handwritten to omit `d` in the comparisons, so keys initialized from seeds compare equally to // keys initialized from the expanded form impl

PartialEq for DecapsulationKey

diff --git a/ml-kem/src/pke.rs b/ml-kem/src/pke.rs index d9360784..29cc3cf1 100644 --- a/ml-kem/src/pke.rs +++ b/ml-kem/src/pke.rs @@ -7,6 +7,7 @@ use crate::compress::Compress; use crate::crypto::{G, PRF}; use crate::param::{EncodedDecryptionKey, EncodedEncryptionKey, PkeParams}; use array::typenum::{U1, Unsigned}; +use core::fmt; use kem::{Ciphertext, InvalidKey}; use module_lattice::{ Encode, @@ -18,7 +19,7 @@ use zeroize::Zeroize; /// A `DecryptionKey` provides the ability to generate a new key pair, and decrypt an /// encrypted value. -#[derive(Clone, Default, Debug)] +#[derive(Clone, Default)] pub(crate) struct DecryptionKey

where P: PkeParams, @@ -26,6 +27,16 @@ where s_hat: NttVector, } +// Don't print the secret vector `s_hat` +impl

fmt::Debug for DecryptionKey

+where + P: PkeParams, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DecryptionKey").finish_non_exhaustive() + } +} + impl

CtEq for DecryptionKey

where P: PkeParams, diff --git a/ml-kem/tests/debug.rs b/ml-kem/tests/debug.rs new file mode 100644 index 00000000..6a6b4de7 --- /dev/null +++ b/ml-kem/tests/debug.rs @@ -0,0 +1,29 @@ +//! `Debug` output tests. + +use core::fmt::Debug; +use ml_kem::{Kem, MlKem512, MlKem768, MlKem1024, Seed, kem::Decapsulator}; + +fn debug_redaction_test() +where + K: Kem, + K::DecapsulationKey: Debug + From, +{ + let dk = K::DecapsulationKey::from(Seed::from([0x42; 64])); + let expected = format!( + "DecapsulationKey {{ ek: {:?}, .. }}", + dk.encapsulation_key() + ); + + // Not `assert_eq!`, which would print the secret key if this fails + assert!( + format!("{dk:?}") == expected, + "`Debug` output should only contain the encapsulation key" + ); +} + +#[test] +fn debug_redaction() { + debug_redaction_test::(); + debug_redaction_test::(); + debug_redaction_test::(); +}