#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_root_url = "https://docs.rs/crypto-mac/0.11.1"
)]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "cipher")]
pub use cipher;
#[cfg(feature = "cipher")]
use cipher::{BlockCipher, NewBlockCipher};
#[cfg(feature = "dev")]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
pub mod dev;
mod errors;
pub use crate::errors::{InvalidKeyLength, MacError};
pub use generic_array::{self, typenum::consts};
use generic_array::typenum::Unsigned;
use generic_array::{ArrayLength, GenericArray};
use subtle::{Choice, ConstantTimeEq};
pub type Key<M> = GenericArray<u8, <M as NewMac>::KeySize>;
pub trait NewMac: Sized {
type KeySize: ArrayLength<u8>;
fn new(key: &Key<Self>) -> Self;
fn new_from_slice(key: &[u8]) -> Result<Self, InvalidKeyLength> {
if key.len() != Self::KeySize::to_usize() {
Err(InvalidKeyLength)
} else {
Ok(Self::new(GenericArray::from_slice(key)))
}
}
}
pub trait Mac: Clone {
type OutputSize: ArrayLength<u8>;
fn update(&mut self, data: &[u8]);
fn reset(&mut self);
fn finalize(self) -> Output<Self>;
fn finalize_reset(&mut self) -> Output<Self> {
let res = self.clone().finalize();
self.reset();
res
}
fn verify(self, tag: &[u8]) -> Result<(), MacError> {
let choice = self.finalize().bytes.ct_eq(tag);
if choice.unwrap_u8() == 1 {
Ok(())
} else {
Err(MacError)
}
}
}
#[derive(Clone)]
pub struct Output<M: Mac> {
bytes: GenericArray<u8, M::OutputSize>,
}
impl<M: Mac> Output<M> {
pub fn new(bytes: GenericArray<u8, M::OutputSize>) -> Output<M> {
Output { bytes }
}
pub fn into_bytes(self) -> GenericArray<u8, M::OutputSize> {
self.bytes
}
}
impl<M: Mac> ConstantTimeEq for Output<M> {
fn ct_eq(&self, other: &Self) -> Choice {
self.bytes.ct_eq(&other.bytes)
}
}
impl<M: Mac> PartialEq for Output<M> {
fn eq(&self, x: &Output<M>) -> bool {
self.ct_eq(x).unwrap_u8() == 1
}
}
impl<M: Mac> Eq for Output<M> {}
#[cfg(feature = "cipher")]
#[cfg_attr(docsrs, doc(cfg(feature = "cipher")))]
pub trait FromBlockCipher {
type Cipher: BlockCipher;
fn from_cipher(cipher: Self::Cipher) -> Self;
}
#[cfg(feature = "cipher")]
#[cfg_attr(docsrs, doc(cfg(feature = "cipher")))]
impl<T> NewMac for T
where
T: FromBlockCipher,
T::Cipher: NewBlockCipher,
{
type KeySize = <<Self as FromBlockCipher>::Cipher as NewBlockCipher>::KeySize;
fn new(key: &Key<Self>) -> Self {
let cipher = <Self as FromBlockCipher>::Cipher::new(key);
Self::from_cipher(cipher)
}
fn new_from_slice(key: &[u8]) -> Result<Self, InvalidKeyLength> {
<Self as FromBlockCipher>::Cipher::new_from_slice(key)
.map_err(|_| InvalidKeyLength)
.map(Self::from_cipher)
}
}