[go: up one dir, main page]

hmac/
optim.rs

1use super::{IPAD, OPAD, get_der_key};
2use core::{fmt, slice};
3use digest::{
4    HashMarker, InvalidLength, KeyInit, MacMarker, Output,
5    block_buffer::Eager,
6    core_api::{
7        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore,
8        OutputSizeUser, UpdateCore,
9    },
10    crypto_common::{Key, KeySizeUser},
11};
12
13/// Generic HMAC instance.
14pub type Hmac<D> = CoreWrapper<HmacCore<D>>;
15
16/// Trait implemented by eager hashes which expose their block-level core.
17pub trait EagerHash {
18    /// Block-level core type of the hash.
19    type Core: HashMarker
20        + UpdateCore
21        + FixedOutputCore
22        + BufferKindUser<BufferKind = Eager>
23        + Default
24        + Clone;
25}
26
27impl<C> EagerHash for CoreWrapper<C>
28where
29    C: HashMarker
30        + UpdateCore
31        + FixedOutputCore
32        + BufferKindUser<BufferKind = Eager>
33        + Default
34        + Clone,
35{
36    type Core = C;
37}
38
39/// Generic core HMAC instance, which operates over blocks.
40pub struct HmacCore<D: EagerHash> {
41    digest: D::Core,
42    opad_digest: D::Core,
43    #[cfg(feature = "reset")]
44    ipad_digest: D::Core,
45}
46
47impl<D: EagerHash> Clone for HmacCore<D> {
48    fn clone(&self) -> Self {
49        Self {
50            digest: self.digest.clone(),
51            opad_digest: self.opad_digest.clone(),
52            #[cfg(feature = "reset")]
53            ipad_digest: self.ipad_digest.clone(),
54        }
55    }
56}
57
58impl<D: EagerHash> MacMarker for HmacCore<D> {}
59
60impl<D: EagerHash> BufferKindUser for HmacCore<D> {
61    type BufferKind = Eager;
62}
63
64impl<D: EagerHash> KeySizeUser for HmacCore<D> {
65    type KeySize = <<D as EagerHash>::Core as BlockSizeUser>::BlockSize;
66}
67
68impl<D: EagerHash> BlockSizeUser for HmacCore<D> {
69    type BlockSize = <<D as EagerHash>::Core as BlockSizeUser>::BlockSize;
70}
71
72impl<D: EagerHash> OutputSizeUser for HmacCore<D> {
73    type OutputSize = <<D as EagerHash>::Core as OutputSizeUser>::OutputSize;
74}
75
76impl<D: EagerHash> KeyInit for HmacCore<D> {
77    #[inline(always)]
78    fn new(key: &Key<Self>) -> Self {
79        Self::new_from_slice(key.as_slice()).unwrap()
80    }
81
82    #[inline(always)]
83    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
84        let mut buf = get_der_key::<CoreWrapper<D::Core>>(key);
85        for b in buf.iter_mut() {
86            *b ^= IPAD;
87        }
88        let mut digest = D::Core::default();
89        digest.update_blocks(slice::from_ref(&buf));
90
91        for b in buf.iter_mut() {
92            *b ^= IPAD ^ OPAD;
93        }
94
95        let mut opad_digest = D::Core::default();
96        opad_digest.update_blocks(slice::from_ref(&buf));
97
98        Ok(Self {
99            #[cfg(feature = "reset")]
100            ipad_digest: digest.clone(),
101            opad_digest,
102            digest,
103        })
104    }
105}
106
107impl<D: EagerHash> UpdateCore for HmacCore<D> {
108    #[inline(always)]
109    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
110        self.digest.update_blocks(blocks);
111    }
112}
113
114impl<D: EagerHash> FixedOutputCore for HmacCore<D> {
115    #[inline(always)]
116    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
117        let mut hash = Output::<D::Core>::default();
118        self.digest.finalize_fixed_core(buffer, &mut hash);
119        // finalize_fixed_core should reset the buffer as well, but
120        // to be extra safe we reset it explicitly again.
121        buffer.reset();
122        #[cfg(not(feature = "reset"))]
123        let h = &mut self.opad_digest;
124        #[cfg(feature = "reset")]
125        let mut h = self.opad_digest.clone();
126        buffer.digest_blocks(&hash, |b| h.update_blocks(b));
127        h.finalize_fixed_core(buffer, out);
128    }
129}
130
131#[cfg(feature = "reset")]
132#[cfg_attr(docsrs, doc(cfg(feature = "reset")))]
133impl<D: EagerHash> digest::Reset for HmacCore<D> {
134    #[inline(always)]
135    fn reset(&mut self) {
136        self.digest = self.ipad_digest.clone();
137    }
138}
139
140impl<D: EagerHash> AlgorithmName for HmacCore<D>
141where
142    D::Core: AlgorithmName,
143{
144    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        f.write_str("Hmac<")?;
146        <D::Core as AlgorithmName>::write_alg_name(f)?;
147        f.write_str(">")
148    }
149}
150
151impl<D: EagerHash> fmt::Debug for HmacCore<D>
152where
153    D::Core: AlgorithmName,
154{
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        f.write_str("HmacCore<")?;
157        <D::Core as AlgorithmName>::write_alg_name(f)?;
158        f.write_str("> { ... }")
159    }
160}