1use crate::errors::UnknownCryptoError;
71use crate::hazardous::hash::blake2::blake2b_core::{self, BLAKE2B_KEYSIZE, BLAKE2B_OUTSIZE};
72
73construct_secret_key! {
74 (SecretKey, test_secret_key, 1, BLAKE2B_KEYSIZE, 32)
85}
86
87construct_tag! {
88 (Tag, test_tag, 1, BLAKE2B_OUTSIZE)
95}
96
97#[derive(Debug, Clone)]
98pub struct Blake2b {
100 _state: blake2b_core::State,
101}
102
103impl Blake2b {
104 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
105 pub fn new(secret_key: &SecretKey, size: usize) -> Result<Self, UnknownCryptoError> {
107 Ok(Self {
108 _state: blake2b_core::State::_new(secret_key.unprotected_as_bytes(), size)?,
109 })
110 }
111
112 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
113 pub fn reset(&mut self, secret_key: &SecretKey) -> Result<(), UnknownCryptoError> {
115 self._state._reset(secret_key.unprotected_as_bytes())
116 }
117
118 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
119 pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
121 self._state._update(data)
122 }
123
124 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
125 pub fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
127 let mut tmp = zeroize_wrap!([0u8; BLAKE2B_OUTSIZE]);
128 self._state._finalize(&mut tmp)?;
129
130 Tag::from_slice(&tmp[..self._state.size])
131 }
132
133 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
134 pub fn verify(
136 expected: &Tag,
137 secret_key: &SecretKey,
138 size: usize,
139 data: &[u8],
140 ) -> Result<(), UnknownCryptoError> {
141 let mut ctx = Self::new(secret_key, size)?;
142 ctx.update(data)?;
143
144 if &ctx.finalize()? == expected {
145 Ok(())
146 } else {
147 Err(UnknownCryptoError)
148 }
149 }
150}
151
152#[cfg(test)]
153mod public {
154 mod test_streaming_interface_no_key {
155 use crate::errors::UnknownCryptoError;
156 use crate::hazardous::hash::blake2::blake2b_core::{
157 compare_blake2b_states, BLAKE2B_BLOCKSIZE, BLAKE2B_OUTSIZE,
158 };
159 use crate::hazardous::mac::blake2b::{Blake2b, SecretKey, Tag};
160 use crate::test_framework::incremental_interface::{
161 StreamingContextConsistencyTester, TestableStreamingContext,
162 };
163
164 const KEY: [u8; 32] = [255u8; 32];
165
166 impl TestableStreamingContext<Tag> for Blake2b {
167 fn reset(&mut self) -> Result<(), UnknownCryptoError> {
168 let key = SecretKey::from_slice(&KEY).unwrap();
169 self.reset(&key)
170 }
171
172 fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
173 self.update(input)
174 }
175
176 fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
177 self.finalize()
178 }
179
180 fn one_shot(input: &[u8]) -> Result<Tag, UnknownCryptoError> {
181 let key = SecretKey::from_slice(&KEY).unwrap();
182 let mut ctx = Blake2b::new(&key, BLAKE2B_OUTSIZE)?;
183 ctx.update(input)?;
184 ctx.finalize()
185 }
186
187 fn verify_result(expected: &Tag, input: &[u8]) -> Result<(), UnknownCryptoError> {
188 let actual = Self::one_shot(input)?;
189
190 if &actual == expected {
191 Ok(())
192 } else {
193 Err(UnknownCryptoError)
194 }
195 }
196
197 fn compare_states(state_1: &Blake2b, state_2: &Blake2b) {
198 compare_blake2b_states(&state_1._state, &state_2._state)
199 }
200 }
201
202 #[test]
203 fn default_consistency_tests() {
204 let key = SecretKey::from_slice(&KEY).unwrap();
205 let initial_state: Blake2b = Blake2b::new(&key, BLAKE2B_OUTSIZE).unwrap();
206
207 let test_runner = StreamingContextConsistencyTester::<Tag, Blake2b>::new(
208 initial_state,
209 BLAKE2B_BLOCKSIZE,
210 );
211 test_runner.run_all_tests();
212 }
213
214 #[quickcheck]
215 #[cfg(feature = "safe_api")]
216 fn prop_input_to_consistency(data: Vec<u8>) -> bool {
219 let key = SecretKey::from_slice(&KEY).unwrap();
220 let initial_state: Blake2b = Blake2b::new(&key, BLAKE2B_OUTSIZE).unwrap();
221
222 let test_runner = StreamingContextConsistencyTester::<Tag, Blake2b>::new(
223 initial_state,
224 BLAKE2B_BLOCKSIZE,
225 );
226 test_runner.run_all_tests_property(&data);
227 true
228 }
229 }
230
231 mod test_new {
232 use crate::hazardous::mac::blake2b::{Blake2b, SecretKey};
233
234 #[test]
235 fn test_init_size() {
236 let sk = SecretKey::from_slice(&[0u8; 32]).unwrap();
237 assert!(Blake2b::new(&sk, 0).is_err());
238 assert!(Blake2b::new(&sk, 65).is_err());
239 assert!(Blake2b::new(&sk, 1).is_ok());
240 assert!(Blake2b::new(&sk, 64).is_ok());
241 }
242 }
243
244 #[cfg(feature = "safe_api")]
245 mod test_verify {
246 use crate::hazardous::mac::blake2b::{Blake2b, SecretKey};
247
248 #[quickcheck]
249 #[cfg(feature = "safe_api")]
250 fn prop_verify_diff_key_false(data: Vec<u8>) -> bool {
253 let sk = SecretKey::generate();
254 let mut state = Blake2b::new(&sk, 64).unwrap();
255 state.update(&data[..]).unwrap();
256 let tag = state.finalize().unwrap();
257 let bad_sk = SecretKey::generate();
258
259 Blake2b::verify(&tag, &bad_sk, 64, &data[..]).is_err()
260 }
261
262 #[quickcheck]
263 #[cfg(feature = "safe_api")]
264 fn prop_verify_diff_size_false(data: Vec<u8>, size_one: usize, size_two: usize) -> bool {
267 let (size_one, size_two) = match (size_one, size_two) {
268 (1..=64, 1..=64) => (size_one, size_two),
269 (_, _) => (32, 64),
270 };
271
272 let sk = SecretKey::generate();
273 let mut state = Blake2b::new(&sk, size_one).unwrap();
274 state.update(&data[..]).unwrap();
275 let tag = state.finalize().unwrap();
276
277 if size_one != size_two {
278 Blake2b::verify(&tag, &sk, size_two, &data[..]).is_err()
279 } else {
280 Blake2b::verify(&tag, &sk, size_two, &data[..]).is_ok()
281 }
282 }
283 }
284
285 mod test_streaming_interface {
286 use crate::hazardous::hash::blake2::blake2b_core::compare_blake2b_states;
287 use crate::hazardous::mac::blake2b::{Blake2b, SecretKey};
288
289 fn produces_same_hash(sk: &SecretKey, size: usize, data: &[u8]) {
293 let mut state_1 = Blake2b::new(sk, size).unwrap();
295 state_1.update(data).unwrap();
296 let res_1 = state_1.finalize().unwrap();
297
298 let mut state_2 = Blake2b::new(sk, size).unwrap();
300 state_2.reset(sk).unwrap();
301 state_2.update(data).unwrap();
302 let res_2 = state_2.finalize().unwrap();
303
304 let mut state_3 = Blake2b::new(sk, size).unwrap();
306 state_3.update(data).unwrap();
307 state_3.reset(sk).unwrap();
308 state_3.update(data).unwrap();
309 let res_3 = state_3.finalize().unwrap();
310
311 let mut state_4 = Blake2b::new(sk, size).unwrap();
313 state_4.update(data).unwrap();
314 let _ = state_4.finalize().unwrap();
315 state_4.reset(sk).unwrap();
316 state_4.update(data).unwrap();
317 let res_4 = state_4.finalize().unwrap();
318
319 assert_eq!(res_1, res_2);
320 assert_eq!(res_2, res_3);
321 assert_eq!(res_3, res_4);
322
323 if data.is_empty() {
328 let mut state_5 = Blake2b::new(sk, size).unwrap();
330 let res_5 = state_5.finalize().unwrap();
331
332 let mut state_6 = Blake2b::new(sk, size).unwrap();
334 state_6.reset(sk).unwrap();
335 let res_6 = state_6.finalize().unwrap();
336
337 let mut state_7 = Blake2b::new(sk, size).unwrap();
339 state_7.update(b"Wrong data").unwrap();
340 state_7.reset(sk).unwrap();
341 let res_7 = state_7.finalize().unwrap();
342
343 assert_eq!(res_4, res_5);
344 assert_eq!(res_5, res_6);
345 assert_eq!(res_6, res_7);
346 }
347 }
348
349 fn produces_same_state(sk: &SecretKey, size: usize, data: &[u8]) {
353 let state_1 = Blake2b::new(sk, size).unwrap();
355
356 let mut state_2 = Blake2b::new(sk, size).unwrap();
358 state_2.reset(sk).unwrap();
359
360 let mut state_3 = Blake2b::new(sk, size).unwrap();
362 state_3.update(data).unwrap();
363 state_3.reset(sk).unwrap();
364
365 let mut state_4 = Blake2b::new(sk, size).unwrap();
367 state_4.update(data).unwrap();
368 let _ = state_4.finalize().unwrap();
369 state_4.reset(sk).unwrap();
370
371 compare_blake2b_states(&state_1._state, &state_2._state);
372 compare_blake2b_states(&state_2._state, &state_3._state);
373 compare_blake2b_states(&state_3._state, &state_4._state);
374 }
375
376 #[test]
377 fn test_produce_same_state() {
379 let sk = SecretKey::from_slice(b"Testing").unwrap();
380 produces_same_state(&sk, 1, b"Tests");
381 produces_same_state(&sk, 32, b"Tests");
382 produces_same_state(&sk, 64, b"Tests");
383 produces_same_state(&sk, 28, b"Tests");
384 }
385
386 #[test]
387 fn test_produce_same_hash() {
389 let sk = SecretKey::from_slice(b"Testing").unwrap();
390 produces_same_hash(&sk, 1, b"Tests");
391 produces_same_hash(&sk, 32, b"Tests");
392 produces_same_hash(&sk, 64, b"Tests");
393 produces_same_hash(&sk, 28, b"Tests");
394
395 produces_same_hash(&sk, 1, b"");
396 produces_same_hash(&sk, 32, b"");
397 produces_same_hash(&sk, 64, b"");
398 produces_same_hash(&sk, 28, b"");
399 }
400
401 #[quickcheck]
402 #[cfg(feature = "safe_api")]
403 fn prop_same_hash_different_usage(data: Vec<u8>, size: usize) -> bool {
406 use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_OUTSIZE;
407
408 if (1..=BLAKE2B_OUTSIZE).contains(&size) {
409 let sk = SecretKey::generate();
411 produces_same_hash(&sk, size, &data[..]);
412 }
413
414 true
415 }
416
417 #[quickcheck]
418 #[cfg(feature = "safe_api")]
419 fn prop_same_state_different_usage(data: Vec<u8>, size: usize) -> bool {
422 use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_OUTSIZE;
423
424 if (1..=BLAKE2B_OUTSIZE).contains(&size) {
425 let sk = SecretKey::generate();
427 produces_same_state(&sk, size, &data[..]);
428 }
429
430 true
431 }
432 }
433}