Skip to main content
This is unreleased documentation for the main (development) branch of crypto-glue.

hmac/
block_api.rs

1use crate::utils::{IPAD, OPAD, get_der_key};
2use core::{fmt, slice};
3use digest::{
4    InvalidLength, KeyInit, MacMarker, Output, Reset,
5    block_api::{
6        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, EagerHash, FixedOutputCore,
7        OutputSizeUser, UpdateCore,
8    },
9    block_buffer::Eager,
10    common::{Key, KeySizeUser},
11};
12
13/// Generic core HMAC instance, which operates over blocks.
14pub struct HmacCore<D: EagerHash> {
15    digest: D::Core,
16    opad_digest: D::Core,
17}
18
19impl<D: EagerHash> Clone for HmacCore<D> {
20    fn clone(&self) -> Self {
21        Self {
22            digest: self.digest.clone(),
23            opad_digest: self.opad_digest.clone(),
24        }
25    }
26}
27
28impl<D: EagerHash> MacMarker for HmacCore<D> {}
29
30impl<D: EagerHash> BufferKindUser for HmacCore<D> {
31    type BufferKind = Eager;
32}
33
34impl<D: EagerHash> KeySizeUser for HmacCore<D> {
35    type KeySize = <<D as EagerHash>::Core as BlockSizeUser>::BlockSize;
36}
37
38impl<D: EagerHash> BlockSizeUser for HmacCore<D> {
39    type BlockSize = <<D as EagerHash>::Core as BlockSizeUser>::BlockSize;
40}
41
42impl<D: EagerHash> OutputSizeUser for HmacCore<D> {
43    type OutputSize = <<D as EagerHash>::Core as OutputSizeUser>::OutputSize;
44}
45
46impl<D: EagerHash> KeyInit for HmacCore<D> {
47    #[inline(always)]
48    fn new(key: &Key<Self>) -> Self {
49        Self::new_from_slice(key.as_slice()).unwrap()
50    }
51
52    #[inline(always)]
53    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
54        let mut buf = get_der_key::<D>(key);
55        buf.iter_mut().for_each(|b: &mut u8| *b ^= IPAD);
56
57        let mut digest = D::Core::default();
58        digest.update_blocks(slice::from_ref(&buf));
59
60        buf.iter_mut().for_each(|b: &mut u8| *b ^= IPAD ^ OPAD);
61
62        let mut opad_digest = D::Core::default();
63        opad_digest.update_blocks(slice::from_ref(&buf));
64
65        Ok(Self {
66            opad_digest,
67            digest,
68        })
69    }
70}
71
72impl<D: EagerHash> UpdateCore for HmacCore<D> {
73    #[inline(always)]
74    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
75        self.digest.update_blocks(blocks);
76    }
77}
78
79impl<D: EagerHash> FixedOutputCore for HmacCore<D> {
80    #[inline(always)]
81    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
82        let mut hash = Output::<D::Core>::default();
83        self.digest.finalize_fixed_core(buffer, &mut hash);
84        // finalize_fixed_core should reset the buffer as well, but
85        // to be extra safe we reset it explicitly again.
86        buffer.reset();
87        let h = &mut self.opad_digest;
88        buffer.digest_blocks(&hash, |b| h.update_blocks(b));
89        h.finalize_fixed_core(buffer, out);
90    }
91}
92
93impl<D: EagerHash + AlgorithmName> AlgorithmName for HmacCore<D> {
94    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        f.write_str("Hmac<")?;
96        <D as AlgorithmName>::write_alg_name(f)?;
97        f.write_str(">")
98    }
99}
100
101impl<D: EagerHash> fmt::Debug for HmacCore<D>
102where
103    D::Core: AlgorithmName,
104{
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        f.write_str("HmacCore { ... }")
107    }
108}
109
110/// Generic core HMAC instance, which operates over blocks.
111pub struct HmacResetCore<D: EagerHash> {
112    digest: D::Core,
113    opad_digest: D::Core,
114    ipad_digest: D::Core,
115}
116
117impl<D: EagerHash> Clone for HmacResetCore<D> {
118    fn clone(&self) -> Self {
119        Self {
120            digest: self.digest.clone(),
121            opad_digest: self.opad_digest.clone(),
122            ipad_digest: self.ipad_digest.clone(),
123        }
124    }
125}
126
127impl<D: EagerHash> MacMarker for HmacResetCore<D> {}
128
129impl<D: EagerHash> BufferKindUser for HmacResetCore<D> {
130    type BufferKind = Eager;
131}
132
133impl<D: EagerHash> KeySizeUser for HmacResetCore<D> {
134    type KeySize = <<D as EagerHash>::Core as BlockSizeUser>::BlockSize;
135}
136
137impl<D: EagerHash> BlockSizeUser for HmacResetCore<D> {
138    type BlockSize = <<D as EagerHash>::Core as BlockSizeUser>::BlockSize;
139}
140
141impl<D: EagerHash> OutputSizeUser for HmacResetCore<D> {
142    type OutputSize = <<D as EagerHash>::Core as OutputSizeUser>::OutputSize;
143}
144
145impl<D: EagerHash> KeyInit for HmacResetCore<D> {
146    #[inline(always)]
147    fn new(key: &Key<Self>) -> Self {
148        Self::new_from_slice(key.as_slice()).unwrap()
149    }
150
151    #[inline(always)]
152    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
153        let mut buf = get_der_key::<D>(key);
154        buf.iter_mut().for_each(|b: &mut u8| *b ^= IPAD);
155
156        let mut digest = D::Core::default();
157        digest.update_blocks(slice::from_ref(&buf));
158
159        buf.iter_mut().for_each(|b: &mut u8| *b ^= IPAD ^ OPAD);
160
161        let mut opad_digest = D::Core::default();
162        opad_digest.update_blocks(slice::from_ref(&buf));
163
164        Ok(Self {
165            ipad_digest: digest.clone(),
166            opad_digest,
167            digest,
168        })
169    }
170}
171
172impl<D: EagerHash> UpdateCore for HmacResetCore<D> {
173    #[inline(always)]
174    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
175        self.digest.update_blocks(blocks);
176    }
177}
178
179impl<D: EagerHash> FixedOutputCore for HmacResetCore<D> {
180    #[inline(always)]
181    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
182        let mut hash = Output::<D::Core>::default();
183        self.digest.finalize_fixed_core(buffer, &mut hash);
184        // finalize_fixed_core should reset the buffer as well, but
185        // to be extra safe we reset it explicitly again.
186        buffer.reset();
187        let mut h = self.opad_digest.clone();
188        buffer.digest_blocks(&hash, |b| h.update_blocks(b));
189        h.finalize_fixed_core(buffer, out);
190    }
191}
192
193impl<D: EagerHash> Reset for HmacResetCore<D> {
194    #[inline(always)]
195    fn reset(&mut self) {
196        self.digest = self.ipad_digest.clone();
197    }
198}
199
200impl<D: EagerHash + AlgorithmName> AlgorithmName for HmacResetCore<D> {
201    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        f.write_str("Hmac<")?;
203        <D as AlgorithmName>::write_alg_name(f)?;
204        f.write_str(">")
205    }
206}
207
208impl<D: EagerHash> fmt::Debug for HmacResetCore<D>
209where
210    D::Core: AlgorithmName,
211{
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        f.write_str("HmacResetCore { ... }")
214    }
215}