diff --git a/crypto/base64/src/lib.rs b/crypto/base64/src/lib.rs index 8b7cfeb..90330d0 100644 --- a/crypto/base64/src/lib.rs +++ b/crypto/base64/src/lib.rs @@ -193,6 +193,8 @@ impl Base64Encoder { assert!(inref.len() >= 3); assert!(out.len() >= 4); + out.fill(0); + out[0] = Self::ct_bin_to_b64(inref[0] >> 2); out[1] = Self::ct_bin_to_b64(((inref[0] & 0x03) << 4) | inref[1] >> 4); out[2] = Self::ct_bin_to_b64(((inref[1] & 0x0F) << 2) | inref[2] >> 6); diff --git a/crypto/factory/src/hash_factory.rs b/crypto/factory/src/hash_factory.rs index d65586f..9d12117 100644 --- a/crypto/factory/src/hash_factory.rs +++ b/crypto/factory/src/hash_factory.rs @@ -129,6 +129,8 @@ impl Hash for HashFactory { } fn hash_out(self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHA224(h) => h.hash_out(data, output), Self::SHA256(h) => h.hash_out(data, output), @@ -168,6 +170,8 @@ impl Hash for HashFactory { } fn do_final_out(self, output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHA224(h) => h.do_final_out(output), Self::SHA256(h) => h.do_final_out(output), diff --git a/crypto/factory/src/mac_factory.rs b/crypto/factory/src/mac_factory.rs index 64ae090..141c59f 100644 --- a/crypto/factory/src/mac_factory.rs +++ b/crypto/factory/src/mac_factory.rs @@ -175,6 +175,8 @@ impl MAC for MACFactory { } fn mac_out(self, data: &[u8], out: &mut [u8]) -> Result { + out.fill(0); + match self { Self::HMAC_SHA224(h) => h.mac_out(data, out), Self::HMAC_SHA256(h) => h.mac_out(data, out), @@ -227,6 +229,8 @@ impl MAC for MACFactory { } fn do_final_out(self, mut out: &mut [u8]) -> Result { + out.fill(0); + match self { Self::HMAC_SHA224(h) => h.do_final_out(&mut out), Self::HMAC_SHA256(h) => h.do_final_out(&mut out), diff --git a/crypto/factory/src/rng_factory.rs b/crypto/factory/src/rng_factory.rs index 89aa3e7..f1792d1 100644 --- a/crypto/factory/src/rng_factory.rs +++ b/crypto/factory/src/rng_factory.rs @@ -108,6 +108,8 @@ impl RNG for RNGFactory { } fn next_bytes_out(&mut self, out: &mut [u8]) -> Result { + out.fill(0); + match self { Self::HashDRBG_SHA256(rng) => {rng.next_bytes_out(out) }, Self::HashDRBG_SHA512(rng) => { rng.next_bytes_out(out) }, diff --git a/crypto/factory/src/xof_factory.rs b/crypto/factory/src/xof_factory.rs index 2809a39..e35e86e 100644 --- a/crypto/factory/src/xof_factory.rs +++ b/crypto/factory/src/xof_factory.rs @@ -86,6 +86,8 @@ impl XOF for XOFFactory { } fn hash_xof_out(self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHAKE128(h) => h.hash_xof_out(data, output), Self::SHAKE256(h) => h.hash_xof_out(data, output), @@ -118,6 +120,8 @@ impl XOF for XOFFactory { } fn squeeze_out(&mut self, output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHAKE128(h) => h.squeeze_out(output), Self::SHAKE256(h) => h.squeeze_out(output), @@ -136,6 +140,8 @@ impl XOF for XOFFactory { num_bits: usize, output: &mut u8, ) -> Result<(), HashError> { + *output = 0; + match self { Self::SHAKE128(h) => h.squeeze_partial_byte_final_out(num_bits, output), Self::SHAKE256(h) => h.squeeze_partial_byte_final_out(num_bits, output), diff --git a/crypto/hex/src/lib.rs b/crypto/hex/src/lib.rs index 2e71988..6fcf787 100644 --- a/crypto/hex/src/lib.rs +++ b/crypto/hex/src/lib.rs @@ -47,6 +47,8 @@ pub fn encode_out>(input: T, out: &mut [u8]) -> Result> 4); out[2 * i + 1] = ct_word_to_hex(inref[i] & 0x0F); @@ -90,6 +92,8 @@ pub fn decode_out>(input: T, out: &mut [u8]) -> Result HMAC { )); } + out.fill(0); + // Per RFC 2104 Section 2, save our inner digest to calculate our // outer digest. Note that we can't (necessarily) reuse out as a // scratch pad here: if we're truncating the output but not @@ -378,6 +380,8 @@ impl MAC for HMAC { } fn mac_out(mut self, data: &[u8], mut out: &mut [u8]) -> Result { + out.fill(0); + self.do_update(data); self.do_final_out(&mut out) } @@ -398,6 +402,8 @@ impl MAC for HMAC { } fn do_final_out(self, mut out: &mut [u8]) -> Result { + out.fill(0); + self.do_final_internal_out(&mut out) } diff --git a/crypto/mldsa/src/aux_functions.rs b/crypto/mldsa/src/aux_functions.rs index 8303063..3164838 100644 --- a/crypto/mldsa/src/aux_functions.rs +++ b/crypto/mldsa/src/aux_functions.rs @@ -397,6 +397,8 @@ pub(crate) fn sig_encode< h: &Vector, output: &mut [u8; SIG_LEN], ) -> usize { + output.fill(0); + let mut pos = 0; output[..LAMBDA_over_4].copy_from_slice(c_tilde); diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 780bd76..52fbdc8 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -478,6 +478,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_with_expanded_key_out(sk, &ph_m, ctx, output) @@ -500,6 +502,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(&sk.sk, Some(&sk.A_hat), ctx, ph, rnd, output) @@ -556,6 +560,8 @@ impl< return Err(SignatureError::LengthError("ctx value is longer than 255 bytes")); } + output.fill(0); + // Algorithm 7 // 6: πœ‡ ← H(BytesToBits(π‘‘π‘Ÿ)||𝑀', 64) let mu = { @@ -860,6 +866,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_out(sk, &ph_m, ctx, output) @@ -898,6 +906,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_ph_out(&self.sk.unwrap(), &ph, Some(&self.ctx[..self.ctx_len]), output) @@ -1045,6 +1055,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, None, ctx, ph, rnd, output) diff --git a/crypto/mldsa/src/mldsa.rs b/crypto/mldsa/src/mldsa.rs index d207f01..dd8eb0f 100644 --- a/crypto/mldsa/src/mldsa.rs +++ b/crypto/mldsa/src/mldsa.rs @@ -845,6 +845,8 @@ impl< rnd: [u8; 32], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + // 1: (𝜌, 𝐾, π‘‘π‘Ÿ, 𝐬1, 𝐬2, 𝐭0) ← skDecode(π‘ π‘˜) // 2: 𝐬1Μ‚_hat ← NTT(𝐬1) // 3: 𝐬2Μ‚_hat ← NTT(𝐬2) @@ -1134,6 +1136,8 @@ impl< ctx: Option<&[u8]>, out: &mut [u8; SIG_LEN], ) -> Result { + out.fill(0); + let mu = MuBuilder::compute_mu(&sk.tr(), msg, ctx)?; Self::sign_mu_out(&sk.sk, Some(&sk.A_hat), &mu, out) } @@ -1154,6 +1158,8 @@ impl< mu: &[u8; 64], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; @@ -1175,6 +1181,8 @@ impl< mu: &[u8; 64], out: &mut [u8; SIG_LEN], ) -> Result { + out.fill(0); + Self::sign_mu_out(&sk.sk, A_hat, mu, out) } @@ -1196,6 +1204,8 @@ impl< rnd: [u8; 32], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + match A_hat { Some(A_hat) => Self::sign_internal(sk, A_hat, mu, rnd, output), None => Self::sign_internal(sk, &sk.A_hat(), mu, rnd, output), @@ -1930,6 +1940,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mu = MuBuilder::compute_mu(&sk.tr(), msg, ctx)?; let bytes_written = Self::sign_mu_out(sk, None, &mu, output)?; @@ -1966,6 +1978,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_mu_out(&self.sk.unwrap(), None, &mu, output) diff --git a/crypto/mldsa/src/mldsa_keys.rs b/crypto/mldsa/src/mldsa_keys.rs index 96a3a5d..c1643ba 100644 --- a/crypto/mldsa/src/mldsa_keys.rs +++ b/crypto/mldsa/src/mldsa_keys.rs @@ -203,6 +203,8 @@ impl SignaturePublicKey usize { + out.fill(0); + self.pk_encode_out(out) } @@ -279,6 +281,8 @@ impl< } fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { + out.fill(0); + self.pk.encode_out(out) } @@ -431,6 +435,8 @@ impl usize { + out.fill(0); + // counter of progress along the output buffer let mut off: usize = 0; @@ -720,6 +726,8 @@ impl usize { + out.fill(0); + self.sk_encode_out(out) } @@ -976,6 +984,8 @@ impl< } fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { + out.fill(0); + self.sk.encode_out(out) } diff --git a/crypto/mldsa_lowmemory/src/aux_functions.rs b/crypto/mldsa_lowmemory/src/aux_functions.rs index ce0f4ca..bcc1e52 100644 --- a/crypto/mldsa_lowmemory/src/aux_functions.rs +++ b/crypto/mldsa_lowmemory/src/aux_functions.rs @@ -167,6 +167,8 @@ pub(crate) fn bitpack_gamma1( z: &Polynomial, out: &mut [u8; POLY_Z_PACKED_LEN], ) { + out.fill(0); + let mut t: [u32; 4] = [0; 4]; match GAMMA1 { MLDSA44_GAMMA1 => { diff --git a/crypto/mldsa_lowmemory/src/hash_mldsa.rs b/crypto/mldsa_lowmemory/src/hash_mldsa.rs index 33b9176..99140fa 100644 --- a/crypto/mldsa_lowmemory/src/hash_mldsa.rs +++ b/crypto/mldsa_lowmemory/src/hash_mldsa.rs @@ -590,6 +590,8 @@ impl< return Err(SignatureError::LengthError("ctx value is longer than 255 bytes")); } + output.fill(0); + // Algorithm 7 // 6: πœ‡ ← H(BytesToBits(π‘‘π‘Ÿ)||𝑀', 64) let mut h = H::new(); @@ -809,6 +811,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_out(sk, &ph_m, ctx, output) @@ -847,6 +851,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_ph_out( @@ -1024,6 +1030,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, ctx, ph, rnd, output) diff --git a/crypto/mldsa_lowmemory/src/mldsa.rs b/crypto/mldsa_lowmemory/src/mldsa.rs index a6efa48..dc6ae2e 100644 --- a/crypto/mldsa_lowmemory/src/mldsa.rs +++ b/crypto/mldsa_lowmemory/src/mldsa.rs @@ -949,6 +949,8 @@ impl< mu: &[u8; 64], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; @@ -1181,6 +1183,8 @@ impl< rnd: [u8; 32], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + SK::from_keymaterial(&seed)?; Self::sign_mu_deterministic_out(&SK::from_keymaterial(&seed)?, mu, rnd, output) } @@ -1586,6 +1590,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mu = MuBuilder::compute_mu(&sk.tr(), msg, ctx)?; let bytes_written = Self::sign_mu_out(sk, &mu, output)?; @@ -1622,6 +1628,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_mu_out(&self.sk.unwrap(), &mu, output) diff --git a/crypto/mldsa_lowmemory/src/mldsa_keys.rs b/crypto/mldsa_lowmemory/src/mldsa_keys.rs index 81985bd..b805d89 100644 --- a/crypto/mldsa_lowmemory/src/mldsa_keys.rs +++ b/crypto/mldsa_lowmemory/src/mldsa_keys.rs @@ -183,6 +183,8 @@ impl SignatureP fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { debug_assert_eq!(out.len(), PK_LEN); + out.fill(0); + out[..32].copy_from_slice(&self.rho); out[32..].copy_from_slice(&self.t1_packed); diff --git a/crypto/mlkem/src/matrix.rs b/crypto/mlkem/src/matrix.rs index 381e7be..563d19c 100644 --- a/crypto/mlkem/src/matrix.rs +++ b/crypto/mlkem/src/matrix.rs @@ -171,6 +171,8 @@ impl Vector // let mut s = self.clone(); // s.conditional_sub_q(); + out.fill(0); + let mut idx = 0; match du { 10 => { // MLKEM512 and MLKEM 768 diff --git a/crypto/mlkem/src/mlkem_keys.rs b/crypto/mlkem/src/mlkem_keys.rs index df04429..a93934d 100644 --- a/crypto/mlkem/src/mlkem_keys.rs +++ b/crypto/mlkem/src/mlkem_keys.rs @@ -180,6 +180,8 @@ impl KEMPublicKey for MLKEMPublicK debug_assert_eq!(PK_LEN, 12*k*32 + 32); debug_assert_eq!(POLY_BYTES, 12*32); + out.fill(0); + let (pk_chunks, last_chunk) = out.as_chunks_mut::(); // that should divide evenly the remainder of the array, leaving space for rho at the end @@ -276,6 +278,8 @@ impl, const PK_LEN: u } fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { + out.fill(0); + self.ek.encode_out(out) } @@ -390,7 +394,7 @@ impl< /// 3: dk ← (dkPKE β€– ek β€– H(ek) β€– 𝑧) fn sk_encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { out.fill(0); - + debug_assert_eq!(SK_LEN, /* dk_pke*/12*k*32 + /*ek*/PK_LEN + /*H(ek)*/32 + /*z*/32); let mut pos = 0usize; @@ -584,6 +588,8 @@ impl< } fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { + out.fill(0); + self.sk_encode_out(out) } @@ -751,6 +757,8 @@ impl< } fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { + out.fill(0); + self.dk.encode_out(out) } diff --git a/crypto/mlkem/src/polynomial.rs b/crypto/mlkem/src/polynomial.rs index 13bc411..1a9bb2e 100644 --- a/crypto/mlkem/src/polynomial.rs +++ b/crypto/mlkem/src/polynomial.rs @@ -127,6 +127,8 @@ impl Polynomial { // each of the N i16's will take dv bits debug_assert_eq!(out.len(), N * (dv as usize) / 8); + out.fill(0); + let mut t = [0u8; 8]; let mut idx = 0; diff --git a/crypto/mlkem_lowmemory/src/mlkem_keys.rs b/crypto/mlkem_lowmemory/src/mlkem_keys.rs index b897d17..b9e58f3 100644 --- a/crypto/mlkem_lowmemory/src/mlkem_keys.rs +++ b/crypto/mlkem_lowmemory/src/mlkem_keys.rs @@ -174,6 +174,8 @@ impl KEMPublicKe fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { debug_assert_eq!(self.t_hat_packed.len(), T_PACKED_LEN); + out.fill(0); + out[..T_PACKED_LEN].copy_from_slice(&self.t_hat_packed); debug_assert_eq!(out[T_PACKED_LEN..].len(), 32); out[T_PACKED_LEN..].copy_from_slice(&self.rho); @@ -549,6 +551,8 @@ impl< fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { debug_assert_eq!(SK_LEN, 64); + out.fill(0); + out[..32].copy_from_slice(&self.seed_d); out[32..].copy_from_slice(&self.z); diff --git a/crypto/mlkem_lowmemory/src/polynomial.rs b/crypto/mlkem_lowmemory/src/polynomial.rs index bec4ee4..a2b1603 100644 --- a/crypto/mlkem_lowmemory/src/polynomial.rs +++ b/crypto/mlkem_lowmemory/src/polynomial.rs @@ -150,6 +150,8 @@ impl Polynomial { // each of the N i16's will take dv bits debug_assert_eq!(out.len(), N * (dv as usize) / 8); + out.fill(0); + let mut t = [0u8; 8]; let mut idx = 0; diff --git a/crypto/rng/src/hash_drbg80090a.rs b/crypto/rng/src/hash_drbg80090a.rs index 4614692..31486ea 100644 --- a/crypto/rng/src/hash_drbg80090a.rs +++ b/crypto/rng/src/hash_drbg80090a.rs @@ -376,6 +376,8 @@ impl Sp80090ADrbg for HashDRBG80090A { return Err(RNGError::ReseedRequired); } + out.fill(0); + // 2. If (additional_input β‰  Null), then do // 2.1 w = Hash (0x02 || V || additional_input). // 2.2 V = (V + w) mod 2^seedlen. @@ -490,6 +492,8 @@ impl RNG for HashDRBG80090A { } fn next_bytes_out(&mut self, out: &mut [u8]) -> Result { + out.fill(0); + self.generate_out("next_bytes_out".as_bytes(), out) } @@ -521,6 +525,8 @@ fn hash_df( panic!("hash_df can't produce that much output!") } + out.fill(0); + // out is "temp" in SP 800-90Ar1 let no_of_bits_to_return: u32 = (out.len() * 8) as u32; let len = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32); @@ -614,6 +620,8 @@ fn hashgen(v: &[u8], out: &mut [u8]) { // 6. Return (returned_bits). // 1. m = ceil(requested_no_of_bits / outlen) + out.fill(0); + let m = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32); // requested_no_of_bits = out.len() diff --git a/crypto/sha2/src/sha256.rs b/crypto/sha2/src/sha256.rs index 10d45e1..7073c59 100644 --- a/crypto/sha2/src/sha256.rs +++ b/crypto/sha2/src/sha256.rs @@ -197,6 +197,8 @@ impl Hash for SHA256Internal { } fn hash_out(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.do_update(data); self.do_final_out(output) } @@ -241,6 +243,8 @@ impl Hash for SHA256Internal { } fn do_final_out(mut self, output: &mut [u8]) -> usize { + output.fill(0); + let n = *min(&output.len(), &PARAMS::OUTPUT_LEN); let bit_len: u64 = self.byte_count << 3; diff --git a/crypto/sha2/src/sha512.rs b/crypto/sha2/src/sha512.rs index 66d5265..c404fc6 100644 --- a/crypto/sha2/src/sha512.rs +++ b/crypto/sha2/src/sha512.rs @@ -209,6 +209,8 @@ impl Hash for Sha512Internal { } fn hash_out(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.do_update(data); self.do_final_out(output) } @@ -252,6 +254,8 @@ impl Hash for Sha512Internal { } fn do_final_out(mut self, output: &mut [u8]) -> usize { + output.fill(0); + let n = *min(&output.len(), &PARAMS::OUTPUT_LEN); let bit_len_hi: u64 = self.byte_count >> 61; diff --git a/crypto/sha3/src/keccak.rs b/crypto/sha3/src/keccak.rs index 55ee617..5e6f6a8 100644 --- a/crypto/sha3/src/keccak.rs +++ b/crypto/sha3/src/keccak.rs @@ -271,6 +271,8 @@ impl KeccakDigest { /// Panics if the output buffer is too small. /// Returns the number of bytes written. pub(super) fn squeeze(&mut self, out: &mut [u8]) -> usize { + out.fill(0); + if !self.squeezing { self.pad_and_switch_to_squeezing_phase(); } diff --git a/crypto/sha3/src/sha3.rs b/crypto/sha3/src/sha3.rs index a55ac26..ed5656c 100644 --- a/crypto/sha3/src/sha3.rs +++ b/crypto/sha3/src/sha3.rs @@ -29,6 +29,8 @@ impl SHA3 { /// Swallows errors and simply returns an empty Vec if the hashes fails for whatever reason. fn hash_internal(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.do_update(data); self.do_final_out(output) } @@ -121,6 +123,8 @@ impl Hash for SHA3 { } fn hash_out(self, data: &[u8], mut output: &mut [u8]) -> usize { + output.fill(0); + self.hash_internal(data, &mut output) } @@ -140,6 +144,8 @@ impl Hash for SHA3 { // todo -- why doesn't this take a &mut [u8; HASH_LEN] ? // That's probably more user-friendly than this auto-truncating that I have here. fn do_final_out(mut self, output: &mut [u8]) -> usize { + output.fill(0); + self.keccak.absorb_bits(0x02, 2).expect("do_final_out: keccak.absorb_bits failed."); // this shouldn't fail because by construction you can only enter this function once, and this is the only way to absorb partial bits. let bytes_written = if output.len() <= self.output_len() { @@ -172,6 +178,8 @@ impl Hash for SHA3 { num_partial_bits: usize, output: &mut [u8], ) -> Result { + output.fill(0); + // Mutants note: yep, this is just bit-setting into empty space, so it doesn't matter whether it's OR or XOR. let mut final_input: u16 = ((partial_byte as u16) & ((1 << num_partial_bits) - 1)) | (0x02 << num_partial_bits); diff --git a/crypto/sha3/src/shake.rs b/crypto/sha3/src/shake.rs index f7cd88e..edf953d 100644 --- a/crypto/sha3/src/shake.rs +++ b/crypto/sha3/src/shake.rs @@ -54,6 +54,8 @@ impl SHAKE { } fn hash_internal_out(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.absorb(data); self.squeeze_out(output) } @@ -200,6 +202,8 @@ impl XOF for SHAKE { } fn hash_xof_out(self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.hash_internal_out(data, output) } @@ -239,6 +243,8 @@ impl XOF for SHAKE { } fn squeeze_out(&mut self, output: &mut [u8]) -> usize { + output.fill(0); + if !self.keccak.squeezing { self.keccak.absorb_bits(0x0F, 4).expect("Absorb_bits failed"); }; @@ -262,6 +268,8 @@ impl XOF for SHAKE { return Err(HashError::InvalidLength("must be in the range [0,7]")); } + *output = 0; + let mut buf = [0u8; 1]; self.keccak.squeeze(&mut buf); *output = buf[0] >> 8 - num_bits; @@ -271,4 +279,4 @@ impl XOF for SHAKE { fn max_security_strength(&self) -> SecurityStrength { SecurityStrength::from_bits(PARAMS::SIZE as usize) } -} \ No newline at end of file +} diff --git a/crypto/sha3/tests/sha3_tests.rs b/crypto/sha3/tests/sha3_tests.rs index 787e9fb..b2d5311 100644 --- a/crypto/sha3/tests/sha3_tests.rs +++ b/crypto/sha3/tests/sha3_tests.rs @@ -66,10 +66,13 @@ mod sha3_tests { assert_eq!(&out, b"\x58\x4c\xc7\x02\xc2\x22\x9a\x0a\xbc\x78\x9b\xfa\x64\xb4\x27\x1f\xb8\xf0\xbb\x78\x67\x15\x88\xb9\xef\x1d\x09\x3e\xa3\xd4\x72\x58\x4c\x6d\x43\xb5\x68\x33\x59\x47\x2f\x44\x1b\x33\x85\x6f\x68\x28\x59\xf0\xc3\x95\x4b\x56\x80\x8f\xd1\xfb\xa0\xb5\x9c\x9d\x19\x54"); assert_eq!(bytes_written, 64); - // check that if you feed it an output slice that's bigger than it needs, that it doesn't touch the extra bytes. + // Q. T. Felix NOTE: With the application of zeroize, the entire output buffer is pre-initialized to 0, + // so the bytes after the digest length are now also 0. + // Previously, the contract was to leave the trailing bytes untouched, + // but this has been changed to fill them with zeros to prevent exposure of stale data. let mut out = DUMMY_SEED_512.clone(); SHA3_256::new().hash_out(DUMMY_SEED_512, &mut out); - assert_eq!(&out[32..], &DUMMY_SEED_512[32..]); + assert!(out[32..].iter().all(|&b| b == 0)); } #[test] diff --git a/crypto/utils/src/ct.rs b/crypto/utils/src/ct.rs index 96b1950..10b23e7 100644 --- a/crypto/utils/src/ct.rs +++ b/crypto/utils/src/ct.rs @@ -292,6 +292,8 @@ pub fn conditional_copy_bytes( out: &mut [u8; LEN], take_a: bool, ) { + out.fill(0); + // we want the behaviour of // if take_a { 0xFF } else { 0x00 } // but without using any branches that could leak timing signals