use {
crate::{Hash, Mac},
docext::docext,
};
const OPAD: u8 = 0x5C;
const IPAD: u8 = 0x36;
#[docext]
pub struct Hmac<H>(H);
impl<H> Hmac<H> {
pub fn new(h: H) -> Self {
Self(h)
}
}
impl<H, const BLOCK_SIZE: usize, const DIGEST_SIZE: usize> Mac for Hmac<H>
where
H: Hash<Block = [u8; BLOCK_SIZE], Digest = [u8; DIGEST_SIZE]>,
{
type Tag = H::Digest;
fn mac(&mut self, msg: &[u8], key: &[u8]) -> Self::Tag {
let mut k = [0; BLOCK_SIZE];
if key.len() <= BLOCK_SIZE {
k[..key.len()].copy_from_slice(key);
} else {
let s = DIGEST_SIZE.min(BLOCK_SIZE);
let h = self.0.hash(key);
k[..s].copy_from_slice(&h[..s]);
};
let mut inner_preimage = Vec::new();
inner_preimage.extend(k.iter().map(|n| n ^ IPAD));
inner_preimage.extend(msg);
let inner_hash = self.0.hash(&inner_preimage);
let mut outer_preimage = Vec::new();
outer_preimage.extend(k.iter().map(|n| n ^ OPAD));
outer_preimage.extend(inner_hash);
self.0.hash(&outer_preimage)
}
}