#![cfg_attr(all(feature = "getrandom", feature = "std"), doc = "```")]
#![cfg_attr(not(all(feature = "getrandom", feature = "std")), doc = "```ignore")]
#![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)]
mod deoxys_bc;
mod modes;
pub use aead::{self, consts, AeadCore, AeadInPlace, Error, Key, KeyInit, KeySizeUser};
use aead::{
consts::{U0, U16},
generic_array::{ArrayLength, GenericArray},
};
use core::marker::PhantomData;
use zeroize::Zeroize;
pub type DeoxysI128 = Deoxys<modes::DeoxysI<deoxys_bc::DeoxysBc256>, deoxys_bc::DeoxysBc256>;
pub type DeoxysI256 = Deoxys<modes::DeoxysI<deoxys_bc::DeoxysBc384>, deoxys_bc::DeoxysBc384>;
#[allow(clippy::upper_case_acronyms)]
pub type DeoxysII128 = Deoxys<modes::DeoxysII<deoxys_bc::DeoxysBc256>, deoxys_bc::DeoxysBc256>;
#[allow(clippy::upper_case_acronyms)]
pub type DeoxysII256 = Deoxys<modes::DeoxysII<deoxys_bc::DeoxysBc384>, deoxys_bc::DeoxysBc384>;
pub type Nonce<NonceSize> = GenericArray<u8, NonceSize>;
pub type Tag = GenericArray<u8, U16>;
pub trait DeoxysMode<B>: modes::DeoxysModeInternal<B>
where
B: DeoxysBcType,
{
type NonceSize: ArrayLength<u8>;
fn encrypt_in_place(
nonce: &GenericArray<u8, Self::NonceSize>,
associated_data: &[u8],
buffer: &mut [u8],
subkeys: &GenericArray<[u8; 16], B::SubkeysSize>,
) -> [u8; 16];
fn decrypt_in_place(
nonce: &GenericArray<u8, Self::NonceSize>,
associated_data: &[u8],
buffer: &mut [u8],
tag: &Tag,
subkeys: &GenericArray<[u8; 16], B::SubkeysSize>,
) -> Result<(), aead::Error>;
}
pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal {
type KeySize: ArrayLength<u8>;
fn precompute_subkeys(
key: &GenericArray<u8, Self::KeySize>,
) -> GenericArray<[u8; 16], Self::SubkeysSize>;
fn encrypt_in_place(
block: &mut [u8; 16],
tweak: &[u8; 16],
subkeys: &GenericArray<[u8; 16], Self::SubkeysSize>,
) {
let keys = Self::key_schedule(tweak, subkeys);
for (b, k) in block.iter_mut().zip(keys[0].iter()) {
*b ^= k;
}
for k in &keys[1..] {
aes::hazmat::cipher_round(block.into(), k.into());
}
}
fn decrypt_in_place(
block: &mut [u8; 16],
tweak: &[u8; 16],
subkeys: &GenericArray<[u8; 16], Self::SubkeysSize>,
) {
let mut keys = Self::key_schedule(tweak, subkeys);
let r = keys.len();
for (b, k) in block.iter_mut().zip(keys[r - 1].iter()) {
*b ^= k;
}
aes::hazmat::inv_mix_columns(block.into());
for k in keys[..r - 1].iter_mut().rev() {
aes::hazmat::inv_mix_columns(k.into());
aes::hazmat::equiv_inv_cipher_round(block.into(), (&*k).into());
}
aes::hazmat::mix_columns(block.into());
}
}
pub struct Deoxys<M, B>
where
M: DeoxysMode<B>,
B: DeoxysBcType,
{
subkeys: GenericArray<[u8; 16], B::SubkeysSize>,
mode: PhantomData<M>,
}
impl<M, B> KeySizeUser for Deoxys<M, B>
where
M: DeoxysMode<B>,
B: DeoxysBcType,
{
type KeySize = B::KeySize;
}
impl<M, B> KeyInit for Deoxys<M, B>
where
M: DeoxysMode<B>,
B: DeoxysBcType,
{
fn new(key: &Key<Self>) -> Self {
Self {
subkeys: B::precompute_subkeys(key),
mode: PhantomData,
}
}
}
impl<M, B> AeadCore for Deoxys<M, B>
where
M: DeoxysMode<B>,
B: DeoxysBcType,
{
type NonceSize = M::NonceSize;
type TagSize = U16;
type CiphertextOverhead = U0;
}
impl<M, B> AeadInPlace for Deoxys<M, B>
where
M: DeoxysMode<B>,
B: DeoxysBcType,
{
fn encrypt_in_place_detached(
&self,
nonce: &Nonce<M::NonceSize>,
associated_data: &[u8],
buffer: &mut [u8],
) -> Result<Tag, Error> {
Ok(Tag::from(M::encrypt_in_place(
nonce,
associated_data,
buffer,
&self.subkeys,
)))
}
fn decrypt_in_place_detached(
&self,
nonce: &Nonce<M::NonceSize>,
associated_data: &[u8],
buffer: &mut [u8],
tag: &Tag,
) -> Result<(), Error> {
M::decrypt_in_place(nonce, associated_data, buffer, tag, &self.subkeys)
}
}
impl<M, B> Drop for Deoxys<M, B>
where
M: DeoxysMode<B>,
B: DeoxysBcType,
{
fn drop(&mut self) {
for s in self.subkeys.iter_mut() {
s.zeroize();
}
}
}