#![no_std]
#![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"
)]
#![warn(missing_docs, rust_2018_idioms)]
use aead::{
consts::U0, generic_array::GenericArray, AeadCore, AeadInPlace, Error, Key, KeyInit,
KeySizeUser,
};
use cfg_if::cfg_if;
use cipher::{BlockCipher, BlockEncrypt, NewBlockCipher};
pub use aead;
mod encdec;
mod gf;
mod sealed;
use sealed::Sealed;
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
cpufeatures::new!(mul_intrinsics, "sse2", "ssse3", "pclmulqdq");
pub type Nonce<NonceSize> = GenericArray<u8, NonceSize>;
pub type Tag<TagSize> = GenericArray<u8, TagSize>;
type Block<C> = GenericArray<u8, <C as BlockCipher>::BlockSize>;
type EncArgs<'a, C> = (&'a C, &'a Block<C>, &'a [u8], &'a mut [u8]);
type DecArgs<'a, C> = (&'a C, &'a Block<C>, &'a [u8], &'a mut [u8], &'a Block<C>);
pub trait MgmBlockSize: sealed::Sealed {}
impl<T: Sealed> MgmBlockSize for T {}
#[derive(Clone, Debug)]
pub struct Mgm<C>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
cipher: C,
}
impl<C> From<C> for Mgm<C>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
fn from(cipher: C) -> Self {
Self { cipher }
}
}
impl<C> KeySizeUser for Mgm<C>
where
C: BlockEncrypt + NewBlockCipher,
C::BlockSize: MgmBlockSize,
{
type KeySize = C::KeySize;
}
impl<C> KeyInit for Mgm<C>
where
C: BlockEncrypt + NewBlockCipher,
C::BlockSize: MgmBlockSize,
{
fn new(key: &Key<Self>) -> Self {
Self::from(C::new(key))
}
}
impl<C> AeadCore for Mgm<C>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
type NonceSize = C::BlockSize;
type TagSize = C::BlockSize;
type CiphertextOverhead = U0;
}
impl<C> AeadInPlace for Mgm<C>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
fn encrypt_in_place_detached(
&self,
nonce: &Nonce<Self::NonceSize>,
adata: &[u8],
buffer: &mut [u8],
) -> Result<Tag<Self::TagSize>, Error> {
if nonce[0] >> 7 != 0 {
return Err(Error);
}
mgm_encrypt((&self.cipher, nonce, adata, buffer))
}
fn decrypt_in_place_detached(
&self,
nonce: &Nonce<Self::NonceSize>,
adata: &[u8],
buffer: &mut [u8],
expected_tag: &Tag<Self::TagSize>,
) -> Result<(), Error> {
if nonce[0] >> 7 != 0 {
return Err(Error);
}
mgm_decrypt((&self.cipher, nonce, adata, buffer, expected_tag))
}
}
cfg_if! {
if #[cfg(all(
any(target_arch = "x86_64", target_arch = "x86"),
not(feature = "force-soft")
))] {
#[target_feature(enable = "pclmulqdq")]
#[target_feature(enable = "ssse3")]
#[target_feature(enable = "sse2")]
unsafe fn wrapper<R: Sized>(f: impl FnOnce() -> R) -> R {
f()
}
fn mgm_encrypt<C>(args: EncArgs<'_, C>) -> Result<Block<C>, Error>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
if mul_intrinsics::get() {
unsafe {
wrapper(|| {
encdec::encrypt::<
C,
gf::gf64_pclmul::Element,
gf::gf128_pclmul::Element,
>(args)
})
}
} else {
encdec::encrypt::<C, gf::gf64_soft64::Element, gf::gf128_soft64::Element>(args)
}
}
fn mgm_decrypt<C>(args: DecArgs<'_, C>) -> Result<(), Error>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
if mul_intrinsics::get() {
unsafe {
wrapper(|| {
encdec::decrypt::<
C,
gf::gf64_pclmul::Element,
gf::gf128_pclmul::Element,
>(args)
})
}
} else {
encdec::decrypt::<C, gf::gf64_soft64::Element, gf::gf128_soft64::Element>(args)
}
}
} else {
fn mgm_encrypt<C>(args: EncArgs<'_, C>) -> Result<Block<C>, Error>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
encdec::encrypt::<C, gf::gf64_soft64::Element, gf::gf128_soft64::Element>(args)
}
fn mgm_decrypt<C>(args: DecArgs<'_, C>) -> Result<(), Error>
where
C: BlockEncrypt,
C::BlockSize: MgmBlockSize,
{
encdec::decrypt::<C, gf::gf64_soft64::Element, gf::gf128_soft64::Element>(args)
}
}
}