use seckey::Bytes;
use ::hash::{ Hash, GenericHash };
use super::{ Mac, NonceMac };
#[derive(Debug, Clone)]
pub struct HMAC<H> {
key: Bytes,
ih: H,
oh: H
}
impl<H> Mac for HMAC<H> where H: Hash {
const KEY_LENGTH: usize = 32;
const TAG_LENGTH: usize = H::DIGEST_LENGTH;
fn new(key: &[u8]) -> Self where Self: Sized {
assert_eq!(key.len(), Self::KEY_LENGTH);
HMAC {
key: Bytes::new(key),
ih: H::default(),
oh: H::default()
}
}
fn result<T>(&self, data: &[u8]) -> T where T: From<Vec<u8>> {
let mut ipad = vec![0x36; 64];
let mut opad = vec![0x5c; 64];
for (i, &b) in self.key.iter().take(64).enumerate() {
ipad[i] ^= b;
opad[i] ^= b;
}
ipad.extend_from_slice(data);
opad.append(&mut self.ih.hash::<Vec<u8>>(&ipad));
self.oh.hash(&opad)
}
}
impl<H> NonceMac for HMAC<H> where H: GenericHash {
const NONCE_LENGTH: usize = 32;
#[inline]
fn with_nonce(&mut self, nonce: &[u8]) -> &mut Self {
assert_eq!(nonce.len(), Self::NONCE_LENGTH);
self.ih.with_key(nonce);
self.oh.with_key(nonce);
self
}
#[inline]
fn with_size(&mut self, len: usize) -> &mut Self {
self.oh.with_size(len);
self
}
}