Skip to main content

bouncycastle_sha3/
sha3.rs

1use crate::SHA3Params;
2use crate::keccak::{
3    KeccakInternal, SHA3_FAMILY_STATE_LEN, SUSPENDED_SHA3_STATE_LEN, deserialize_sha3_family_state,
4    serialize_sha3_family_state,
5};
6use bouncycastle_core::errors::{HashError, KDFError, SuspendableError};
7use bouncycastle_core::key_material;
8use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType};
9use bouncycastle_core::suspendable_state::{add_lib_ver, check_lib_ver};
10use bouncycastle_core::traits::{Algorithm, Hash, KDF, SecurityStrength, Suspendable};
11use bouncycastle_utils::{max, min};
12
13/// Internal struct for SHA3.
14/// This uses a private bound so that you cannot instantiate it directly and have to use the
15/// provided and NIST-approved parameters.
16#[derive(Clone)]
17pub struct SHA3Internal<PARAMS: SHA3Params> {
18    _params: std::marker::PhantomData<PARAMS>,
19    keccak: KeccakInternal,
20    kdf_key_type: KeyType,
21    kdf_security_strength: SecurityStrength,
22    kdf_entropy: usize,
23}
24
25// Note: zeroizing Drop is not necessary here because all the sensitive info is in KeccakDigest, which has one.
26
27impl<PARAMS: SHA3Params> SHA3Internal<PARAMS> {
28    /// Get a new SHA3 instance, ready for use.
29    pub fn new() -> Self {
30        Self {
31            _params: std::marker::PhantomData,
32            keccak: KeccakInternal::new(PARAMS::SIZE),
33            kdf_key_type: KeyType::Zeroized,
34            kdf_security_strength: SecurityStrength::None,
35            kdf_entropy: 0,
36        }
37    }
38
39    /// Swallows errors and simply returns an empty Vec<u8> if the hashes fails for whatever reason.
40    fn hash_internal(mut self, data: &[u8], output: &mut [u8]) -> usize {
41        output.fill(0);
42
43        self.do_update(data);
44        self.do_final_out(output)
45    }
46
47    fn mix_key_internal(&mut self, key: &impl KeyMaterialTrait) {
48        // track the strongest input key type
49        self.kdf_key_type = *max(&self.kdf_key_type, &key.key_type());
50
51        // track input entropy
52        if key.is_full_entropy() {
53            self.kdf_entropy += key.key_len();
54            self.kdf_security_strength =
55                max(&self.kdf_security_strength, &key.security_strength()).clone();
56            self.kdf_security_strength = min(
57                &self.kdf_security_strength,
58                &SecurityStrength::from_bits(PARAMS::OUTPUT_LEN * 8 / 2),
59            )
60            .clone();
61        }
62
63        self.do_update(key.ref_to_bytes())
64    }
65
66    fn derive_key_final_internal(
67        self,
68        additional_input: &[u8],
69    ) -> Result<Box<dyn KeyMaterialTrait>, KDFError> {
70        let mut output_key = KeyMaterial::<64>::new();
71        self.derive_key_out_final_internal(additional_input, &mut output_key)?;
72
73        Ok(Box::new(output_key))
74    }
75
76    fn derive_key_out_final_internal(
77        mut self,
78        additional_input: &[u8],
79        output_key: &mut impl KeyMaterialTrait,
80    ) -> Result<usize, KDFError> {
81        // For the KDF to be considered "fully-seeded" and be capable of outputting full-entropy KeyMaterials,
82        // it requires full-entropy input that is at least block length.
83        // TODO: citation needed (NIST)
84        if self.kdf_entropy < PARAMS::OUTPUT_LEN {
85            self.kdf_key_type = min(&self.kdf_key_type, &KeyType::Unknown).clone();
86            self.kdf_security_strength = SecurityStrength::None; // BytesLowEntropy can't have a securtiy level.
87        }
88
89        self.do_update(additional_input);
90
91        let mut key_type = self.kdf_key_type.clone();
92        let output_security_strength = self.kdf_security_strength.clone();
93        let mut bytes_written: usize = 0;
94        key_material::do_hazardous_operations(output_key, |output_key| {
95            bytes_written = self.do_final_out(output_key.ref_to_bytes_mut()?);
96            output_key.set_key_len(bytes_written)?;
97            Ok(())
98        })
99        .expect(
100            "both mut_ref_to_bytes() and set_key_len() should be infallible within a hazop block",
101        );
102
103        // since computation has been performed, the result will not actually be zeroized,
104        // even if all input key material was zeroized.
105        if key_type == KeyType::Zeroized {
106            key_type = KeyType::Unknown;
107        }
108        key_material::do_hazardous_operations(&mut *output_key, |output_key| {
109            output_key.set_key_type(key_type)?;
110            output_key.set_security_strength(
111                min(&output_security_strength, &SecurityStrength::from_bits(bytes_written * 8)).clone(),
112            )
113        })
114        .expect(
115            "both set_key_type() and set_security_strength() should be infallible within a hazop block",
116        );
117
118        output_key
119            .set_key_len(min(&output_key.key_len(), &PARAMS::OUTPUT_LEN).clone())
120            .expect("should be infallible to truncate key length");
121        Ok(bytes_written)
122    }
123}
124
125impl<PARAMS: SHA3Params> Default for SHA3Internal<PARAMS> {
126    fn default() -> Self {
127        Self::new()
128    }
129}
130
131impl<PARAMS: SHA3Params> Algorithm for SHA3Internal<PARAMS> {
132    const ALG_NAME: &'static str = PARAMS::ALG_NAME;
133    const MAX_SECURITY_STRENGTH: SecurityStrength = PARAMS::MAX_SECURITY_STRENGTH;
134}
135
136impl<PARAMS: SHA3Params> Hash for SHA3Internal<PARAMS> {
137    /// As per FIPS 202 Table 3.
138    /// Required, for example, to compute the pad lengths in HMAC.
139    fn block_bitlen(&self) -> usize {
140        PARAMS::BLOCK_LEN * 8
141    }
142
143    fn output_len(&self) -> usize {
144        PARAMS::OUTPUT_LEN
145    }
146
147    fn hash(self, data: &[u8]) -> Vec<u8> {
148        let mut output: Vec<u8> = vec![0u8; PARAMS::OUTPUT_LEN];
149        _ = self.hash_internal(data, &mut output[..]);
150        output
151    }
152
153    fn hash_out(self, data: &[u8], mut output: &mut [u8]) -> usize {
154        output.fill(0);
155
156        self.hash_internal(data, &mut output)
157    }
158
159    fn do_update(&mut self, data: &[u8]) {
160        self.keccak.absorb(data)
161    }
162
163    fn do_final(self) -> Vec<u8> {
164        let dbg_rslt_len = self.output_len();
165        let mut output: Vec<u8> = vec![0u8; self.output_len()];
166        let bytes_written = self.do_final_out(output.as_mut_slice());
167        debug_assert_eq!(bytes_written, dbg_rslt_len);
168
169        output
170    }
171
172    // TODO: investigate why this doesn't take a &mut [u8; HASH_LEN] 
173    // Being able to do so would improve ergonomics
174    fn do_final_out(mut self, output: &mut [u8]) -> usize {
175        output.fill(0);
176
177        // this shouldn't fail because, by construction, the function is only called once, 
178        // and this is the only way to absorb partial bits.
179        self.keccak.absorb_bits(0x02, 2).expect("do_final_out: keccak.absorb_bits failed."); 
180
181        let bytes_written = if output.len() <= self.output_len() {
182            self.keccak.squeeze(output)
183        } else {
184            let min =
185                if output.len() >= self.output_len() { self.output_len() } else { output.len() };
186            self.keccak.squeeze(&mut output[..min])
187        };
188        bytes_written
189    }
190
191    fn do_final_partial_bits(
192        self,
193        partial_byte: u8,
194        num_partial_bits: usize,
195    ) -> Result<Vec<u8>, HashError> {
196        let dbg_rslt_len = self.output_len();
197        let mut output: Vec<u8> = vec![0u8; self.output_len()];
198        let bytes_written =
199            self.do_final_partial_bits_out(partial_byte, num_partial_bits, output.as_mut_slice())?;
200        debug_assert_eq!(bytes_written, dbg_rslt_len);
201
202        Ok(output)
203    }
204
205    fn do_final_partial_bits_out(
206        mut self,
207        partial_byte: u8,
208        num_partial_bits: usize,
209        output: &mut [u8],
210    ) -> Result<usize, HashError> {
211        output.fill(0);
212
213        // Mutants note: This is just bit-setting into empty space. 
214        // It works the same regardless of whether it's OR or XOR.
215        let mut final_input: u16 =
216            ((partial_byte as u16) & ((1 << num_partial_bits) - 1)) | (0x02 << num_partial_bits);
217        let mut final_bits = num_partial_bits + 2;
218
219        if final_bits >= 8 {
220            self.keccak.absorb(&[final_input as u8]);
221            final_bits -= 8;
222            final_input >>= 8;
223        }
224
225        self.keccak.absorb_bits(final_input as u8, final_bits)?;
226
227        let min = if output.len() >= self.output_len() { self.output_len() } else { output.len() };
228        Ok(self.keccak.squeeze(&mut output[..min]))
229    }
230
231    fn max_security_strength(&self) -> SecurityStrength {
232        SecurityStrength::from_bytes(PARAMS::OUTPUT_LEN / 2)
233    }
234}
235
236/// SHA3 is allowed to be used as a KDF in the form HASH(X) as per NIST SP 800-56C.
237impl<PARAMS: SHA3Params> KDF for SHA3Internal<PARAMS> {
238    /// Returns a [`KeyMaterial`].
239    /// For the KDF to be considered "fully-seeded" and be capable of outputting full-entropy KeyMaterials,
240    /// it requires full-entropy input that is at least the bit size (ie 256 bits for SHA3-256, etc).
241    fn derive_key(
242        mut self,
243        key: &impl KeyMaterialTrait,
244        additional_input: &[u8],
245    ) -> Result<Box<dyn KeyMaterialTrait>, KDFError> {
246        self.mix_key_internal(key);
247        self.derive_key_final_internal(additional_input)
248    }
249
250    fn derive_key_out(
251        mut self,
252        key: &impl KeyMaterialTrait,
253        additional_input: &[u8],
254        output_key: &mut impl KeyMaterialTrait,
255    ) -> Result<usize, KDFError> {
256        // self.derive_key_from_multiple_out(&[key], additional_input, output_key)
257        self.mix_key_internal(key);
258        self.derive_key_out_final_internal(additional_input, output_key)
259    }
260
261    fn derive_key_from_multiple(
262        mut self,
263        keys: &[&impl KeyMaterialTrait],
264        additional_input: &[u8],
265    ) -> Result<Box<dyn KeyMaterialTrait>, KDFError> {
266        for key in keys {
267            self.mix_key_internal(*key);
268        }
269        self.derive_key_final_internal(additional_input)
270    }
271
272    fn derive_key_from_multiple_out(
273        mut self,
274        keys: &[&impl KeyMaterialTrait],
275        additional_input: &[u8],
276        output_key: &mut impl KeyMaterialTrait,
277    ) -> Result<usize, KDFError> {
278        // self.derive_key_from_multiple_internal(keys, additional_input, output_key)
279        for key in keys {
280            self.mix_key_internal(*key);
281        }
282        self.derive_key_out_final_internal(additional_input, output_key)
283    }
284
285    fn max_security_strength(&self) -> SecurityStrength {
286        SecurityStrength::from_bytes(PARAMS::OUTPUT_LEN / 2)
287    }
288}
289
290impl<PARAMS: SHA3Params> Suspendable<SUSPENDED_SHA3_STATE_LEN> for SHA3Internal<PARAMS> {
291    fn suspend(self) -> [u8; SUSPENDED_SHA3_STATE_LEN] {
292        let mut out_to_return = [0u8; SUSPENDED_SHA3_STATE_LEN];
293
294        // insert the version tag
295        let out: &mut [u8; SHA3_FAMILY_STATE_LEN] =
296            add_lib_ver(&mut out_to_return).try_into().unwrap();
297
298        serialize_sha3_family_state(
299            out,
300            PARAMS::STATE_TAG,
301            &self.keccak,
302            self.kdf_key_type,
303            self.kdf_security_strength,
304            self.kdf_entropy,
305        );
306
307        out_to_return
308    }
309
310    fn from_suspended(
311        serialized_state: [u8; SUSPENDED_SHA3_STATE_LEN],
312    ) -> Result<Self, SuspendableError> {
313        // check the version tag. At the moment, we have no not_before version to specify.
314        let input: &[u8; SHA3_FAMILY_STATE_LEN] =
315            check_lib_ver(&serialized_state, None)?.try_into().unwrap();
316
317        // The variant tag rejects states from any other SHA3/SHAKE variant; the rate is then the
318        // correct one to rebuild with (both are fully determined by the algorithm parameters).
319        let rate = 1600 - ((PARAMS::SIZE as usize) << 1);
320        let (keccak, kdf_key_type, kdf_security_strength, kdf_entropy) =
321            deserialize_sha3_family_state(input, PARAMS::STATE_TAG, rate)?;
322
323        Ok(SHA3Internal {
324            _params: std::marker::PhantomData,
325            keccak,
326            kdf_key_type,
327            kdf_security_strength,
328            kdf_entropy,
329        })
330    }
331}