1use super::{get_der_key, IPAD, OPAD};
2use core::fmt;
3use digest::{
4 crypto_common::{Block, BlockSizeUser, InvalidLength, Key, KeySizeUser},
5 Digest, FixedOutput, KeyInit, MacMarker, Output, OutputSizeUser, Update,
6};
7#[cfg(feature = "reset")]
8use digest::{FixedOutputReset, Reset};
9
10#[derive(Clone)]
14pub struct SimpleHmac<D: Digest + BlockSizeUser> {
15 digest: D,
16 opad_key: Block<D>,
17 #[cfg(feature = "reset")]
18 ipad_key: Block<D>,
19}
20
21impl<D: Digest + BlockSizeUser> KeySizeUser for SimpleHmac<D> {
22 type KeySize = D::BlockSize;
23}
24
25impl<D: Digest + BlockSizeUser> MacMarker for SimpleHmac<D> {}
26
27impl<D: Digest + BlockSizeUser> KeyInit for SimpleHmac<D> {
28 fn new(key: &Key<Self>) -> Self {
29 Self::new_from_slice(key.as_slice()).unwrap()
30 }
31
32 #[inline]
33 fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
34 let der_key = get_der_key::<D>(key);
35 let mut ipad_key = der_key.clone();
36 for b in ipad_key.iter_mut() {
37 *b ^= IPAD;
38 }
39 let mut digest = D::new();
40 digest.update(&ipad_key);
41
42 let mut opad_key = der_key;
43 for b in opad_key.iter_mut() {
44 *b ^= OPAD;
45 }
46
47 Ok(Self {
48 digest,
49 opad_key,
50 #[cfg(feature = "reset")]
51 ipad_key,
52 })
53 }
54}
55
56impl<D: Digest + BlockSizeUser> Update for SimpleHmac<D> {
57 #[inline(always)]
58 fn update(&mut self, data: &[u8]) {
59 self.digest.update(data);
60 }
61}
62
63impl<D: Digest + BlockSizeUser> OutputSizeUser for SimpleHmac<D> {
64 type OutputSize = D::OutputSize;
65}
66
67impl<D: Digest + BlockSizeUser> FixedOutput for SimpleHmac<D> {
68 fn finalize_into(self, out: &mut Output<Self>) {
69 let mut h = D::new();
70 h.update(&self.opad_key);
71 h.update(&self.digest.finalize());
72 h.finalize_into(out);
73 }
74}
75
76impl<D: Digest + BlockSizeUser + fmt::Debug> fmt::Debug for SimpleHmac<D> {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 f.debug_struct("SimpleHmac")
79 .field("digest", &self.digest)
80 .field("..", &"..")
83 .finish()
84 }
85}
86
87#[cfg(feature = "reset")]
88#[cfg_attr(docsrs, doc(cfg(feature = "reset")))]
89impl<D: Digest + BlockSizeUser + Reset> Reset for SimpleHmac<D> {
90 fn reset(&mut self) {
91 Reset::reset(&mut self.digest);
92 self.digest.update(&self.ipad_key);
93 }
94}
95
96#[cfg(feature = "reset")]
97#[cfg_attr(docsrs, doc(cfg(feature = "reset")))]
98impl<D: Digest + BlockSizeUser + FixedOutputReset> FixedOutputReset for SimpleHmac<D> {
99 fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
100 let mut h = D::new();
101 Update::update(&mut h, &self.opad_key);
102 Update::update(&mut h, &self.digest.finalize_reset());
103 Update::update(&mut self.digest, &self.ipad_key);
104 Digest::finalize_into(h, out);
105 }
106}