Skip to main content

bouncycastle_sha3/
sha3.rs

1use bouncycastle_core_interface::errors::{HashError, KDFError};
2use bouncycastle_core_interface::key_material::{KeyMaterialInternal, KeyType};
3use bouncycastle_core_interface::traits::{Hash, KeyMaterial, SecurityStrength, KDF};
4use bouncycastle_utils::{max, min};
5use crate::keccak::KeccakDigest;
6use crate::SHA3Params;
7
8#[derive(Clone)]
9pub struct SHA3<PARAMS: SHA3Params> {
10    _params: std::marker::PhantomData<PARAMS>,
11    keccak: KeccakDigest,
12    kdf_key_type: KeyType,
13    kdf_security_strength: SecurityStrength,
14    kdf_entropy: usize,
15}
16
17// Note: don't need a zeroizing Drop here because all the sensitive info is in KeccakDigest, which has one.
18
19impl<PARAMS: SHA3Params> SHA3<PARAMS> {
20    pub fn new() -> Self {
21        Self {
22            _params: std::marker::PhantomData,
23            keccak: KeccakDigest::new(PARAMS::SIZE),
24            kdf_key_type: KeyType::Zeroized,
25            kdf_security_strength: SecurityStrength::None,
26            kdf_entropy: 0,
27        }
28    }
29
30    /// Swallows errors and simply returns an empty Vec<u8> if the hashes fails for whatever reason.
31    fn hash_internal(mut self, data: &[u8], output: &mut [u8]) -> usize {
32        self.do_update(data);
33        self.do_final_out(output)
34    }
35
36    fn mix_key_internal(&mut self, key: &impl KeyMaterial) {
37        // track the strongest input key type
38        self.kdf_key_type = *max(&self.kdf_key_type, &key.key_type());
39
40        // track input entropy
41        if key.is_full_entropy() {
42            self.kdf_entropy += key.key_len();
43            self.kdf_security_strength =
44                max(&self.kdf_security_strength, &key.security_strength()).clone();
45            self.kdf_security_strength = min(
46                &self.kdf_security_strength,
47                &SecurityStrength::from_bits(PARAMS::OUTPUT_LEN * 8 / 2),
48            )
49                .clone();
50        }
51
52        self.do_update(key.ref_to_bytes())
53    }
54
55    fn derive_key_final_internal(
56        self,
57        additional_input: &[u8],
58    ) -> Result<Box<dyn KeyMaterial>, KDFError> {
59        let mut output_key = KeyMaterialInternal::<64>::new();
60        self.derive_key_out_final_internal(additional_input, &mut output_key)?;
61
62        Ok(Box::new(output_key))
63    }
64
65    fn derive_key_out_final_internal(
66        mut self,
67        additional_input: &[u8],
68        output_key: &mut impl KeyMaterial,
69    ) -> Result<usize, KDFError> {
70        // For the KDF to be considered "fully-seeded" and be capable of outputting full-entropy KeyMaterials,
71        // it requires full-entropy input that is at least block length.
72        // TODO: citation needed, which NIST spec did I get this from?
73        if self.kdf_entropy < PARAMS::OUTPUT_LEN {
74            self.kdf_key_type = min(&self.kdf_key_type, &KeyType::BytesLowEntropy).clone();
75            self.kdf_security_strength = SecurityStrength::None; // BytesLowEntropy can't have a securtiy level.
76        }
77
78        self.do_update(additional_input);
79
80        let mut key_type = self.kdf_key_type.clone();
81        let output_security_strength = self.kdf_security_strength.clone();
82        output_key.allow_hazardous_operations();
83        let bytes_written = self.do_final_out(output_key.mut_ref_to_bytes()?);
84        output_key.set_key_len(bytes_written)?;
85
86        // since we've done some computation, the result will not actually be zeroized, even if all input key material was zeroized.
87        if key_type == KeyType::Zeroized {
88            key_type = KeyType::BytesLowEntropy;
89        }
90        output_key.set_key_type(key_type)?;
91        output_key.set_security_strength(
92            min(&output_security_strength, &SecurityStrength::from_bits(bytes_written * 8)).clone(),
93        )?;
94        output_key.drop_hazardous_operations();
95        output_key.truncate(min(&output_key.key_len(), &PARAMS::OUTPUT_LEN).clone())?;
96        Ok(bytes_written)
97    }
98}
99
100impl<PARAMS: SHA3Params> Default for SHA3<PARAMS> {
101    fn default() -> Self {
102        Self::new()
103    }
104}
105
106impl<PARAMS: SHA3Params> Hash for SHA3<PARAMS> {
107    /// As per FIPS 202 Table 3.
108    /// Required, for example, to compute the pad lengths in HMAC.
109    fn block_bitlen(&self) -> usize {
110        PARAMS::BLOCK_LEN * 8
111    }
112
113    fn output_len(&self) -> usize {
114        PARAMS::OUTPUT_LEN
115    }
116
117    fn hash(self, data: &[u8]) -> Vec<u8> {
118        let mut output: Vec<u8> = vec![0u8; PARAMS::OUTPUT_LEN];
119        _ = self.hash_internal(data, &mut output[..]);
120        output
121    }
122
123    fn hash_out(self, data: &[u8], mut output: &mut [u8]) -> usize {
124        self.hash_internal(data, &mut output)
125    }
126
127    fn do_update(&mut self, data: &[u8]) {
128        self.keccak.absorb(data)
129    }
130
131    fn do_final(self) -> Vec<u8> {
132        let dbg_rslt_len = self.output_len();
133        let mut output: Vec<u8> = vec![0u8; self.output_len()];
134        let bytes_written = self.do_final_out(output.as_mut_slice());
135        debug_assert_eq!(bytes_written, dbg_rslt_len);
136
137        output
138    }
139
140    fn do_final_out(mut self, output: &mut [u8]) -> usize {
141        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.
142
143        let bytes_written = if output.len() <= self.output_len() {
144            self.keccak.squeeze(output)
145        } else {
146            let min =
147                if output.len() >= self.output_len() { self.output_len() } else { output.len() };
148            self.keccak.squeeze(&mut output[..min])
149        };
150        bytes_written
151    }
152
153    fn do_final_partial_bits(
154        self,
155        partial_byte: u8,
156        num_partial_bits: usize,
157    ) -> Result<Vec<u8>, HashError> {
158        let dbg_rslt_len = self.output_len();
159        let mut output: Vec<u8> = vec![0u8; self.output_len()];
160        let bytes_written =
161            self.do_final_partial_bits_out(partial_byte, num_partial_bits, output.as_mut_slice())?;
162        debug_assert_eq!(bytes_written, dbg_rslt_len);
163
164        Ok(output)
165    }
166
167    fn do_final_partial_bits_out(
168        mut self,
169        partial_byte: u8,
170        num_partial_bits: usize,
171        output: &mut [u8],
172    ) -> Result<usize, HashError> {
173        // Mutants note: yep, this is just bit-setting into empty space, so it doesn't matter whether it's OR or XOR.
174        let mut final_input: u16 =
175            ((partial_byte as u16) & ((1 << num_partial_bits) - 1)) | (0x02 << num_partial_bits);
176        let mut final_bits = num_partial_bits + 2;
177
178        if final_bits >= 8 {
179            self.keccak.absorb(&[final_input as u8]);
180            final_bits -= 8;
181            final_input >>= 8;
182        }
183
184        self.keccak.absorb_bits(final_input as u8, final_bits)?;
185
186        let min = if output.len() >= self.output_len() { self.output_len() } else { output.len() };
187        Ok(self.keccak.squeeze(&mut output[..min]))
188    }
189
190    fn max_security_strength(&self) -> SecurityStrength {
191        SecurityStrength::from_bytes(PARAMS::OUTPUT_LEN / 2)
192    }
193}
194
195/// SHA3 is allowed to be used as a KDF in the form HASH(X) as per NIST SP 800-56C.
196impl<PARAMS: SHA3Params> KDF for SHA3<PARAMS> {
197    /// Returns a [KeyMaterialInternal].
198    /// For the KDF to be considered "fully-seeded" and be capable of outputting full-entropy KeyMaterials,
199    /// it requires full-entropy input that is at least the bit size (ie 256 bits for SHA3-256, etc).
200    fn derive_key(
201        mut self,
202        key: &impl KeyMaterial,
203        additional_input: &[u8],
204    ) -> Result<Box<dyn KeyMaterial>, KDFError> {
205        self.mix_key_internal(key);
206        self.derive_key_final_internal(additional_input)
207    }
208
209    fn derive_key_out(
210        mut self,
211        key: &impl KeyMaterial,
212        additional_input: &[u8],
213        output_key: &mut impl KeyMaterial,
214    ) -> Result<usize, KDFError> {
215        // self.derive_key_from_multiple_out(&[key], additional_input, output_key)
216        self.mix_key_internal(key);
217        self.derive_key_out_final_internal(additional_input, output_key)
218    }
219
220    fn derive_key_from_multiple(
221        mut self,
222        keys: &[&impl KeyMaterial],
223        additional_input: &[u8],
224    ) -> Result<Box<dyn KeyMaterial>, KDFError> {
225        for key in keys {
226            self.mix_key_internal(*key);
227        }
228        self.derive_key_final_internal(additional_input)
229    }
230
231    fn derive_key_from_multiple_out(
232        mut self,
233        keys: &[&impl KeyMaterial],
234        additional_input: &[u8],
235        output_key: &mut impl KeyMaterial,
236    ) -> Result<usize, KDFError> {
237        // self.derive_key_from_multiple_internal(keys, additional_input, output_key)
238        for key in keys {
239            self.mix_key_internal(*key);
240        }
241        self.derive_key_out_final_internal(additional_input, output_key)
242    }
243
244    fn max_security_strength(&self) -> SecurityStrength {
245        SecurityStrength::from_bytes(PARAMS::OUTPUT_LEN / 2)
246    }
247}