use super::{get_der_key, IPAD, OPAD}; use core::{fmt, slice}; #[cfg(feature = "reset")] use digest::Reset; use digest::{ block_buffer::Eager, core_api::{ AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreProxy, CoreWrapper, FixedOutputCore, OutputSizeUser, UpdateCore, }, crypto_common::{Key, KeySizeUser}, generic_array::typenum::{IsLess, Le, NonZero, U256}, HashMarker, InvalidLength, KeyInit, MacMarker, Output, }; /// Generic HMAC instance. pub type Hmac = CoreWrapper>; /// Generic core HMAC instance, which operates over blocks. pub struct HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { digest: D::Core, opad_digest: D::Core, #[cfg(feature = "reset")] ipad_digest: D::Core, } impl Clone for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { fn clone(&self) -> Self { Self { digest: self.digest.clone(), opad_digest: self.opad_digest.clone(), #[cfg(feature = "reset")] ipad_digest: self.ipad_digest.clone(), } } } impl MacMarker for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { } impl BufferKindUser for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { type BufferKind = Eager; } impl KeySizeUser for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { type KeySize = <::Core as BlockSizeUser>::BlockSize; } impl BlockSizeUser for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { type BlockSize = <::Core as BlockSizeUser>::BlockSize; } impl OutputSizeUser for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { type OutputSize = <::Core as OutputSizeUser>::OutputSize; } impl KeyInit for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { #[inline(always)] fn new(key: &Key) -> Self { Self::new_from_slice(key.as_slice()).unwrap() } #[inline(always)] fn new_from_slice(key: &[u8]) -> Result { let mut buf = get_der_key::>(key); for b in buf.iter_mut() { *b ^= IPAD; } let mut digest = D::Core::default(); digest.update_blocks(slice::from_ref(&buf)); for b in buf.iter_mut() { *b ^= IPAD ^ OPAD; } let mut opad_digest = D::Core::default(); opad_digest.update_blocks(slice::from_ref(&buf)); Ok(Self { #[cfg(feature = "reset")] ipad_digest: digest.clone(), opad_digest, digest, }) } } impl UpdateCore for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { #[inline(always)] fn update_blocks(&mut self, blocks: &[Block]) { self.digest.update_blocks(blocks); } } impl FixedOutputCore for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { #[inline(always)] fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output) { let mut hash = Output::::default(); self.digest.finalize_fixed_core(buffer, &mut hash); // finalize_fixed_core should reset the buffer as well, but // to be extra safe we reset it explicitly again. buffer.reset(); #[cfg(not(feature = "reset"))] let h = &mut self.opad_digest; #[cfg(feature = "reset")] let mut h = self.opad_digest.clone(); buffer.digest_blocks(&hash, |b| h.update_blocks(b)); h.finalize_fixed_core(buffer, out); } } #[cfg(feature = "reset")] #[cfg_attr(docsrs, doc(cfg(feature = "reset")))] impl Reset for HmacCore where D: CoreProxy, D::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { #[inline(always)] fn reset(&mut self) { self.digest = self.ipad_digest.clone(); } } impl AlgorithmName for HmacCore where D: CoreProxy, D::Core: HashMarker + AlgorithmName + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Hmac<")?; ::write_alg_name(f)?; f.write_str(">") } } impl fmt::Debug for HmacCore where D: CoreProxy, D::Core: HashMarker + AlgorithmName + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("HmacCore<")?; ::write_alg_name(f)?; f.write_str("> { ... }") } }