use cmac::crypto_mac::generic_array::typenum::U16;
use cmac::crypto_mac::generic_array::GenericArray;
use std::fmt;
use subtle::{Choice, ConstantTimeEq};
use zeroize::Zeroize;
use crate::session::{SessionError, SessionErrorKind::VerifyFailed};
pub const MAC_SIZE: usize = 8;
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<(), SessionError>
where
M: Into<Mac>,
{
if self.ct_eq(&other.into()).unwrap_u8() == 1 {
Ok(())
} else {
fail!(VerifyFailed, "MAC mismatch!");
}
}
}
impl ConstantTimeEq for Mac {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.as_ref().ct_eq(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.zeroize();
}
}
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])
}
}