hmac/
simple.rs

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/// Simplified HMAC instance able to operate over hash functions
11/// which do not expose block-level API and hash functions which
12/// process blocks lazily (e.g. BLAKE2).
13#[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            // TODO: replace with `finish_non_exhaustive` on MSRV
81            // bump to 1.53
82            .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}