use crate::error::Result;
use subtle::ConstantTimeEq;
use zeroize::Zeroize;
pub mod hmac;
pub mod poly1305;
pub use hmac::Hmac;
pub use poly1305::{Poly1305, POLY1305_KEY_SIZE, POLY1305_TAG_SIZE};
pub trait MacAlgorithm {
const KEY_SIZE: usize;
const TAG_SIZE: usize;
const BLOCK_SIZE: usize;
fn name() -> &'static str;
}
pub trait Mac: Sized {
type Key: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
type Tag: AsRef<[u8]> + AsMut<[u8]> + Clone;
fn new(key: &[u8]) -> Result<Self>;
fn update(&mut self, data: &[u8]) -> Result<&mut Self>;
fn finalize(&mut self) -> Result<Self::Tag>;
fn reset(&mut self) -> Result<()>;
fn compute_tag(key: &[u8], data: &[u8]) -> Result<Self::Tag> {
let mut mac = Self::new(key)?;
mac.update(data)?;
mac.finalize()
}
fn verify_tag(key: &[u8], data: &[u8], tag: &[u8]) -> Result<bool> {
let computed = Self::compute_tag(key, data)?;
if computed.as_ref().len() != tag.len() {
return Ok(false);
}
Ok(computed.as_ref().ct_eq(tag).into())
}
}
pub trait MacBuilder<'a, M: Mac>: Sized {
fn update(self, data: &'a [u8]) -> Result<Self>;
fn update_multi(self, data: &[&'a [u8]]) -> Result<Self>;
fn finalize(self) -> Result<M::Tag>;
fn verify(self, expected: &'a [u8]) -> Result<bool>;
}
pub struct GenericMacBuilder<'a, M: Mac> {
mac: &'a mut M,
}
impl<'a, M: Mac> MacBuilder<'a, M> for GenericMacBuilder<'a, M> {
fn update(self, data: &'a [u8]) -> Result<Self> {
self.mac.update(data)?;
Ok(self)
}
fn update_multi(self, data: &[&'a [u8]]) -> Result<Self> {
for chunk in data {
self.mac.update(chunk)?;
}
Ok(self)
}
fn finalize(self) -> Result<M::Tag> {
self.mac.finalize()
}
fn verify(self, expected: &'a [u8]) -> Result<bool> {
let tag = self.mac.finalize()?;
if tag.as_ref().len() != expected.len() {
return Ok(false);
}
Ok(tag.as_ref().ct_eq(expected).into())
}
}
pub trait MacExt: Mac {
fn builder(&mut self) -> GenericMacBuilder<'_, Self>;
}
impl<T: Mac> MacExt for T {
fn builder(&mut self) -> GenericMacBuilder<'_, Self> {
GenericMacBuilder { mac: self }
}
}