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
13pub 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 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
110pub 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 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}