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}