use core::cell::UnsafeCell;
use core::ffi::c_void;
use aead_trait::generic_array::GenericArray;
use aead_trait::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
use typenum::{U0, U12, U16, U32};
use crate::error::len_as_u32;
pub use aead_trait;
#[cfg(wolfssl_aes_gcm)]
macro_rules! impl_aes_gcm {
($name:ident, $key_size:ty, $key_len:expr, $doc:expr) => {
#[doc = $doc]
pub struct $name {
// SAFETY: UnsafeCell is needed because wc_AesGcmEncrypt may mutate
aes: UnsafeCell<wolfcrypt_rs::WcAes>,
}
unsafe impl Send for $name {}
impl KeySizeUser for $name {
type KeySize = $key_size;
}
impl KeyInit for $name {
fn new(key: &GenericArray<u8, $key_size>) -> Self {
let mut aes = wolfcrypt_rs::WcAes::zeroed();
let rc = unsafe {
wolfcrypt_rs::wc_AesInit(
&mut aes as *mut wolfcrypt_rs::WcAes,
core::ptr::null_mut::<c_void>(),
wolfcrypt_rs::INVALID_DEVID,
)
};
assert_eq!(rc, 0, "wc_AesInit failed (OOM or invalid device)");
let rc = unsafe {
wolfcrypt_rs::wc_AesGcmSetKey(
&mut aes as *mut wolfcrypt_rs::WcAes,
key.as_ptr(),
$key_len,
)
};
assert_eq!(rc, 0, "wc_AesGcmSetKey failed (invalid key length)");
Self {
aes: UnsafeCell::new(aes),
}
}
}
impl AeadCore for $name {
type NonceSize = U12;
type TagSize = U16;
type CiphertextOverhead = U0;
}
impl AeadInPlace for $name {
fn encrypt_in_place_detached(
&self,
nonce: &aead_trait::Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
) -> aead_trait::Result<aead_trait::Tag<Self>> {
let mut tag = GenericArray::<u8, U16>::default();
let aad_ptr = if associated_data.is_empty() {
core::ptr::null()
} else {
associated_data.as_ptr()
};
let (in_ptr, out_ptr) = if buffer.is_empty() {
(core::ptr::null(), core::ptr::null_mut())
} else {
(buffer.as_ptr(), buffer.as_mut_ptr())
};
let rc = unsafe {
wolfcrypt_rs::wc_AesGcmEncrypt(
self.aes.get(),
out_ptr,
in_ptr,
len_as_u32(buffer.len()),
nonce.as_ptr(),
12,
tag.as_mut_ptr(),
16,
aad_ptr,
len_as_u32(associated_data.len()),
)
};
if rc == 0 {
Ok(tag)
} else {
Err(aead_trait::Error)
}
}
fn decrypt_in_place_detached(
&self,
nonce: &aead_trait::Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
tag: &aead_trait::Tag<Self>,
) -> aead_trait::Result<()> {
let aad_ptr = if associated_data.is_empty() {
core::ptr::null()
} else {
associated_data.as_ptr()
};
let (in_ptr, out_ptr) = if buffer.is_empty() {
(core::ptr::null(), core::ptr::null_mut())
} else {
(buffer.as_ptr(), buffer.as_mut_ptr())
};
let rc = unsafe {
wolfcrypt_rs::wc_AesGcmDecrypt(
self.aes.get(),
out_ptr,
in_ptr,
len_as_u32(buffer.len()),
nonce.as_ptr(),
12,
tag.as_ptr(),
16,
aad_ptr,
len_as_u32(associated_data.len()),
)
};
if rc == 0 {
Ok(())
} else {
zeroize::Zeroize::zeroize(buffer);
Err(aead_trait::Error)
}
}
}
impl Drop for $name {
fn drop(&mut self) {
unsafe {
wolfcrypt_rs::wc_AesFree(self.aes.get_mut());
}
}
}
};
}
#[cfg(wolfssl_aes_gcm)]
impl_aes_gcm!(
Aes128Gcm,
typenum::U16,
16,
"AES-128-GCM AEAD cipher, implementing `AeadInPlace` and `KeyInit`."
);
#[cfg(all(wolfssl_aes_gcm, wolfssl_aes_192))]
impl_aes_gcm!(
Aes192Gcm,
typenum::U24,
24,
"AES-192-GCM AEAD cipher, implementing `AeadInPlace` and `KeyInit`."
);
#[cfg(wolfssl_aes_gcm)]
impl_aes_gcm!(
Aes256Gcm,
U32,
32,
"AES-256-GCM AEAD cipher, implementing `AeadInPlace` and `KeyInit`."
);
#[cfg(wolfssl_chacha20_poly1305)]
pub struct ChaCha20Poly1305 {
key: [u8; 32],
}
#[cfg(wolfssl_chacha20_poly1305)]
unsafe impl Send for ChaCha20Poly1305 {}
#[cfg(wolfssl_chacha20_poly1305)]
unsafe impl Sync for ChaCha20Poly1305 {}
#[cfg(wolfssl_chacha20_poly1305)]
impl Drop for ChaCha20Poly1305 {
fn drop(&mut self) {
use zeroize::Zeroize;
self.key.zeroize();
}
}
#[cfg(wolfssl_chacha20_poly1305)]
impl KeySizeUser for ChaCha20Poly1305 {
type KeySize = U32;
}
#[cfg(wolfssl_chacha20_poly1305)]
impl KeyInit for ChaCha20Poly1305 {
fn new(key: &GenericArray<u8, U32>) -> Self {
let mut k = [0u8; 32];
k.copy_from_slice(key.as_slice());
Self { key: k }
}
}
#[cfg(wolfssl_chacha20_poly1305)]
impl AeadCore for ChaCha20Poly1305 {
type NonceSize = U12;
type TagSize = U16;
type CiphertextOverhead = U0;
}
#[cfg(wolfssl_chacha20_poly1305)]
impl AeadInPlace for ChaCha20Poly1305 {
fn encrypt_in_place_detached(
&self,
nonce: &aead_trait::Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
) -> aead_trait::Result<aead_trait::Tag<Self>> {
let mut tag = GenericArray::<u8, U16>::default();
let mut aead = wolfcrypt_rs::ChaChaPoly_Aead::zeroed();
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_Init(
&mut aead,
self.key.as_ptr(),
nonce.as_ptr(),
1, )
};
if rc != 0 {
return Err(aead_trait::Error);
}
if !associated_data.is_empty() {
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_UpdateAad(
&mut aead,
associated_data.as_ptr(),
len_as_u32(associated_data.len()),
)
};
if rc != 0 {
return Err(aead_trait::Error);
}
}
{
let (in_ptr, out_ptr) = if buffer.is_empty() {
let sentinel: *const u8 = &0u8;
(sentinel, sentinel as *mut u8)
} else {
(buffer.as_ptr(), buffer.as_mut_ptr())
};
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_UpdateData(
&mut aead,
in_ptr,
out_ptr,
len_as_u32(buffer.len()),
)
};
if rc != 0 {
return Err(aead_trait::Error);
}
}
let rc = unsafe { wolfcrypt_rs::wc_ChaCha20Poly1305_Final(&mut aead, tag.as_mut_ptr()) };
if rc != 0 {
return Err(aead_trait::Error);
}
Ok(tag)
}
fn decrypt_in_place_detached(
&self,
nonce: &aead_trait::Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
tag: &aead_trait::Tag<Self>,
) -> aead_trait::Result<()> {
let mut aead = wolfcrypt_rs::ChaChaPoly_Aead::zeroed();
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_Init(
&mut aead,
self.key.as_ptr(),
nonce.as_ptr(),
0, )
};
if rc != 0 {
return Err(aead_trait::Error);
}
if !associated_data.is_empty() {
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_UpdateAad(
&mut aead,
associated_data.as_ptr(),
len_as_u32(associated_data.len()),
)
};
if rc != 0 {
return Err(aead_trait::Error);
}
}
{
let (in_ptr, out_ptr) = if buffer.is_empty() {
let sentinel: *const u8 = &0u8;
(sentinel, sentinel as *mut u8)
} else {
(buffer.as_ptr(), buffer.as_mut_ptr())
};
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_UpdateData(
&mut aead,
in_ptr,
out_ptr,
len_as_u32(buffer.len()),
)
};
if rc != 0 {
return Err(aead_trait::Error);
}
}
let mut computed_tag = [0u8; 16];
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_Final(&mut aead, computed_tag.as_mut_ptr())
};
if rc != 0 {
zeroize::Zeroize::zeroize(buffer);
return Err(aead_trait::Error);
}
let rc = unsafe {
wolfcrypt_rs::wc_ChaCha20Poly1305_CheckTag(computed_tag.as_ptr(), tag.as_ptr())
};
if rc != 0 {
zeroize::Zeroize::zeroize(buffer);
return Err(aead_trait::Error);
}
Ok(())
}
}