#![no_std]
#![doc(html_logo_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
pub extern crate digest;
pub extern crate crypto_mac;
pub use crypto_mac::Mac;
use crypto_mac::{InvalidKeyLength, MacResult};
use digest::{Input, BlockInput, FixedOutput, Reset};
use digest::generic_array::{ArrayLength, GenericArray};
use digest::generic_array::sequence::GenericSequence;
use core::cmp::min;
use core::fmt;
const IPAD: u8 = 0x36;
const OPAD: u8 = 0x5C;
pub struct Hmac<D>
where D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
D::BlockSize: ArrayLength<u8>
{
digest: D,
i_key_pad: GenericArray<u8, D::BlockSize>,
opad_digest: D,
}
impl<D> Clone for Hmac<D>
where D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
D::BlockSize: ArrayLength<u8>
{
fn clone(&self) -> Hmac<D> {
Hmac {
digest: self.digest.clone(),
i_key_pad: self.i_key_pad.clone(),
opad_digest: self.opad_digest.clone(),
}
}
}
impl<D> fmt::Debug for Hmac<D>
where D: Input + BlockInput + FixedOutput + Reset + Default + Clone + fmt::Debug,
D::BlockSize: ArrayLength<u8>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Hmac")
.field("digest", &self.digest)
.field("i_key_pad", &self.i_key_pad)
.field("opad_digest", &self.opad_digest)
.finish()
}
}
impl <D> Mac for Hmac<D>
where D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
D::BlockSize: ArrayLength<u8>,
D::OutputSize: ArrayLength<u8>
{
type OutputSize = D::OutputSize;
type KeySize = D::BlockSize;
fn new(key: &GenericArray<u8, Self::KeySize>) -> Self {
Self::new_varkey(key.as_slice()).unwrap()
}
#[inline]
fn new_varkey(key: &[u8]) -> Result<Self, InvalidKeyLength> {
let mut hmac = Self {
digest: Default::default(),
i_key_pad: GenericArray::generate(|_| IPAD),
opad_digest: Default::default(),
};
let mut opad = GenericArray::<u8, D::BlockSize>::generate(|_| OPAD);
debug_assert!(hmac.i_key_pad.len() == opad.len());
if key.len() <= hmac.i_key_pad.len() {
for (k_idx, k_itm) in key.iter().enumerate() {
hmac.i_key_pad[k_idx] ^= *k_itm;
opad[k_idx] ^= *k_itm;
}
} else {
let mut digest = D::default();
digest.input(key);
let output = digest.fixed_result();
let n = min(output.len(), hmac.i_key_pad.len());
for idx in 0..n {
hmac.i_key_pad[idx] ^= output[idx];
opad[idx] ^= output[idx];
}
}
hmac.digest.input(&hmac.i_key_pad);
hmac.opad_digest.input(&opad);
Ok(hmac)
}
#[inline]
fn input(&mut self, data: &[u8]) {
self.digest.input(data);
}
#[inline]
fn result(self) -> MacResult<D::OutputSize> {
let mut opad_digest = self.opad_digest.clone();
let hash = self.digest.fixed_result();
opad_digest.input(&hash);
MacResult::new(opad_digest.fixed_result())
}
#[inline]
fn reset(&mut self) {
self.digest.reset();
self.digest.input(&self.i_key_pad);
}
}