Skip to main content

cocoon_tpm_crypto/pure_rust/
hash.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2023-2025 SUSE LLC
3// Author: Nicolai Stange <nstange@suse.de>
4
5//! Pure Rust, RustCrypto based backend for hash algorithms.
6
7// Lifetimes are not obvious at first sight here, make the explicit.
8#![allow(clippy::needless_lifetimes)]
9
10extern crate alloc;
11use alloc::boxed::Box;
12
13use crate::{CryptoError, io_slices::CryptoIoSlicesIter};
14use crate::{
15    tpm2_interface,
16    utils_common::{
17        alloc::{box_try_new_with, try_alloc_zeroizing_vec},
18        zeroize,
19    },
20};
21use core::{convert, mem, ops::Deref as _};
22
23use crypto_common::{self, KeyInit as _};
24use digest::{self, Digest as _};
25use hmac::{self, Hmac};
26
27/// A hash instance.
28pub struct HashInstance {
29    state: HashInstanceState,
30}
31
32impl HashInstance {
33    /// Create a new hash instance for the specified algorithm.
34    ///
35    /// # Arguments:
36    ///
37    /// * `alg` - The hash algorithm to create an instance for.
38    pub fn new(alg: tpm2_interface::TpmiAlgHash) -> Result<Self, convert::Infallible> {
39        Ok(Self {
40            state: HashInstanceState::new(alg),
41        })
42    }
43
44    pub fn try_clone(&self) -> Result<Self, convert::Infallible> {
45        Ok(Self {
46            state: self.state.clone(),
47        })
48    }
49
50    /// Append to the digested data.
51    ///
52    /// # Arguments:
53    ///
54    /// * `data` - The data to digest.
55    pub fn update<'a, DI: CryptoIoSlicesIter<'a>>(&mut self, mut data: DI) -> Result<(), CryptoError> {
56        self.state.update(&mut data)
57    }
58
59    /// Produce a digest into a provided buffer and reset the hash instance.
60    ///
61    /// Produce a digest into `digest` and reset the hash instance to the state
62    /// it would have had right after [`Self::new()`](Self::new()).
63    ///
64    /// # Arguments:
65    ///
66    /// * `digest` - Destination to write the produced digest to.
67    pub fn finalize_into_reset(&mut self, digest: &mut [u8]) -> Result<(), convert::Infallible> {
68        self.state.finalize_into_reset(digest);
69        Ok(())
70    }
71
72    /// Produce the final digest into a provided buffer..
73    ///
74    /// # Arguments:
75    ///
76    /// * `digest` - Destination to write the produced digest to.
77    pub fn finalize_into(self, digest: &mut [u8]) -> Result<(), convert::Infallible> {
78        self.state.finalize_into(digest);
79        Ok(())
80    }
81
82    /// Produce a digest and reset the hash instance.
83    ///
84    /// Allocate a buffer suitable for the instance's digest length,  produce a
85    /// digest into it and reset the hash instance to the state it
86    /// would have had right after [`Self::new()`](Self::new()).
87    pub fn finalize_reset(&mut self) -> Result<tpm2_interface::TpmtHa<'static>, CryptoError> {
88        self.state.finalize_reset()
89    }
90
91    /// Produce the final digest.
92    ///
93    /// Allocate a buffer suitable for the instance's digest length and produce
94    /// the final digest into it.
95    pub fn finalize(self) -> Result<tpm2_interface::TpmtHa<'static>, CryptoError> {
96        self.state.finalize()
97    }
98
99    /// Determine the instance's associated hash algorithm's digest length.
100    pub fn digest_len(&self) -> usize {
101        self.state.digest_len()
102    }
103}
104
105#[derive(Clone)]
106enum HashInstanceState {
107    #[cfg(feature = "sha1")]
108    Sha1(sha1::Sha1),
109    #[cfg(feature = "sha256")]
110    Sha256(sha2::Sha256),
111    #[cfg(feature = "sha384")]
112    Sha384(sha2::Sha384),
113    #[cfg(feature = "sha512")]
114    Sha512(sha2::Sha512),
115    #[cfg(feature = "sha3_256")]
116    Sha3_256(sha3::Sha3_256),
117    #[cfg(feature = "sha3_384")]
118    Sha3_384(sha3::Sha3_384),
119    #[cfg(feature = "sha3_512")]
120    Sha3_512(sha3::Sha3_512),
121    #[cfg(feature = "sm3_256")]
122    Sm3_256(sm3::Sm3),
123}
124
125impl HashInstanceState {
126    fn new(alg: tpm2_interface::TpmiAlgHash) -> Self {
127        match alg {
128            #[cfg(feature = "sha1")]
129            tpm2_interface::TpmiAlgHash::Sha1 => Self::Sha1(sha1::Sha1::new()),
130            #[cfg(feature = "sha256")]
131            tpm2_interface::TpmiAlgHash::Sha256 => Self::Sha256(sha2::Sha256::new()),
132            #[cfg(feature = "sha384")]
133            tpm2_interface::TpmiAlgHash::Sha384 => Self::Sha384(sha2::Sha384::new()),
134            #[cfg(feature = "sha512")]
135            tpm2_interface::TpmiAlgHash::Sha512 => Self::Sha512(sha2::Sha512::new()),
136            #[cfg(feature = "sm3_256")]
137            tpm2_interface::TpmiAlgHash::Sm3_256 => Self::Sm3_256(sm3::Sm3::new()),
138            #[cfg(feature = "sha3_256")]
139            tpm2_interface::TpmiAlgHash::Sha3_256 => Self::Sha3_256(sha3::Sha3_256::new()),
140            #[cfg(feature = "sha3_384")]
141            tpm2_interface::TpmiAlgHash::Sha3_384 => Self::Sha3_384(sha3::Sha3_384::new()),
142            #[cfg(feature = "sha3_512")]
143            tpm2_interface::TpmiAlgHash::Sha3_512 => Self::Sha3_512(sha3::Sha3_512::new()),
144        }
145    }
146
147    fn update<'a>(&mut self, data: &mut dyn CryptoIoSlicesIter<'a>) -> Result<(), CryptoError> {
148        match self {
149            #[cfg(feature = "sha1")]
150            Self::Sha1(instance) => {
151                while let Some(data) = data.next_slice(None)? {
152                    digest::Update::update(instance, data);
153                }
154            }
155            #[cfg(feature = "sha256")]
156            Self::Sha256(instance) => {
157                while let Some(data) = data.next_slice(None)? {
158                    digest::Update::update(instance, data);
159                }
160            }
161            #[cfg(feature = "sha384")]
162            Self::Sha384(instance) => {
163                while let Some(data) = data.next_slice(None)? {
164                    digest::Update::update(instance, data);
165                }
166            }
167            #[cfg(feature = "sha512")]
168            Self::Sha512(instance) => {
169                while let Some(data) = data.next_slice(None)? {
170                    digest::Update::update(instance, data);
171                }
172            }
173            #[cfg(feature = "sha3_256")]
174            Self::Sha3_256(instance) => {
175                while let Some(data) = data.next_slice(None)? {
176                    digest::Update::update(instance, data);
177                }
178            }
179            #[cfg(feature = "sha3_384")]
180            Self::Sha3_384(instance) => {
181                while let Some(data) = data.next_slice(None)? {
182                    digest::Update::update(instance, data);
183                }
184            }
185            #[cfg(feature = "sha3_512")]
186            Self::Sha3_512(instance) => {
187                while let Some(data) = data.next_slice(None)? {
188                    digest::Update::update(instance, data);
189                }
190            }
191            #[cfg(feature = "sm3_256")]
192            Self::Sm3_256(instance) => {
193                while let Some(data) = data.next_slice(None)? {
194                    digest::Update::update(instance, data);
195                }
196            }
197        }
198        Ok(())
199    }
200
201    fn finalize_into_reset(&mut self, digest: &mut [u8]) {
202        match self {
203            #[cfg(feature = "sha1")]
204            Self::Sha1(instance) => {
205                let digest: &mut crypto_common::Output<sha1::Sha1> = digest.into();
206                digest::FixedOutputReset::finalize_into_reset(instance, digest);
207            }
208            #[cfg(feature = "sha256")]
209            Self::Sha256(instance) => {
210                let digest: &mut crypto_common::Output<sha2::Sha256> = digest.into();
211                digest::FixedOutputReset::finalize_into_reset(instance, digest);
212            }
213            #[cfg(feature = "sha384")]
214            Self::Sha384(instance) => {
215                let digest: &mut crypto_common::Output<sha2::Sha384> = digest.into();
216                digest::FixedOutputReset::finalize_into_reset(instance, digest);
217            }
218            #[cfg(feature = "sha512")]
219            Self::Sha512(instance) => {
220                let digest: &mut crypto_common::Output<sha2::Sha512> = digest.into();
221                digest::FixedOutputReset::finalize_into_reset(instance, digest);
222            }
223            #[cfg(feature = "sha3_256")]
224            Self::Sha3_256(instance) => {
225                let digest: &mut crypto_common::Output<sha3::Sha3_256> = digest.into();
226                digest::FixedOutputReset::finalize_into_reset(instance, digest);
227            }
228            #[cfg(feature = "sha3_384")]
229            Self::Sha3_384(instance) => {
230                let digest: &mut crypto_common::Output<sha3::Sha3_384> = digest.into();
231                digest::FixedOutputReset::finalize_into_reset(instance, digest);
232            }
233            #[cfg(feature = "sha3_512")]
234            Self::Sha3_512(instance) => {
235                let digest: &mut crypto_common::Output<sha3::Sha3_512> = digest.into();
236                digest::FixedOutputReset::finalize_into_reset(instance, digest);
237            }
238            #[cfg(feature = "sm3_256")]
239            Self::Sm3_256(instance) => {
240                let digest: &mut crypto_common::Output<sm3::Sm3> = digest.into();
241                digest::FixedOutputReset::finalize_into_reset(instance, digest);
242            }
243        }
244    }
245
246    fn finalize_into(mut self, digest: &mut [u8]) {
247        self.finalize_into_reset(digest)
248    }
249
250    fn finalize_reset(&mut self) -> Result<tpm2_interface::TpmtHa<'static>, CryptoError> {
251        let digest_len = self.digest_len();
252        let mut digest_buf = try_alloc_zeroizing_vec::<u8>(digest_len)?;
253        self.finalize_into_reset(&mut digest_buf);
254        match self {
255            #[cfg(feature = "sha1")]
256            Self::Sha1(_) => Ok(tpm2_interface::TpmtHa::Sha1(tpm2_interface::TpmBuffer::Owned(
257                mem::take(&mut digest_buf),
258            ))),
259            #[cfg(feature = "sha256")]
260            Self::Sha256(_) => Ok(tpm2_interface::TpmtHa::Sha256(tpm2_interface::TpmBuffer::Owned(
261                mem::take(&mut digest_buf),
262            ))),
263            #[cfg(feature = "sha384")]
264            Self::Sha384(_) => Ok(tpm2_interface::TpmtHa::Sha384(tpm2_interface::TpmBuffer::Owned(
265                mem::take(&mut digest_buf),
266            ))),
267            #[cfg(feature = "sha512")]
268            Self::Sha512(_) => Ok(tpm2_interface::TpmtHa::Sha512(tpm2_interface::TpmBuffer::Owned(
269                mem::take(&mut digest_buf),
270            ))),
271            #[cfg(feature = "sha3_256")]
272            Self::Sha3_256(_) => Ok(tpm2_interface::TpmtHa::Sha3_256(tpm2_interface::TpmBuffer::Owned(
273                mem::take(&mut digest_buf),
274            ))),
275            #[cfg(feature = "sha3_384")]
276            Self::Sha3_384(_) => Ok(tpm2_interface::TpmtHa::Sha3_384(tpm2_interface::TpmBuffer::Owned(
277                mem::take(&mut digest_buf),
278            ))),
279            #[cfg(feature = "sha3_512")]
280            Self::Sha3_512(_) => Ok(tpm2_interface::TpmtHa::Sha3_512(tpm2_interface::TpmBuffer::Owned(
281                mem::take(&mut digest_buf),
282            ))),
283            #[cfg(feature = "sm3_256")]
284            Self::Sm3_256(_) => Ok(tpm2_interface::TpmtHa::Sm3_256(tpm2_interface::TpmBuffer::Owned(
285                mem::take(&mut digest_buf),
286            ))),
287        }
288    }
289
290    fn finalize(mut self) -> Result<tpm2_interface::TpmtHa<'static>, CryptoError> {
291        self.finalize_reset()
292    }
293
294    fn digest_len(&self) -> usize {
295        match self {
296            #[cfg(feature = "sha1")]
297            Self::Sha1(_) => <sha1::Sha1 as crypto_common::OutputSizeUser>::output_size(),
298            #[cfg(feature = "sha256")]
299            Self::Sha256(_) => <sha2::Sha256 as crypto_common::OutputSizeUser>::output_size(),
300            #[cfg(feature = "sha384")]
301            Self::Sha384(_) => <sha2::Sha384 as crypto_common::OutputSizeUser>::output_size(),
302            #[cfg(feature = "sha512")]
303            Self::Sha512(_) => <sha2::Sha512 as crypto_common::OutputSizeUser>::output_size(),
304            #[cfg(feature = "sha3_256")]
305            Self::Sha3_256(_) => <sha3::Sha3_256 as crypto_common::OutputSizeUser>::output_size(),
306            #[cfg(feature = "sha3_384")]
307            Self::Sha3_384(_) => <sha3::Sha3_384 as crypto_common::OutputSizeUser>::output_size(),
308            #[cfg(feature = "sha3_512")]
309            Self::Sha3_512(_) => <sha3::Sha3_512 as crypto_common::OutputSizeUser>::output_size(),
310            #[cfg(feature = "sm3_256")]
311            Self::Sm3_256(_) => <sm3::Sm3 as crypto_common::OutputSizeUser>::output_size(),
312        }
313    }
314}
315
316impl convert::From<&HashInstance> for tpm2_interface::TpmiAlgHash {
317    fn from(instance: &HashInstance) -> Self {
318        match &instance.state {
319            #[cfg(feature = "sha1")]
320            HashInstanceState::Sha1(_) => tpm2_interface::TpmiAlgHash::Sha1,
321            #[cfg(feature = "sha256")]
322            HashInstanceState::Sha256(_) => tpm2_interface::TpmiAlgHash::Sha256,
323            #[cfg(feature = "sha384")]
324            HashInstanceState::Sha384(_) => tpm2_interface::TpmiAlgHash::Sha384,
325            #[cfg(feature = "sha512")]
326            HashInstanceState::Sha512(_) => tpm2_interface::TpmiAlgHash::Sha512,
327            #[cfg(feature = "sha3_256")]
328            HashInstanceState::Sha3_256(_) => tpm2_interface::TpmiAlgHash::Sha3_256,
329            #[cfg(feature = "sha3_384")]
330            HashInstanceState::Sha3_384(_) => tpm2_interface::TpmiAlgHash::Sha3_384,
331            #[cfg(feature = "sha3_512")]
332            HashInstanceState::Sha3_512(_) => tpm2_interface::TpmiAlgHash::Sha3_512,
333            #[cfg(feature = "sm3_256")]
334            HashInstanceState::Sm3_256(_) => tpm2_interface::TpmiAlgHash::Sm3_256,
335        }
336    }
337}
338
339/// A HMAC instance.
340pub struct HmacInstance {
341    state: Box<zeroize::ZeroizingFlat<HmacInstanceState>>,
342}
343
344impl HmacInstance {
345    /// Create a new hash instance for the specified underlying hash algorithm.
346    ///
347    /// # Arguments:
348    ///
349    /// * `alg` - The hash algorithm to create a HMAC instance for.
350    pub fn new(alg: tpm2_interface::TpmiAlgHash, key: &[u8]) -> Result<Self, CryptoError> {
351        Ok(Self {
352            state: HmacInstanceState::new(alg, key)?,
353        })
354    }
355
356    /// Try to clone a HMAC instance.
357    pub fn try_clone(&self) -> Result<Self, CryptoError> {
358        Ok(Self {
359            state: box_try_new_with(
360                || -> Result<zeroize::ZeroizingFlat<HmacInstanceState>, convert::Infallible> {
361                    Ok(self.state.as_ref().clone())
362                },
363            )?,
364        })
365    }
366
367    /// Reset an existing HMAC instance's state to that of another one.
368    ///
369    /// Prefer [`repurpose_for_clone_of()`](Self::repurpose_for_clone_of) if
370    /// possible, as that might enable the compiler to elide some stack
371    /// copies.
372    ///
373    /// # Arguments:
374    ///
375    /// * `instance` - The instance to reset `self`'s state to.
376    pub fn reset_to(&mut self, instance: &Self) -> Result<(), convert::Infallible> {
377        self.state.replace(instance.state.deref().deref().clone());
378        Ok(())
379    }
380
381    /// Repurpose a HMAC instance's memory for the clone of another one.
382    ///
383    /// It is functionally equivalent to [`reset_to`](Self::reset_to), but might
384    /// enable the compiler to elide some stack copies.
385    ///
386    /// # Arguments:
387    ///
388    /// * `instance` - The instance to reset `self`'s state to.
389    pub fn repurpose_for_clone_of(self, instance: &Self) -> Result<Self, convert::Infallible> {
390        let Self { state } = self;
391        let state = state.replace_boxed_with(|| instance.state.deref().deref().clone());
392        Ok(Self { state })
393    }
394
395    /// Append to the digested data.
396    ///
397    /// # Arguments:
398    ///
399    /// * `data` - The data to digest.
400    pub fn update<'a, DI: CryptoIoSlicesIter<'a>>(&mut self, mut data: DI) -> Result<(), CryptoError> {
401        self.state.update(&mut data)
402    }
403    /// Produce the final digest into a provided buffer..
404    ///
405    /// # Arguments:
406    ///
407    /// * `digest` - Destination to write the produced digest to.
408    pub fn finalize_into(self, digest: &mut [u8]) -> Result<(), convert::Infallible> {
409        self.state.take_boxed_with(|state| state.finalize_into(digest));
410        Ok(())
411    }
412
413    /// Determine the instance's associated hash algorithm's digest length.
414    pub fn digest_len(&self) -> usize {
415        self.state.digest_len()
416    }
417}
418
419impl convert::From<&HmacInstance> for tpm2_interface::TpmiAlgHash {
420    fn from(instance: &HmacInstance) -> Self {
421        tpm2_interface::TpmiAlgHash::from(instance.state.deref().deref())
422    }
423}
424
425#[derive(Clone)]
426enum HmacInstanceState {
427    #[cfg(feature = "sha1")]
428    Sha1(hmac::Hmac<sha1::Sha1>),
429    #[cfg(feature = "sha256")]
430    Sha256(hmac::Hmac<sha2::Sha256>),
431    #[cfg(feature = "sha384")]
432    Sha384(hmac::Hmac<sha2::Sha384>),
433    #[cfg(feature = "sha512")]
434    Sha512(hmac::Hmac<sha2::Sha512>),
435    #[cfg(feature = "sha3_256")]
436    Sha3_256(hmac::Hmac<sha3::Sha3_256>),
437    #[cfg(feature = "sha3_384")]
438    Sha3_384(hmac::Hmac<sha3::Sha3_384>),
439    #[cfg(feature = "sha3_512")]
440    Sha3_512(hmac::Hmac<sha3::Sha3_512>),
441    #[cfg(feature = "sm3_256")]
442    Sm3_256(hmac::Hmac<sm3::Sm3>),
443}
444
445impl HmacInstanceState {
446    #[inline(never)]
447    fn new(alg: tpm2_interface::TpmiAlgHash, key: &[u8]) -> Result<Box<zeroize::ZeroizingFlat<Self>>, CryptoError> {
448        match alg {
449            #[cfg(feature = "sha1")]
450            tpm2_interface::TpmiAlgHash::Sha1 => {
451                // This in fact never fails and is always inlined, so the compiler can prove
452                // it's infallible.
453                let hmac_core = hmac::HmacCore::<sha1::Sha1>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
454
455                // The infallible enables zero-copy construction in place.
456                box_try_new_with(|| -> Result<_, convert::Infallible> {
457                    Ok(zeroize::ZeroizingFlat::from(Self::Sha1(hmac::Hmac::from_core(
458                        hmac_core,
459                    ))))
460                })
461                .map_err(CryptoError::from)
462            }
463            #[cfg(feature = "sha256")]
464            tpm2_interface::TpmiAlgHash::Sha256 => {
465                // This in fact never fails and is always inlined, so the compiler can prove
466                // it's infallible.
467                let hmac_core =
468                    hmac::HmacCore::<sha2::Sha256>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
469
470                // The infallible enables zero-copy construction in place.
471                box_try_new_with(|| -> Result<_, convert::Infallible> {
472                    Ok(zeroize::ZeroizingFlat::from(Self::Sha256(hmac::Hmac::from_core(
473                        hmac_core,
474                    ))))
475                })
476                .map_err(CryptoError::from)
477            }
478            #[cfg(feature = "sha384")]
479            tpm2_interface::TpmiAlgHash::Sha384 => {
480                // This in fact never fails and is always inlined, so the compiler can prove
481                // it's infallible.
482                let hmac_core =
483                    hmac::HmacCore::<sha2::Sha384>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
484
485                // The infallible enables zero-copy construction in place.
486                box_try_new_with(|| -> Result<_, convert::Infallible> {
487                    Ok(zeroize::ZeroizingFlat::from(Self::Sha384(hmac::Hmac::from_core(
488                        hmac_core,
489                    ))))
490                })
491                .map_err(CryptoError::from)
492            }
493            #[cfg(feature = "sha512")]
494            tpm2_interface::TpmiAlgHash::Sha512 => {
495                // This in fact never fails and is always inlined, so the compiler can prove
496                // it's infallible.
497                let hmac_core =
498                    hmac::HmacCore::<sha2::Sha512>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
499
500                // The infallible enables zero-copy construction in place.
501                box_try_new_with(|| -> Result<_, convert::Infallible> {
502                    Ok(zeroize::ZeroizingFlat::from(Self::Sha512(hmac::Hmac::from_core(
503                        hmac_core,
504                    ))))
505                })
506                .map_err(CryptoError::from)
507            }
508            #[cfg(feature = "sha3_256")]
509            tpm2_interface::TpmiAlgHash::Sha3_256 => {
510                // This in fact never fails and is always inlined, so the compiler can prove
511                // it's infallible.
512                let hmac_core =
513                    hmac::HmacCore::<sha3::Sha3_256>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
514
515                // The infallible enables zero-copy construction in place.
516                box_try_new_with(|| -> Result<_, convert::Infallible> {
517                    Ok(zeroize::ZeroizingFlat::from(Self::Sha3_256(hmac::Hmac::from_core(
518                        hmac_core,
519                    ))))
520                })
521                .map_err(CryptoError::from)
522            }
523            #[cfg(feature = "sha3_384")]
524            tpm2_interface::TpmiAlgHash::Sha3_384 => {
525                // This in fact never fails and is always inlined, so the compiler can prove
526                // it's infallible.
527                let hmac_core =
528                    hmac::HmacCore::<sha3::Sha3_384>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
529
530                // The infallible enables zero-copy construction in place.
531                box_try_new_with(|| -> Result<_, convert::Infallible> {
532                    Ok(zeroize::ZeroizingFlat::from(Self::Sha3_384(hmac::Hmac::from_core(
533                        hmac_core,
534                    ))))
535                })
536                .map_err(CryptoError::from)
537            }
538            #[cfg(feature = "sha3_512")]
539            tpm2_interface::TpmiAlgHash::Sha3_512 => {
540                // This in fact never fails and is always inlined, so the compiler can prove
541                // it's infallible.
542                let hmac_core =
543                    hmac::HmacCore::<sha3::Sha3_512>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
544
545                // The infallible enables zero-copy construction in place.
546                box_try_new_with(|| -> Result<_, convert::Infallible> {
547                    Ok(zeroize::ZeroizingFlat::from(Self::Sha3_512(hmac::Hmac::from_core(
548                        hmac_core,
549                    ))))
550                })
551                .map_err(CryptoError::from)
552            }
553            #[cfg(feature = "sm3_256")]
554            tpm2_interface::TpmiAlgHash::Sm3_256 => {
555                // This in fact never fails and is always inlined, so the compiler can prove
556                // it's infallible.
557                let hmac_core = hmac::HmacCore::<sm3::Sm3>::new_from_slice(key).map_err(|_| CryptoError::KeySize)?;
558
559                // The infallible enables zero-copy construction in place.
560                box_try_new_with(|| -> Result<_, convert::Infallible> {
561                    Ok(zeroize::ZeroizingFlat::from(Self::Sm3_256(hmac::Hmac::from_core(
562                        hmac_core,
563                    ))))
564                })
565                .map_err(CryptoError::from)
566            }
567        }
568    }
569
570    fn update<'a>(&mut self, data: &mut dyn CryptoIoSlicesIter<'a>) -> Result<(), CryptoError> {
571        match self {
572            #[cfg(feature = "sha1")]
573            Self::Sha1(instance) => {
574                while let Some(data) = data.next_slice(None)? {
575                    digest::Update::update(instance, data);
576                }
577            }
578            #[cfg(feature = "sha256")]
579            Self::Sha256(instance) => {
580                while let Some(data) = data.next_slice(None)? {
581                    digest::Update::update(instance, data);
582                }
583            }
584            #[cfg(feature = "sha384")]
585            Self::Sha384(instance) => {
586                while let Some(data) = data.next_slice(None)? {
587                    digest::Update::update(instance, data);
588                }
589            }
590            #[cfg(feature = "sha512")]
591            Self::Sha512(instance) => {
592                while let Some(data) = data.next_slice(None)? {
593                    digest::Update::update(instance, data);
594                }
595            }
596            #[cfg(feature = "sha3_256")]
597            Self::Sha3_256(instance) => {
598                while let Some(data) = data.next_slice(None)? {
599                    digest::Update::update(instance, data);
600                }
601            }
602            #[cfg(feature = "sha3_384")]
603            Self::Sha3_384(instance) => {
604                while let Some(data) = data.next_slice(None)? {
605                    digest::Update::update(instance, data);
606                }
607            }
608            #[cfg(feature = "sha3_512")]
609            Self::Sha3_512(instance) => {
610                while let Some(data) = data.next_slice(None)? {
611                    digest::Update::update(instance, data);
612                }
613            }
614            #[cfg(feature = "sm3_256")]
615            Self::Sm3_256(instance) => {
616                while let Some(data) = data.next_slice(None)? {
617                    digest::Update::update(instance, data);
618                }
619            }
620        }
621        Ok(())
622    }
623
624    fn finalize_into(self, digest: &mut [u8]) {
625        match self {
626            #[cfg(feature = "sha1")]
627            Self::Sha1(instance) => {
628                let digest: &mut crypto_common::Output<Hmac<sha1::Sha1>> = digest.into();
629                digest::FixedOutput::finalize_into(instance, digest);
630            }
631            #[cfg(feature = "sha256")]
632            Self::Sha256(instance) => {
633                let digest: &mut crypto_common::Output<Hmac<sha2::Sha256>> = digest.into();
634                digest::FixedOutput::finalize_into(instance, digest);
635            }
636            #[cfg(feature = "sha384")]
637            Self::Sha384(instance) => {
638                let digest: &mut crypto_common::Output<Hmac<sha2::Sha384>> = digest.into();
639                digest::FixedOutput::finalize_into(instance, digest);
640            }
641            #[cfg(feature = "sha512")]
642            Self::Sha512(instance) => {
643                let digest: &mut crypto_common::Output<Hmac<sha2::Sha512>> = digest.into();
644                digest::FixedOutput::finalize_into(instance, digest);
645            }
646            #[cfg(feature = "sha3_256")]
647            Self::Sha3_256(instance) => {
648                let digest: &mut crypto_common::Output<Hmac<sha3::Sha3_256>> = digest.into();
649                digest::FixedOutput::finalize_into(instance, digest);
650            }
651            #[cfg(feature = "sha3_384")]
652            Self::Sha3_384(instance) => {
653                let digest: &mut crypto_common::Output<Hmac<sha3::Sha3_384>> = digest.into();
654                digest::FixedOutput::finalize_into(instance, digest);
655            }
656            #[cfg(feature = "sha3_512")]
657            Self::Sha3_512(instance) => {
658                let digest: &mut crypto_common::Output<Hmac<sha3::Sha3_512>> = digest.into();
659                digest::FixedOutput::finalize_into(instance, digest);
660            }
661            #[cfg(feature = "sm3_256")]
662            Self::Sm3_256(instance) => {
663                let digest: &mut crypto_common::Output<Hmac<sm3::Sm3>> = digest.into();
664                digest::FixedOutput::finalize_into(instance, digest);
665            }
666        }
667    }
668
669    fn digest_len(&self) -> usize {
670        match self {
671            #[cfg(feature = "sha1")]
672            Self::Sha1(_) => <Hmac<sha1::Sha1> as crypto_common::OutputSizeUser>::output_size(),
673            #[cfg(feature = "sha256")]
674            Self::Sha256(_) => <Hmac<sha2::Sha256> as crypto_common::OutputSizeUser>::output_size(),
675            #[cfg(feature = "sha384")]
676            Self::Sha384(_) => <Hmac<sha2::Sha384> as crypto_common::OutputSizeUser>::output_size(),
677            #[cfg(feature = "sha512")]
678            Self::Sha512(_) => <Hmac<sha2::Sha512> as crypto_common::OutputSizeUser>::output_size(),
679            #[cfg(feature = "sha3_256")]
680            Self::Sha3_256(_) => <Hmac<sha3::Sha3_256> as crypto_common::OutputSizeUser>::output_size(),
681            #[cfg(feature = "sha3_384")]
682            Self::Sha3_384(_) => <Hmac<sha3::Sha3_384> as crypto_common::OutputSizeUser>::output_size(),
683            #[cfg(feature = "sha3_512")]
684            Self::Sha3_512(_) => <Hmac<sha3::Sha3_512> as crypto_common::OutputSizeUser>::output_size(),
685            #[cfg(feature = "sm3_256")]
686            Self::Sm3_256(_) => <Hmac<sm3::Sm3> as crypto_common::OutputSizeUser>::output_size(),
687        }
688    }
689}
690
691impl convert::From<&HmacInstanceState> for tpm2_interface::TpmiAlgHash {
692    fn from(instance_state: &HmacInstanceState) -> Self {
693        match instance_state {
694            #[cfg(feature = "sha1")]
695            HmacInstanceState::Sha1(_) => tpm2_interface::TpmiAlgHash::Sha1,
696            #[cfg(feature = "sha256")]
697            HmacInstanceState::Sha256(_) => tpm2_interface::TpmiAlgHash::Sha256,
698            #[cfg(feature = "sha384")]
699            HmacInstanceState::Sha384(_) => tpm2_interface::TpmiAlgHash::Sha384,
700            #[cfg(feature = "sha512")]
701            HmacInstanceState::Sha512(_) => tpm2_interface::TpmiAlgHash::Sha512,
702            #[cfg(feature = "sha3_256")]
703            HmacInstanceState::Sha3_256(_) => tpm2_interface::TpmiAlgHash::Sha3_256,
704            #[cfg(feature = "sha3_384")]
705            HmacInstanceState::Sha3_384(_) => tpm2_interface::TpmiAlgHash::Sha3_384,
706            #[cfg(feature = "sha3_512")]
707            HmacInstanceState::Sha3_512(_) => tpm2_interface::TpmiAlgHash::Sha3_512,
708            #[cfg(feature = "sm3_256")]
709            HmacInstanceState::Sm3_256(_) => tpm2_interface::TpmiAlgHash::Sm3_256,
710        }
711    }
712}