wolf_crypto/mac/hmac/mod.rs
1//! Keyed Hash Message Authentication Codes `HMAC`.
2
3pub mod algo;
4mod digest;
5
6#[doc(inline)]
7pub use algo::{
8 Sha224, Sha256, Sha384, Sha512,
9 Sha3_224, Sha3_256, Sha3_384, Sha3_512,
10
11 KeySlice
12};
13
14non_fips! {
15 #[doc(inline)]
16 pub use algo::{Sha, Md5};
17}
18
19use algo::GenericKey;
20use crate::{ct, Fips};
21
22use wolf_crypto_sys::{
23 Hmac as wc_Hmac,
24 wc_HmacSetKey, wc_HmacUpdate, wc_HmacFree, wc_HmacFinal,
25};
26
27use core::marker::PhantomData;
28use core::mem::MaybeUninit;
29use core::ptr::addr_of_mut;
30use crate::{can_cast_u32, const_can_cast_u32, Unspecified};
31use crate::buf::InvalidSize;
32use crate::mac::hmac::algo::Digest as _;
33use core::fmt;
34
35pub use digest::{Digest, HexDigest};
36
37/// Hashed-Based Message Authentication Codes `HMAC`.
38///
39/// # Generic `H`
40///
41/// This denotes which hashing function you wish to use under the hood. Options are:
42///
43/// - `Sha224`
44/// - `Sha256`
45/// - `Sha384`
46/// - `Sha512`
47/// - `Sha3_224`
48/// - `Sha3_256`
49/// - `Sha3_384`
50/// - `Sha3_512`
51///
52/// ### Non-FIPS / Legacy
53///
54/// - `Md5`
55/// - `Sha` (`SHA-1`)
56///
57/// # Example
58///
59/// ```
60/// use wolf_crypto::mac::hmac::{Hmac, Sha256};
61///
62/// # fn main() -> Result<(), wolf_crypto::Unspecified> {
63/// let mut hmac = Hmac::<Sha256>::new([42u8; 32]);
64///
65/// hmac.update(b"hello world, ")?;
66/// hmac.update(b"beautiful weather.")?;
67///
68/// let parts = hmac.finalize();
69///
70/// let mut hmac = Hmac::<Sha256>::new([42u8; 32]);
71///
72/// hmac.update(b"hello world, beautiful weather.")?;
73///
74/// let all = hmac.finalize();
75///
76/// assert_eq!(parts, all);
77/// # Ok(()) }
78#[repr(transparent)]
79pub struct Hmac<H: algo::Hash> {
80 inner: wc_Hmac,
81 _algo: PhantomData<H>
82}
83
84impl<H: algo::Hash> fmt::Debug for Hmac<H> {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.write_str("Hmac<")
87 .and_then(|_| H::write_alg_name(f))
88 .and_then(|_| f.write_str(">"))
89 }
90}
91
92impl<H: algo::Hash> Hmac<H> {
93 /// Create a new `Hmac` instance.
94 ///
95 /// # Arguments
96 ///
97 /// * `key` - The key material to initialize the `Hmac` instance with. This can be the size of
98 /// the digest or greater (for example, `Sha256` means a 256-bit (32 byte) or larger key).
99 ///
100 /// # Example
101 ///
102 /// ```
103 /// use wolf_crypto::{mac::hmac::{Hmac, Sha3_512, KeySlice}, MakeOpaque};
104 ///
105 /// // we can provide the exact size of our digest:
106 /// let hmac = Hmac::<Sha3_512>::new([42u8; 64]);
107 ///
108 /// // or we can provide a larger key, however this does not
109 /// // come with much benefit.
110 /// let hmac = KeySlice::new(&[42u8; 128])
111 /// .opaque_map(Hmac::<Sha3_512>::new)
112 /// .unwrap();
113 /// ```
114 pub fn new<K>(key: K) -> Self
115 where K: GenericKey<Size = H::KeyLen>
116 {
117 let mut inner = MaybeUninit::<wc_Hmac>::uninit();
118
119 unsafe {
120 // INFALLIBLE
121 //
122 // With our current configuration, even with FIPS 140-3 enabled, this is completely
123 // infallible. The possible failures are OOM, invalid type ID, and for FIPS 140-3 the
124 // key not being at least the FIPS standard of 14 bytes.
125 //
126 // We use the no malloc configuration, so OOM is not of concern, all the type IDs
127 // are from the wolfcrypt constants, and the generic H only includes enabled hashing
128 // functions so all type IDs are valid. Our minimum key size for invoking new is
129 // the hash functions digest length, pursuant to the RFC2104 section 3 recommendations.
130 //
131 // So, this function is infallible under all possible paths.
132 let _res = wc_HmacSetKey(
133 inner.as_mut_ptr(),
134 H::type_id(),
135 key.ptr(),
136 key.size()
137 );
138
139 debug_assert_eq!(_res, 0);
140
141 // If the provided key was owned zero the memory.
142 key.cleanup();
143
144 Self { inner: inner.assume_init(), _algo: PhantomData }
145 }
146 }
147
148 /// Updates the message to authenticate using `HMAC`, without performing any safety checks.
149 ///
150 /// # Arguments
151 ///
152 /// * `data` - The buffer containing the message to append.
153 ///
154 /// # Safety
155 ///
156 /// The length of `data` must not be greater than [`u32::MAX`].
157 #[inline]
158 unsafe fn update_unchecked(&mut self, data: &[u8]) -> &mut Self {
159 debug_assert!(can_cast_u32(data.len()));
160
161 // Infallible
162 //
163 // The infallibility of wc_HmacUpdate depends on the underlying hash functions
164 // infallibility for updates. Which as outlined in the hash module infallibility commentary,
165 // these all are to be considered infallible.
166 //
167 // Then, there's the basic preconditions which the type system and borrow checker ensure
168 // are satisfied.
169 let _res = wc_HmacUpdate(
170 addr_of_mut!(self.inner),
171 data.as_ptr(),
172 data.len() as u32
173 );
174
175 debug_assert_eq!(_res, 0);
176
177 self
178 }
179
180 /// Updates the message to authenticate using `HMAC`.
181 ///
182 /// # Arguments
183 ///
184 /// * `data` - The buffer containing the message to append.
185 ///
186 /// # Errors
187 ///
188 /// If the length of `data` is greater than [`u32::MAX`].
189 ///
190 /// # Example
191 ///
192 /// ```
193 /// use wolf_crypto::{mac::hmac::{Hmac, Sha3_256}, ct_eq};
194 ///
195 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
196 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
197 /// hmac.update("hello world".as_bytes())?;
198 ///
199 /// let out = hmac.finalize();
200 ///
201 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
202 /// hmac.update("hello world".as_bytes())?;
203 ///
204 /// let other = hmac.finalize();
205 ///
206 /// // Always check in constant-time!! (Digest does this for us)
207 /// assert_eq!(out, other);
208 /// # Ok(()) }
209 /// ```
210 pub fn update(&mut self, data: &[u8]) -> Result<&mut Self, Unspecified> {
211 if can_cast_u32(data.len()) {
212 Ok(unsafe { self.update_unchecked(data) })
213 } else {
214 Err(Unspecified)
215 }
216 }
217
218 /// Updates the message to authenticate using `HMAC`.
219 ///
220 /// The distinction between this and [`update`] is that the safety checks are performed over
221 /// the constant `C`, thus during compilation time.
222 ///
223 /// # Arguments
224 ///
225 /// * `data` - The fixed-size buffer containing the message to append.
226 ///
227 /// # Errors
228 ///
229 /// If the length of `data` is greater than [`u32::MAX`].
230 ///
231 /// [`update`]: Self::update
232 ///
233 /// # Example
234 ///
235 /// ```
236 /// use wolf_crypto::mac::hmac::{Hmac, Sha3_256};
237 ///
238 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
239 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
240 /// hmac.update_sized(b"hello world")?;
241 ///
242 /// // It is generally recommended to use `finalize` instead.
243 /// let mut out = [0u8; 32];
244 /// hmac.finalize_into(&mut out);
245 ///
246 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
247 /// hmac.update_sized(b"hello world")?;
248 ///
249 /// // Always check in constant-time!!
250 /// assert!(hmac.compare_digest(&out));
251 /// # Ok(()) }
252 /// ```
253 pub fn update_sized<const C: usize>(&mut self, data: &[u8; C]) -> Result<&mut Self, Unspecified> {
254 if const_can_cast_u32::<C>() {
255 Ok(unsafe { self.update_unchecked(data) })
256 } else {
257 Err(Unspecified)
258 }
259 }
260
261 /// Compute the final hash of the `HMAC` instance's message into the `output` pointer.
262 ///
263 /// # Arguments
264 ///
265 /// * `output` - The pointer to write the underlying hash function's digest to.
266 ///
267 /// # Safety
268 ///
269 /// The output pointer must be valid for writes and non-null for the length of the underlying
270 /// hash functions digest.
271 #[inline(always)]
272 unsafe fn finalize_imp(mut self, output: *mut u8) {
273 debug_assert!(!output.is_null());
274 unsafe {
275 // INFALLIBLE
276 //
277 // See hash module commentary on all the associated hashing algorithms' final functions.
278 let _res = wc_HmacFinal(
279 addr_of_mut!(self.inner),
280 output
281 );
282
283 debug_assert_eq!(_res, 0);
284 }
285 }
286
287 /// Compute the final hash of the `HMAC` instance's message into the `output` buffer.
288 ///
289 /// # Arguments
290 ///
291 /// * `output` - The buffer to write the digest to.
292 ///
293 /// # Note
294 ///
295 /// It is generally recommended to use [`finalize`] in favor of this, as mistakes happen,
296 /// [`finalize`]'s returned [`Digest`] type can help prevent these mistakes.
297 ///
298 /// # Example
299 ///
300 /// ```
301 /// use wolf_crypto::mac::hmac::{Hmac, Sha3_256};
302 ///
303 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
304 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
305 /// hmac.update(b"hello world")?;
306 ///
307 /// let mut out = [0u8; 32];
308 /// hmac.finalize_into(&mut out);
309 ///
310 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
311 /// hmac.update(b"hello world")?;
312 ///
313 /// // Always check in constant-time!!
314 /// assert!(hmac.compare_digest(&out));
315 /// # Ok(()) }
316 /// ```
317 ///
318 /// [`finalize`]: Self::finalize
319 #[inline]
320 pub fn finalize_into(self, output: &mut H::Digest) {
321 unsafe { self.finalize_imp(output.ptr()); }
322 }
323
324 /// Compute the final hash of the `HMAC` instance's message into the `output` buffer.
325 ///
326 /// # Arguments
327 ///
328 /// * `output` - The buffer to write the digest to.
329 ///
330 /// # Errors
331 ///
332 /// If the length of `output` is less than the result of [`size`] (the digest size) for the
333 /// underlying hashing function.
334 ///
335 /// # Note
336 ///
337 /// It is generally recommended to use [`finalize`] in favor of this, as mistakes happen,
338 /// [`finalize`]'s returned [`Digest`] type can help prevent these mistakes.
339 ///
340 /// # Example
341 ///
342 /// ```
343 /// use wolf_crypto::{mac::hmac::{Hmac, Sha3_256}, ct_eq};
344 ///
345 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
346 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
347 /// hmac.update(b"hello world")?;
348 ///
349 /// let mut out = [0u8; 32];
350 /// hmac.finalize_into_slice(out.as_mut_slice())?;
351 ///
352 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
353 /// hmac.update(b"hello world")?;
354 ///
355 /// let mut other = [0u8; 32];
356 /// hmac.finalize_into_slice(other.as_mut_slice())?;
357 ///
358 /// // Always check in constant-time!!
359 /// // (either using the Digest type or ct_eq directly)
360 /// assert!(ct_eq(&out, &other));
361 /// # Ok(()) }
362 /// ```
363 ///
364 /// [`finalize`]: Self::finalize
365 /// [`size`]: algo::Digest::size
366 pub fn finalize_into_slice(self, output: &mut [u8]) -> Result<(), InvalidSize> {
367 if output.len() >= <H::Digest as algo::Digest>::size() as usize {
368 unsafe { self.finalize_imp(output.as_mut_ptr()); }
369 Ok(())
370 } else {
371 Err(InvalidSize)
372 }
373 }
374
375 /// Compute the final hash of the `HMAC` instance's message.
376 ///
377 /// # Returns
378 ///
379 /// The resulting final digest for the underlying hash function. The type returned ([`Digest`])
380 /// has `PartialEq` utilities which all are in constant-time.
381 ///
382 /// # Example
383 ///
384 /// ```
385 /// use wolf_crypto::{mac::hmac::{Hmac, Sha3_256}, ct_eq};
386 ///
387 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
388 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
389 /// hmac.update(b"hello world")?;
390 ///
391 /// let out = hmac.finalize();
392 ///
393 /// let mut hmac = Hmac::<Sha3_256>::new([42; 32]);
394 /// hmac.update(b"hello world")?;
395 ///
396 /// let other = hmac.finalize();
397 ///
398 /// // Always check in constant-time!! (Digest does this for us)
399 /// assert_eq!(out, other);
400 /// # Ok(()) }
401 /// ```
402 #[inline]
403 pub fn finalize(self) -> Digest<H::Digest> {
404 let mut out = <H::Digest as algo::Digest>::zeroes();
405 unsafe { self.finalize_imp(out.ptr()) };
406 Digest::new(out)
407 }
408
409 /// Ensure that `other` is equivalent to the current message in constant-time.
410 ///
411 /// # Arguments
412 ///
413 /// * `other` - The digest to compare with.
414 ///
415 /// # Returns
416 ///
417 /// `true` if the digests were equivalent, `false` otherwise.
418 ///
419 /// # Note
420 ///
421 /// If you do not have a fixed size buffer of the digest size, see [`compare_digest_slice`]. Or,
422 /// you can use the [`finalize`] method which returns a type who's `PartialEq` implementations
423 /// are all in constant-time.
424 ///
425 /// [`compare_digest_slice`]: Self::compare_digest_slice
426 /// [`finalize`]: Self::finalize
427 #[must_use]
428 pub fn compare_digest(self, other: &H::Digest) -> bool {
429 let finalized = self.finalize();
430 ct::cmp_slice(finalized.as_ref(), other.as_ref()) != 0
431 }
432
433 /// Ensure that `other` is equivalent to the current message in constant-time.
434 ///
435 /// # Arguments
436 ///
437 /// * `other` - The digest to compare with.
438 ///
439 /// # Returns
440 ///
441 /// `true` if the digests were equivalent, `false` otherwise.
442 #[must_use]
443 pub fn compare_digest_slice(self, other: &[u8]) -> bool {
444 let finalized = self.finalize();
445 ct::cmp_slice(finalized.as_ref(), other) != 0
446 }
447}
448
449impl<H: algo::Hash> Drop for Hmac<H> {
450 #[inline]
451 fn drop(&mut self) {
452 unsafe { wc_HmacFree(addr_of_mut!(self.inner)); }
453 }
454}
455
456// There is no interior mutability or anything of this nature. While raw pointers
457// exist in the underlying struct, they are not ever used under our configuration.
458// These pointers only exist in the underlying hashing functions, which in this crate
459// are also Send + Sync due to our configuration again.
460unsafe impl<H: algo::Hash> Send for Hmac<H> {}
461unsafe impl<H: algo::Hash> Sync for Hmac<H> {}
462
463impl<H: algo::Hash + Fips> crate::sealed::FipsSealed for Hmac<H> {}
464impl<H: algo::Hash + Fips> Fips for Hmac<H> {}
465
466#[cfg(test)]
467mod property_tests {
468 use super::*;
469 use hmac::{Hmac as rc_Hmac, Mac as _};
470 use proptest::prelude::*;
471 use crate::aes::test_utils::{BoundList, AnyList};
472
473 proptest! {
474 #![proptest_config(ProptestConfig::with_cases(5_000))]
475
476 #[test]
477 fn rust_crypto_equivalence_sha256(
478 input in any::<BoundList<1024>>(),
479 key in any::<[u8; 32]>()
480 ) {
481 let mut rc = rc_Hmac::<sha2::Sha256>::new_from_slice(key.as_slice())
482 .unwrap();
483
484 let mut wc = Hmac::<Sha256>::new(&key);
485
486 rc.update(input.as_slice());
487 wc.update(input.as_slice()).unwrap();
488
489 let rc_out = rc.finalize().into_bytes();
490
491 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
492 }
493
494 #[test]
495 fn rust_crypto_equivalence_many_updates_sha256(
496 input in any::<AnyList<32, BoundList<256>>>(),
497 key in any::<[u8; 32]>()
498 ) {
499 let mut rc = rc_Hmac::<sha2::Sha256>::new_from_slice(key.as_slice())
500 .unwrap();
501
502 let mut wc = Hmac::<Sha256>::new(&key);
503
504 for data in input.as_slice() {
505 rc.update(data.as_slice());
506 wc.update(data.as_slice()).unwrap();
507 }
508
509 let rc_out = rc.finalize().into_bytes();
510
511 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
512 }
513
514 #[test]
515 fn rust_crypto_equivalence_sha224(
516 input in any::<BoundList<1024>>(),
517 key in any::<[u8; 28]>()
518 ) {
519 let mut rc = rc_Hmac::<sha2::Sha224>::new_from_slice(key.as_slice())
520 .unwrap();
521
522 let mut wc = Hmac::<Sha224>::new(&key);
523
524 rc.update(input.as_slice());
525 wc.update(input.as_slice()).unwrap();
526
527 let rc_out = rc.finalize().into_bytes();
528
529 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
530 }
531
532 #[test]
533 fn rust_crypto_equivalence_many_updates_sha224(
534 input in any::<AnyList<32, BoundList<256>>>(),
535 key in any::<[u8; 28]>()
536 ) {
537 let mut rc = rc_Hmac::<sha2::Sha224>::new_from_slice(key.as_slice())
538 .unwrap();
539
540 let mut wc = Hmac::<Sha224>::new(&key);
541
542 for data in input.as_slice() {
543 rc.update(data.as_slice());
544 wc.update(data.as_slice()).unwrap();
545 }
546
547 let rc_out = rc.finalize().into_bytes();
548
549 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
550 }
551
552 #[test]
553 fn rust_crypto_equivalence_sha384(
554 input in any::<BoundList<1024>>(),
555 key in any::<[u8; 48]>()
556 ) {
557 let mut rc = rc_Hmac::<sha2::Sha384>::new_from_slice(key.as_slice())
558 .unwrap();
559
560 let mut wc = Hmac::<Sha384>::new(&key);
561
562 rc.update(input.as_slice());
563 wc.update(input.as_slice()).unwrap();
564
565 let rc_out = rc.finalize().into_bytes();
566
567 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
568 }
569
570 #[test]
571 fn rust_crypto_equivalence_many_updates_sha384(
572 input in any::<AnyList<32, BoundList<256>>>(),
573 key in any::<[u8; 48]>()
574 ) {
575 let mut rc = rc_Hmac::<sha2::Sha384>::new_from_slice(key.as_slice())
576 .unwrap();
577
578 let mut wc = Hmac::<Sha384>::new(&key);
579
580 for data in input.as_slice() {
581 rc.update(data.as_slice());
582 wc.update(data.as_slice()).unwrap();
583 }
584
585 let rc_out = rc.finalize().into_bytes();
586
587 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
588 }
589
590 #[test]
591 fn rust_crypto_equivalence_sha512(
592 input in any::<BoundList<1024>>(),
593 key in any::<[u8; 64]>()
594 ) {
595 let mut rc = rc_Hmac::<sha2::Sha512>::new_from_slice(key.as_slice())
596 .unwrap();
597
598 let mut wc = Hmac::<Sha512>::new(&key);
599
600 rc.update(input.as_slice());
601 wc.update(input.as_slice()).unwrap();
602
603 let rc_out = rc.finalize().into_bytes();
604
605 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
606 }
607
608 #[test]
609 fn rust_crypto_equivalence_many_updates_sha512(
610 input in any::<AnyList<32, BoundList<256>>>(),
611 key in any::<[u8; 64]>()
612 ) {
613 let mut rc = rc_Hmac::<sha2::Sha512>::new_from_slice(key.as_slice())
614 .unwrap();
615
616 let mut wc = Hmac::<Sha512>::new(&key);
617
618 for data in input.as_slice() {
619 rc.update(data.as_slice());
620 wc.update(data.as_slice()).unwrap();
621 }
622
623 let rc_out = rc.finalize().into_bytes();
624
625 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
626 }
627
628 #[test]
629 fn rust_crypto_equivalence_sha3_256(
630 input in any::<BoundList<1024>>(),
631 key in any::<[u8; 32]>()
632 ) {
633 let mut rc = rc_Hmac::<sha3::Sha3_256>::new_from_slice(key.as_slice())
634 .unwrap();
635
636 let mut wc = Hmac::<Sha3_256>::new(&key);
637
638 rc.update(input.as_slice());
639 wc.update(input.as_slice()).unwrap();
640
641 let rc_out = rc.finalize().into_bytes();
642
643 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
644 }
645
646 #[test]
647 fn rust_crypto_equivalence_many_updates_sha3_256(
648 input in any::<AnyList<32, BoundList<256>>>(),
649 key in any::<[u8; 32]>()
650 ) {
651 let mut rc = rc_Hmac::<sha3::Sha3_256>::new_from_slice(key.as_slice())
652 .unwrap();
653
654 let mut wc = Hmac::<Sha3_256>::new(&key);
655
656 for data in input.as_slice() {
657 rc.update(data.as_slice());
658 wc.update(data.as_slice()).unwrap();
659 }
660
661 let rc_out = rc.finalize().into_bytes();
662
663 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
664 }
665
666 #[test]
667 fn rust_crypto_equivalence_sha3_224(
668 input in any::<BoundList<1024>>(),
669 key in any::<[u8; 28]>()
670 ) {
671 let mut rc = rc_Hmac::<sha3::Sha3_224>::new_from_slice(key.as_slice())
672 .unwrap();
673
674 let mut wc = Hmac::<Sha3_224>::new(&key);
675
676 rc.update(input.as_slice());
677 wc.update(input.as_slice()).unwrap();
678
679 let rc_out = rc.finalize().into_bytes();
680
681 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
682 }
683
684 #[test]
685 fn rust_crypto_equivalence_many_updates_sha3_224(
686 input in any::<AnyList<32, BoundList<256>>>(),
687 key in any::<[u8; 28]>()
688 ) {
689 let mut rc = rc_Hmac::<sha3::Sha3_224>::new_from_slice(key.as_slice())
690 .unwrap();
691
692 let mut wc = Hmac::<Sha3_224>::new(&key);
693
694 for data in input.as_slice() {
695 rc.update(data.as_slice());
696 wc.update(data.as_slice()).unwrap();
697 }
698
699 let rc_out = rc.finalize().into_bytes();
700
701 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
702 }
703
704 #[test]
705 fn rust_crypto_equivalence_sha3_384(
706 input in any::<BoundList<1024>>(),
707 key in any::<[u8; 48]>()
708 ) {
709 let mut rc = rc_Hmac::<sha3::Sha3_384>::new_from_slice(key.as_slice())
710 .unwrap();
711
712 let mut wc = Hmac::<Sha3_384>::new(&key);
713
714 rc.update(input.as_slice());
715 wc.update(input.as_slice()).unwrap();
716
717 let rc_out = rc.finalize().into_bytes();
718
719 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
720 }
721
722 #[test]
723 fn rust_crypto_equivalence_many_updates_sha3_384(
724 input in any::<AnyList<32, BoundList<256>>>(),
725 key in any::<[u8; 48]>()
726 ) {
727 let mut rc = rc_Hmac::<sha3::Sha3_384>::new_from_slice(key.as_slice())
728 .unwrap();
729
730 let mut wc = Hmac::<Sha3_384>::new(&key);
731
732 for data in input.as_slice() {
733 rc.update(data.as_slice());
734 wc.update(data.as_slice()).unwrap();
735 }
736
737 let rc_out = rc.finalize().into_bytes();
738
739 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
740 }
741
742 #[test]
743 fn rust_crypto_equivalence_sha3_512(
744 input in any::<BoundList<1024>>(),
745 key in any::<[u8; 64]>()
746 ) {
747 let mut rc = rc_Hmac::<sha3::Sha3_512>::new_from_slice(key.as_slice())
748 .unwrap();
749
750 let mut wc = Hmac::<Sha3_512>::new(&key);
751
752 rc.update(input.as_slice());
753 wc.update(input.as_slice()).unwrap();
754
755 let rc_out = rc.finalize().into_bytes();
756
757 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
758 }
759
760 #[test]
761 fn rust_crypto_equivalence_many_updates_sha3_512(
762 input in any::<AnyList<32, BoundList<256>>>(),
763 key in any::<[u8; 64]>()
764 ) {
765 let mut rc = rc_Hmac::<sha3::Sha3_512>::new_from_slice(key.as_slice())
766 .unwrap();
767
768 let mut wc = Hmac::<Sha3_512>::new(&key);
769
770 for data in input.as_slice() {
771 rc.update(data.as_slice());
772 wc.update(data.as_slice()).unwrap();
773 }
774
775 let rc_out = rc.finalize().into_bytes();
776
777 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
778 }
779
780 #[cfg(feature = "allow-non-fips")]
781 #[test]
782 fn rust_crypto_equivalence_sha1(
783 input in any::<BoundList<1024>>(),
784 key in any::<[u8; 20]>()
785 ) {
786 let mut rc = rc_Hmac::<sha1::Sha1>::new_from_slice(key.as_slice())
787 .unwrap();
788
789 let mut wc = Hmac::<Sha>::new(&key);
790
791 rc.update(input.as_slice());
792 wc.update(input.as_slice()).unwrap();
793
794 let rc_out = rc.finalize().into_bytes();
795
796 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
797 }
798
799 #[cfg(feature = "allow-non-fips")]
800 #[test]
801 fn rust_crypto_equivalence_many_updates_sha1(
802 input in any::<AnyList<32, BoundList<256>>>(),
803 key in any::<[u8; 20]>()
804 ) {
805 let mut rc = rc_Hmac::<sha1::Sha1>::new_from_slice(key.as_slice())
806 .unwrap();
807
808 let mut wc = Hmac::<Sha>::new(&key);
809
810 for data in input.as_slice() {
811 rc.update(data.as_slice());
812 wc.update(data.as_slice()).unwrap();
813 }
814
815 let rc_out = rc.finalize().into_bytes();
816
817 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
818 }
819
820 #[cfg(feature = "allow-non-fips")]
821 #[test]
822 fn rust_crypto_equivalence_md5(
823 input in any::<BoundList<1024>>(),
824 key in any::<[u8; 16]>()
825 ) {
826 let mut rc = rc_Hmac::<md5::Md5>::new_from_slice(key.as_slice())
827 .unwrap();
828
829 let mut wc = Hmac::<Md5>::new(&key);
830
831 rc.update(input.as_slice());
832 wc.update(input.as_slice()).unwrap();
833
834 let rc_out = rc.finalize().into_bytes();
835
836 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
837 }
838
839 #[cfg(feature = "allow-non-fips")]
840 #[test]
841 fn rust_crypto_equivalence_many_updates_md5(
842 input in any::<AnyList<32, BoundList<256>>>(),
843 key in any::<[u8; 16]>()
844 ) {
845 let mut rc = rc_Hmac::<md5::Md5>::new_from_slice(key.as_slice())
846 .unwrap();
847
848 let mut wc = Hmac::<Md5>::new(&key);
849
850 for data in input.as_slice() {
851 rc.update(data.as_slice());
852 wc.update(data.as_slice()).unwrap();
853 }
854
855 let rc_out = rc.finalize().into_bytes();
856
857 prop_assert!(wc.compare_digest_slice(rc_out.as_slice()));
858 }
859 }
860}