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#[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
25impl<PARAMS: SHA3Params> SHA3Internal<PARAMS> {
28 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 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 self.kdf_key_type = *max(&self.kdf_key_type, &key.key_type());
50
51 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 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; }
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 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 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 fn do_final_out(mut self, output: &mut [u8]) -> usize {
175 output.fill(0);
176
177 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 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
236impl<PARAMS: SHA3Params> KDF for SHA3Internal<PARAMS> {
238 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.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 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 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 let input: &[u8; SHA3_FAMILY_STATE_LEN] =
315 check_lib_ver(&serialized_state, None)?.try_into().unwrap();
316
317 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}