use clear_on_drop::clear::Clear;
use cmac::crypto_mac::generic_array::GenericArray;
use cmac::crypto_mac::generic_array::typenum::U16;
use constant_time_eq::constant_time_eq;
use failure::Error;
use std::fmt;
use super::SecureChannelError;
pub const MAC_SIZE: usize = 8;
#[derive(Eq)]
pub struct Mac([u8; MAC_SIZE]);
impl Mac {
pub fn from_slice(slice: &[u8]) -> Self {
assert_eq!(slice.len(), 8, "MAC must be 8-bytes long");
let mut mac = [0u8; MAC_SIZE];
mac.copy_from_slice(slice);
Mac(mac)
}
pub fn as_slice(&self) -> &[u8] {
&self.0
}
pub fn verify<M>(&self, other: M) -> Result<(), Error>
where
M: Into<Mac>,
{
let other_mac: Mac = other.into();
if *self != other_mac {
fail!(SecureChannelError::VerifyFailed, "MAC mismatch!");
}
Ok(())
}
}
impl PartialEq for Mac {
fn eq(&self, other: &Mac) -> bool {
constant_time_eq(self.0.as_ref(), other.0.as_ref())
}
}
impl fmt::Debug for Mac {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "yubihsm::Mac")
}
}
impl Drop for Mac {
fn drop(&mut self) {
self.0.clear();
}
}
impl<'a> From<&'a GenericArray<u8, U16>> for Mac {
fn from(array: &'a GenericArray<u8, U16>) -> Self {
Self::from_slice(&array.as_slice()[..MAC_SIZE])
}
}