use super::ring;
macro_rules! aesgcm {
($name:ident, $cipher:ident) => {
pub mod $name {
use super::{
super::$name::{KEY_LEN, NONCE_LEN, TAG_LEN},
ring,
};
use crate::{
aead,
aes::{
x86::$cipher::{EncryptionKey, Key as AesKey},
$cipher::Key as Wrapper,
Encrypt,
},
aesgcm::generic::AesGcm,
arch::*,
block::{Block, Zeroed as _, LEN as BLOCK_LEN},
ctr::x86::Ctr,
ghash::x86::{hkey, precomputed},
};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[allow(clippy::large_enum_variant)]
#[derive(Zeroize)]
pub enum Key {
Precomputed(PrecomputedKey),
Ring(ring::$name::Key),
}
impl Key {
#[inline]
pub fn new(secret: &[u8; KEY_LEN]) -> Self {
let key = ring::$name::Key::new(secret);
Self::Ring(key)
}
pub fn should_update_pmtu(&self, mtu: u16) -> bool {
match self {
_ if !Avx2::is_supported() => false,
Self::Precomputed(key) if key.mtu >= mtu => false,
_ => true,
}
}
pub fn update(&self, secret: &[u8; KEY_LEN]) -> Self {
match self {
Self::Ring(_) => Self::new(secret),
Self::Precomputed(key) => Self::Precomputed(unsafe {
debug_assert!(Avx2::is_supported());
PrecomputedKey::new(secret, key.mtu)
}),
}
}
pub fn update_pmtu(&mut self, secret: &[u8; KEY_LEN], mtu: u16) {
debug_assert!(self.should_update_pmtu(mtu));
*self = Self::Precomputed(unsafe {
debug_assert!(Avx2::is_supported());
PrecomputedKey::new(secret, mtu)
})
}
}
impl aead::Aead for Key {
type Nonce = [u8; NONCE_LEN];
type Tag = [u8; TAG_LEN];
#[inline]
fn encrypt(
&self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
input: &mut [u8],
tag: &mut [u8; TAG_LEN],
) -> aead::Result {
match self {
Self::Precomputed(key) => key.encrypt(nonce, aad, input, tag),
Self::Ring(key) => key.encrypt(nonce, aad, input, tag),
}
}
#[inline]
fn decrypt(
&self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
input: &mut [u8],
tag: &[u8; TAG_LEN],
) -> aead::Result {
match self {
Self::Precomputed(key) => key.decrypt(nonce, aad, input, tag),
Self::Ring(key) => key.decrypt(nonce, aad, input, tag),
}
}
}
type PrecomputedGHash = precomputed::Allocated<hkey::H>;
type PrecomputedAesGcmKey = AesGcm<Wrapper<EncryptionKey>, PrecomputedGHash, Ctr, 6>;
#[derive(Zeroize, ZeroizeOnDrop)]
pub struct PrecomputedKey {
key: PrecomputedAesGcmKey,
mtu: u16,
}
impl PrecomputedKey {
#[inline]
#[target_feature(enable = "aes,avx2,pclmulqdq")]
unsafe fn new(secret: &[u8; KEY_LEN], mtu: u16) -> Self {
debug_assert!(Avx2::is_supported());
let AesKey { encrypt, .. } = AesKey::new(*secret);
let key = Wrapper(encrypt);
let mut ghash_key = __m128i::zeroed();
key.encrypt(&mut ghash_key);
let blocks = (mtu as usize + BLOCK_LEN - 1) / BLOCK_LEN;
let ghash = PrecomputedGHash::new(ghash_key.into_array(), blocks);
let key = AesGcm::new(key, ghash);
Self { key, mtu }
}
#[inline]
#[target_feature(enable = "aes,avx2,pclmulqdq")]
unsafe fn encrypt_impl(
&self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
input: &mut [u8],
tag: &mut [u8; TAG_LEN],
) -> aead::Result {
aead::Aead::encrypt(&self.key, nonce, aad, input, tag)
}
#[inline]
#[target_feature(enable = "aes,avx2,pclmulqdq")]
unsafe fn decrypt_impl(
&self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
input: &mut [u8],
tag: &[u8; TAG_LEN],
) -> aead::Result {
aead::Aead::decrypt(&self.key, nonce, aad, input, tag)
}
}
impl aead::Aead for PrecomputedKey {
type Nonce = [u8; NONCE_LEN];
type Tag = [u8; TAG_LEN];
#[inline]
fn encrypt(
&self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
input: &mut [u8],
tag: &mut [u8; TAG_LEN],
) -> aead::Result {
unsafe {
debug_assert!(Avx2::is_supported());
self.encrypt_impl(nonce, aad, input, tag)
}
}
#[inline]
fn decrypt(
&self,
nonce: &[u8; NONCE_LEN],
aad: &[u8],
input: &mut [u8],
tag: &[u8; TAG_LEN],
) -> aead::Result {
unsafe {
debug_assert!(Avx2::is_supported());
self.decrypt_impl(nonce, aad, input, tag)
}
}
}
}
};
}
aesgcm!(aes128_gcm, aes128);
aesgcm!(aes256_gcm, aes256);
pub use super::ring::chacha20_poly1305;