Skip to main content

bssl_crypto/
hmac.rs

1// Copyright 2023 The BoringSSL Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Hash-based message authentication from <https://datatracker.ietf.org/doc/html/rfc2104>.
16//!
17//! HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 are supported.
18//!
19//! MACs can be computed in a single shot:
20//!
21//! ```
22//! use bssl_crypto::hmac::HmacSha256;
23//!
24//! let mac: [u8; 32] = HmacSha256::mac(b"key", b"hello");
25//! ```
26//!
27//! Or they can be computed incrementally:
28//!
29//! ```
30//! use bssl_crypto::hmac::HmacSha256;
31//!
32//! let key = bssl_crypto::rand_array();
33//! let mut ctx = HmacSha256::new(&key);
34//! ctx.update(b"hel");
35//! ctx.update(b"lo");
36//! let mac: [u8; 32] = ctx.digest();
37//! ```
38//!
39//! **WARNING** comparing MACs using typical methods will often leak information
40//! about the size of the matching prefix. Use the `verify` method instead.
41//!
42//! If you need to compute many MACs with the same key, contexts can be
43//! cloned:
44//!
45//! ```
46//! use bssl_crypto::hmac::HmacSha256;
47//!
48//! let key = bssl_crypto::rand_array();
49//! let mut keyed_ctx = HmacSha256::new(&key);
50//! let mut ctx1 = keyed_ctx.clone();
51//! ctx1.update(b"foo");
52//! let mut ctx2 = keyed_ctx.clone();
53//! ctx2.update(b"foo");
54//!
55//! assert_eq!(ctx1.digest(), ctx2.digest());
56//! ```
57
58use crate::{
59    digest,
60    digest::{Sha256, Sha384, Sha512},
61    initialized_struct, sealed, FfiMutSlice, FfiSlice, ForeignTypeRef as _, InvalidSignatureError,
62};
63use core::{ffi::c_uint, marker::PhantomData, ptr};
64
65/// HMAC-SHA256.
66pub struct HmacSha256(Hmac<32, Sha256>);
67
68impl HmacSha256 {
69    /// Computes the HMAC-SHA256 of `data` as a one-shot operation.
70    pub fn mac(key: &[u8], data: &[u8]) -> [u8; 32] {
71        hmac::<32, Sha256>(key, data)
72    }
73
74    /// Creates a new HMAC-SHA256 operation from a fixed-length key.
75    pub fn new(key: &[u8; 32]) -> Self {
76        Self(Hmac::new(key))
77    }
78
79    /// Creates a new HMAC-SHA256 operation from a variable-length key.
80    pub fn new_from_slice(key: &[u8]) -> Self {
81        Self(Hmac::new_from_slice(key))
82    }
83
84    /// Hashes the provided input into the HMAC operation.
85    pub fn update(&mut self, data: &[u8]) {
86        self.0.update(data)
87    }
88
89    /// Computes the final HMAC value, consuming the object.
90    pub fn digest(self) -> [u8; 32] {
91        self.0.digest()
92    }
93
94    /// Checks that the provided tag value matches the computed HMAC value.
95    pub fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
96        self.0.verify_slice(tag)
97    }
98
99    /// Checks that the provided tag value matches the computed HMAC value.
100    pub fn verify(self, tag: &[u8; 32]) -> Result<(), InvalidSignatureError> {
101        self.0.verify(tag)
102    }
103
104    /// Checks that the provided tag value matches the computed HMAC, truncated to the input tag's
105    /// length.
106    ///
107    /// Truncating an HMAC reduces the security of the construction. Callers must ensure `tag`'s
108    /// length matches the desired HMAC length and security level.
109    pub fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
110        self.0.verify_truncated_left(tag)
111    }
112}
113
114#[cfg(feature = "std")]
115impl std::io::Write for HmacSha256 {
116    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
117        self.update(buf);
118        Ok(buf.len())
119    }
120
121    fn flush(&mut self) -> std::io::Result<()> {
122        Ok(())
123    }
124}
125
126impl Clone for HmacSha256 {
127    fn clone(&self) -> Self {
128        HmacSha256(self.0.clone())
129    }
130}
131
132/// HMAC-SHA384.
133pub struct HmacSha384(Hmac<48, Sha384>);
134
135impl HmacSha384 {
136    /// Computes the HMAC-SHA384 of `data` as a one-shot operation.
137    pub fn mac(key: &[u8], data: &[u8]) -> [u8; 48] {
138        hmac::<48, Sha384>(key, data)
139    }
140
141    /// Creates a new HMAC-SHA384 operation from a fixed-size key.
142    pub fn new(key: &[u8; 48]) -> Self {
143        Self(Hmac::new(key))
144    }
145
146    /// Creates a new HMAC-SHA384 operation from a variable-length key.
147    pub fn new_from_slice(key: &[u8]) -> Self {
148        Self(Hmac::new_from_slice(key))
149    }
150
151    /// Hashes the provided input into the HMAC operation.
152    pub fn update(&mut self, data: &[u8]) {
153        self.0.update(data)
154    }
155
156    /// Computes the final HMAC value, consuming the object.
157    pub fn digest(self) -> [u8; 48] {
158        self.0.digest()
159    }
160
161    /// Checks that the provided tag value matches the computed HMAC value.
162    pub fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
163        self.0.verify_slice(tag)
164    }
165
166    /// Checks that the provided tag value matches the computed HMAC value.
167    pub fn verify(self, tag: &[u8; 48]) -> Result<(), InvalidSignatureError> {
168        self.0.verify(tag)
169    }
170
171    /// Checks that the provided tag value matches the computed HMAC, truncated to the input tag's
172    /// length.
173    ///
174    /// Truncating an HMAC reduces the security of the construction. Callers must ensure `tag`'s
175    /// length matches the desired HMAC length and security level.
176    pub fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
177        self.0.verify_truncated_left(tag)
178    }
179}
180
181#[cfg(feature = "std")]
182impl std::io::Write for HmacSha384 {
183    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
184        self.update(buf);
185        Ok(buf.len())
186    }
187
188    fn flush(&mut self) -> std::io::Result<()> {
189        Ok(())
190    }
191}
192
193impl Clone for HmacSha384 {
194    fn clone(&self) -> Self {
195        HmacSha384(self.0.clone())
196    }
197}
198
199/// HMAC-SHA512.
200pub struct HmacSha512(Hmac<64, Sha512>);
201
202impl HmacSha512 {
203    /// Computes the HMAC-SHA512 of `data` as a one-shot operation.
204    pub fn mac(key: &[u8], data: &[u8]) -> [u8; 64] {
205        hmac::<64, Sha512>(key, data)
206    }
207
208    /// Creates a new HMAC-SHA512 operation from a fixed-size key.
209    pub fn new(key: &[u8; 64]) -> Self {
210        Self(Hmac::new(key))
211    }
212
213    /// Creates a new HMAC-SHA512 operation from a variable-length key.
214    pub fn new_from_slice(key: &[u8]) -> Self {
215        Self(Hmac::new_from_slice(key))
216    }
217
218    /// Hashes the provided input into the HMAC operation.
219    pub fn update(&mut self, data: &[u8]) {
220        self.0.update(data)
221    }
222
223    /// Computes the final HMAC value, consuming the object.
224    pub fn digest(self) -> [u8; 64] {
225        self.0.digest()
226    }
227
228    /// Checks that the provided tag value matches the computed HMAC value.
229    pub fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
230        self.0.verify_slice(tag)
231    }
232
233    /// Checks that the provided tag value matches the computed HMAC value.
234    pub fn verify(self, tag: &[u8; 64]) -> Result<(), InvalidSignatureError> {
235        self.0.verify(tag)
236    }
237
238    /// Checks that the provided tag value matches the computed HMAC, truncated to the input tag's
239    /// length.
240    ///
241    /// Truncating an HMAC reduces the security of the construction. Callers must ensure `tag`'s
242    /// length matches the desired HMAC length and security level.
243    pub fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
244        self.0.verify_truncated_left(tag)
245    }
246}
247
248#[cfg(feature = "std")]
249impl std::io::Write for HmacSha512 {
250    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
251        self.update(buf);
252        Ok(buf.len())
253    }
254
255    fn flush(&mut self) -> std::io::Result<()> {
256        Ok(())
257    }
258}
259
260impl Clone for HmacSha512 {
261    fn clone(&self) -> Self {
262        HmacSha512(self.0.clone())
263    }
264}
265
266/// Private generically implemented function for computing HMAC as a oneshot operation.
267/// This should only be exposed publicly by types with the correct output size `N` which corresponds
268/// to the output size of the provided generic hash function. Ideally `N` would just come from `MD`,
269/// but this is not possible until the Rust language can support the `min_const_generics` feature.
270/// Until then we will have to pass both separately: https://github.com/rust-lang/rust/issues/60551
271#[inline]
272fn hmac<const N: usize, MD: digest::Algorithm>(key: &[u8], data: &[u8]) -> [u8; N] {
273    let mut out = [0_u8; N];
274    let mut size: c_uint = 0;
275
276    // Safety:
277    // - buf always contains N bytes of space
278    // - If NULL is returned on error we panic immediately
279    let result = unsafe {
280        bssl_sys::HMAC(
281            MD::get_md(sealed::SealedType).as_ptr(),
282            key.as_ffi_void_ptr(),
283            key.len(),
284            data.as_ffi_ptr(),
285            data.len(),
286            out.as_mut_ffi_ptr(),
287            &mut size as *mut c_uint,
288        )
289    };
290    assert_eq!(size as usize, N);
291    assert!(!result.is_null(), "Result of bssl_sys::HMAC was null");
292
293    out
294}
295
296/// Private generically implemented HMAC instance given a generic hash function and a length `N`,
297/// where `N` is the output size of the hash function. This should only be exposed publicly by
298/// wrapper types with the correct output size `N` which corresponds to the output size of the
299/// provided generic hash function. Ideally `N` would just come from `MD`, but this is not possible
300/// until the Rust language can support the `min_const_generics` feature. Until then we will have to
301/// pass both separately: https://github.com/rust-lang/rust/issues/60551
302struct Hmac<const N: usize, MD: digest::Algorithm> {
303    // Safety: this relies on HMAC_CTX being relocatable via `memcpy`, which is
304    // not generally true of BoringSSL types. This is fine to rely on only
305    // because we do not allow any version skew between bssl-crypto and
306    // BoringSSL. It is *not* safe to copy this code in any other project.
307    ctx: bssl_sys::HMAC_CTX,
308    _marker: PhantomData<MD>,
309}
310
311impl<const N: usize, MD: digest::Algorithm> Hmac<N, MD> {
312    /// Creates a new HMAC operation from a fixed-length key.
313    fn new(key: &[u8; N]) -> Self {
314        Self::new_from_slice(key)
315    }
316
317    /// Creates a new HMAC operation from a variable-length key.
318    fn new_from_slice(key: &[u8]) -> Self {
319        let mut ret = Self {
320            // Safety: type checking will ensure that |ctx| is the correct size
321            // for `HMAC_CTX_init`.
322            ctx: unsafe { initialized_struct(|ctx| bssl_sys::HMAC_CTX_init(ctx)) },
323            _marker: Default::default(),
324        };
325
326        // Safety:
327        // - HMAC_Init_ex must be called with an initialized context, which
328        //   `HMAC_CTX_init` provides.
329        // - HMAC_Init_ex may return an error if key is null but the md is different from
330        //   before. This is avoided here since key is guaranteed to be non-null.
331        // - HMAC_Init_ex returns 0 on allocation failure in which case we panic
332        let result = unsafe {
333            bssl_sys::HMAC_Init_ex(
334                &mut ret.ctx,
335                key.as_ffi_void_ptr(),
336                key.len(),
337                MD::get_md(sealed::SealedType).as_ptr(),
338                ptr::null_mut(),
339            )
340        };
341        assert!(result > 0, "Allocation failure in bssl_sys::HMAC_Init_ex");
342        ret
343    }
344
345    /// Hashes the provided input into the HMAC operation.
346    fn update(&mut self, data: &[u8]) {
347        // Safety: `HMAC_Update` needs an initialized context, but the only way
348        // to create this object is via `new_from_slice`, which ensures that.
349        let result = unsafe { bssl_sys::HMAC_Update(&mut self.ctx, data.as_ffi_ptr(), data.len()) };
350        // HMAC_Update always returns 1.
351        assert_eq!(result, 1, "failure in bssl_sys::HMAC_Update");
352    }
353
354    /// Computes the final HMAC value, consuming the object.
355    fn digest(mut self) -> [u8; N] {
356        let mut buf = [0_u8; N];
357        let mut size: c_uint = 0;
358        // Safety:
359        // - HMAC has a fixed size output of N which will never exceed the length of an N
360        // length array
361        // - `HMAC_Final` needs an initialized context, but the only way
362        //  to create this object is via `new_from_slice`, which ensures that.
363        // - on allocation failure we panic
364        let result =
365            unsafe { bssl_sys::HMAC_Final(&mut self.ctx, buf.as_mut_ffi_ptr(), &mut size) };
366        assert!(result > 0, "Allocation failure in bssl_sys::HMAC_Final");
367        assert_eq!(size as usize, N);
368        buf
369    }
370
371    /// Checks that the provided tag value matches the computed HMAC value.
372    fn verify(self, tag: &[u8; N]) -> Result<(), InvalidSignatureError> {
373        self.verify_slice(tag)
374    }
375
376    /// Checks that the provided tag value matches the computed HMAC value.
377    ///
378    /// Returns `Error` if `tag` is not valid or not equal in length
379    /// to MAC's output.
380    fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
381        if tag.len() == N {
382            self.verify_truncated_left(tag)
383        } else {
384            Err(InvalidSignatureError)
385        }
386    }
387
388    /// Checks that the provided tag value matches the computed HMAC, truncated to the input tag's
389    /// length.
390    ///
391    /// Returns `Error` if `tag` is not valid or empty.
392    ///
393    /// Truncating an HMAC reduces the security of the construction. Callers must ensure `tag`'s
394    /// length matches the desired HMAC length and security level.
395    fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
396        let len = tag.len();
397        if len == 0 || len > N {
398            return Err(InvalidSignatureError);
399        }
400        let calculated = self.digest();
401
402        // Safety: both `calculated` and `tag` must be at least `len` bytes available.
403        // This is true because `len` is the length of `tag` and `len` is <= N,
404        // the length of `calculated`, which is checked above.
405        let result = unsafe {
406            bssl_sys::CRYPTO_memcmp(calculated.as_ffi_void_ptr(), tag.as_ffi_void_ptr(), len)
407        };
408        if result == 0 {
409            Ok(())
410        } else {
411            Err(InvalidSignatureError)
412        }
413    }
414
415    fn clone(&self) -> Self {
416        let mut ret = Self {
417            // Safety: type checking will ensure that |ctx| is the correct size
418            // for `HMAC_CTX_init`.
419            ctx: unsafe { initialized_struct(|ctx| bssl_sys::HMAC_CTX_init(ctx)) },
420            _marker: Default::default(),
421        };
422        // Safety: `ret.ctx` is initialized and `self.ctx` is valid by
423        // construction.
424        let result = unsafe { bssl_sys::HMAC_CTX_copy(&mut ret.ctx, &self.ctx) };
425        assert_eq!(result, 1);
426        ret
427    }
428}
429
430impl<const N: usize, MD: digest::Algorithm> Drop for Hmac<N, MD> {
431    fn drop(&mut self) {
432        unsafe { bssl_sys::HMAC_CTX_cleanup(&mut self.ctx) }
433    }
434}
435
436#[cfg(test)]
437mod tests {
438    use super::*;
439    use alloc::boxed::Box;
440
441    #[test]
442    fn hmac_sha256() {
443        let expected: [u8; 32] = [
444            0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
445            0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
446            0x2e, 0x32, 0xcf, 0xf7,
447        ];
448        let key: [u8; 20] = [0x0b; 20];
449        let data = b"Hi There";
450
451        let mut hmac = HmacSha256::new_from_slice(&key);
452        hmac.update(data);
453        assert_eq!(hmac.digest(), expected);
454
455        let mut hmac = HmacSha256::new_from_slice(&key);
456        hmac.update(&data[..1]);
457        hmac.update(&data[1..]);
458        assert_eq!(hmac.digest(), expected);
459
460        let mut hmac = HmacSha256::new_from_slice(&key);
461        hmac.update(data);
462        assert!(hmac.verify(&expected).is_ok());
463
464        let mut hmac = HmacSha256::new_from_slice(&key);
465        hmac.update(data);
466        assert!(hmac.verify_truncated_left(&expected[..4]).is_ok());
467
468        let mut hmac = HmacSha256::new_from_slice(&key);
469        hmac.update(data);
470        assert!(hmac.verify_truncated_left(&expected[4..8]).is_err());
471
472        let mut hmac = HmacSha256::new_from_slice(&key);
473        hmac.update(&data[..1]);
474        let mut hmac2 = hmac.clone();
475        let mut hmac3 = Box::new(hmac2.clone());
476        hmac.update(&data[1..]);
477        hmac2.update(&data[1..]);
478        hmac3.update(&data[1..]);
479        assert_eq!(hmac.digest(), expected);
480        assert_eq!(hmac2.digest(), expected);
481        assert_eq!(hmac3.digest(), expected);
482    }
483
484    #[test]
485    fn hmac_sha256_fixed_size_key() {
486        let expected_hmac = [
487            0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6, 0x99, 0x3, 0xa0, 0xf1, 0xcf, 0x2b,
488            0xbd, 0xc5, 0xba, 0xa, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c, 0x7a, 0x3b, 0x16, 0x96,
489            0xa0, 0xb6, 0x8c, 0xf7,
490        ];
491        let key: [u8; 32] = [0x0b; 32];
492        let data = b"Hi There";
493
494        let mut hmac = HmacSha256::new(&key);
495        hmac.update(data);
496        let hmac_result: [u8; 32] = hmac.digest();
497        assert_eq!(&hmac_result, &expected_hmac);
498    }
499
500    #[test]
501    fn hmac_sha384() {
502        // We test against some Wycheproof test vectors `hmac_sha384_test.json`.
503        let key = &[
504            238, 141, 240, 103, 133, 125, 242, 48, 15, 167, 26, 16, 195, 9, 151, 23, 139, 179, 121,
505            97, 39, 181, 236, 229, 242, 204, 193, 112, 147, 43, 224, 231, 142, 169, 176, 165, 147,
506            108, 9, 21, 126, 103, 28, 231, 236, 159, 197, 16,
507        ];
508        let mut hmac = HmacSha384::new_from_slice(key);
509        hmac.update(b"");
510        let hmac_result: [u8; 48] = hmac.digest();
511        assert_eq!(
512            hmac_result,
513            [
514                166, 85, 24, 77, 175, 51, 70, 255, 198, 98, 157, 73, 60, 132, 66, 100, 78, 73, 150,
515                162, 121, 158, 66, 227, 48, 111, 166, 245, 176, 150, 123, 108, 243, 166, 248, 25,
516                186, 184, 155, 206, 41, 125, 29, 26, 89, 7, 178, 208
517            ]
518        );
519
520        let key = &[
521            151, 102, 150, 192, 220, 151, 24, 44, 167, 113, 151, 92, 57, 40, 255, 145, 104, 239,
522            137, 205, 116, 12, 210, 41, 40, 88, 253, 145, 96, 104, 167, 2, 188, 29, 247, 198, 205,
523            142, 225, 240, 210, 94, 97, 212, 197, 20, 204, 93,
524        ];
525        hmac = HmacSha384::new_from_slice(key);
526        hmac.update(&[43]);
527        let hmac_result: [u8; 48] = hmac.digest();
528        assert_eq!(
529            hmac_result,
530            [
531                54, 62, 137, 115, 254, 220, 247, 137, 32, 19, 223, 174, 11, 112, 101, 214, 29, 128,
532                185, 140, 99, 91, 192, 158, 216, 96, 160, 20, 115, 185, 188, 208, 220, 85, 13, 191,
533                102, 207, 13, 96, 31, 233, 203, 243, 174, 89, 98, 13
534            ]
535        );
536
537        let key = &[
538            188, 49, 11, 195, 145, 61, 159, 229, 158, 32, 18, 160, 88, 201, 225, 80, 83, 77, 37,
539            97, 30, 54, 32, 108, 240, 124, 202, 239, 225, 83, 243, 142, 176, 234, 173, 153, 65,
540            182, 136, 61, 251, 206, 1, 188, 181, 25, 96, 65,
541        ];
542        hmac = HmacSha384::new_from_slice(key);
543        let msg = &[
544            159, 7, 71, 215, 57, 107, 251, 224, 28, 243, 232, 83, 97, 229, 0, 133, 224, 169, 26,
545            116, 144, 185, 148, 3, 29, 129, 133, 27, 114, 80, 101, 153, 63, 69, 218, 208, 214, 13,
546            121, 74, 237, 236, 123, 165, 217, 214, 219, 190, 228,
547        ];
548        hmac.update(&msg[..20]);
549        hmac.update(&msg[20..]);
550        let hmac_result: [u8; 48] = hmac.digest();
551        assert_eq!(
552            hmac_result,
553            [
554                58, 134, 73, 143, 120, 195, 251, 126, 179, 183, 179, 216, 47, 103, 125, 45, 254, 1,
555                22, 111, 231, 110, 35, 32, 131, 51, 77, 116, 241, 21, 136, 253, 8, 150, 55, 201,
556                71, 97, 233, 207, 232, 54, 67, 96, 5, 222, 174, 247
557            ]
558        );
559    }
560
561    #[test]
562    fn hmac_sha512() {
563        let expected: [u8; 64] = [
564            135, 170, 124, 222, 165, 239, 97, 157, 79, 240, 180, 36, 26, 29, 108, 176, 35, 121,
565            244, 226, 206, 78, 194, 120, 122, 208, 179, 5, 69, 225, 124, 222, 218, 168, 51, 183,
566            214, 184, 167, 2, 3, 139, 39, 78, 174, 163, 244, 228, 190, 157, 145, 78, 235, 97, 241,
567            112, 46, 105, 108, 32, 58, 18, 104, 84,
568        ];
569        let key: [u8; 20] = [0x0b; 20];
570        let data = b"Hi There";
571
572        let mut hmac = HmacSha512::new_from_slice(&key);
573        hmac.update(data);
574        assert_eq!(hmac.digest(), expected);
575
576        let mut hmac = HmacSha512::new_from_slice(&key);
577        hmac.update(&data[..1]);
578        hmac.update(&data[1..]);
579        assert_eq!(hmac.digest(), expected);
580
581        let mut hmac = HmacSha512::new_from_slice(&key);
582        hmac.update(data);
583        assert!(hmac.verify(&expected).is_ok());
584
585        let mut hmac = HmacSha512::new_from_slice(&key);
586        hmac.update(data);
587        assert!(hmac.verify_truncated_left(&expected[..4]).is_ok());
588
589        let mut hmac = HmacSha512::new_from_slice(&key);
590        hmac.update(data);
591        assert!(hmac.verify_truncated_left(&expected[4..8]).is_err());
592
593        let mut hmac = HmacSha512::new_from_slice(&key);
594        hmac.update(&data[..1]);
595        let mut hmac2 = hmac.clone();
596        let mut hmac3 = Box::new(hmac.clone());
597        hmac.update(&data[1..]);
598        hmac2.update(&data[1..]);
599        hmac3.update(&data[1..]);
600        assert_eq!(hmac.digest(), expected);
601        assert_eq!(hmac2.digest(), expected);
602        assert_eq!(hmac3.digest(), expected);
603    }
604}