use crate::algorithms::aead::{AeadAlgorithm, AesKeySize};
use crate::error::Error;
#[cfg(feature = "xof")]
use crate::wrappers::xof::XofReaderWrapper;
use seal_crypto::prelude::{Key, SymmetricKeyGenerator, SymmetricKeySet};
use seal_crypto::schemes::aead::aes_gcm::{Aes128Gcm, Aes256Gcm};
use seal_crypto::schemes::aead::chacha20_poly1305::{ChaCha20Poly1305, XChaCha20Poly1305};
use seal_crypto::zeroize::Zeroizing;
#[cfg(feature = "kdf")]
use {
crate::algorithms::kdf::key::KdfKeyAlgorithm, crate::wrappers::kdf::passwd::KdfPasswordWrapper,
seal_crypto::secrecy::SecretBox,
};
macro_rules! dispatch_aead {
($algorithm:expr, $action:ident) => {
match $algorithm {
AeadAlgorithm::AesGcm(AesKeySize::K128) => {
$action!(Aes128Gcm, AeadAlgorithm::AesGcm(AesKeySize::K128))
}
AeadAlgorithm::AesGcm(AesKeySize::K256) => {
$action!(Aes256Gcm, AeadAlgorithm::AesGcm(AesKeySize::K256))
}
AeadAlgorithm::XChaCha20Poly1305 => {
$action!(XChaCha20Poly1305, AeadAlgorithm::XChaCha20Poly1305)
}
AeadAlgorithm::ChaCha20Poly1305 => {
$action!(ChaCha20Poly1305, AeadAlgorithm::ChaCha20Poly1305)
}
}
};
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, bincode::Encode, bincode::Decode)]
pub struct TypedAeadKey {
key: AeadKey,
algorithm: AeadAlgorithm,
}
impl TypedAeadKey {
pub fn generate(algorithm: AeadAlgorithm) -> Result<Self, Error> {
macro_rules! generate_key {
($key_type:ty, $alg_enum:expr) => {
<$key_type>::generate_key()
.map_err(Error::from)
.and_then(|k| {
Ok(Self {
key: AeadKey::new(k.to_bytes().map_err(Error::from)?),
algorithm: $alg_enum,
})
})
};
}
dispatch_aead!(algorithm, generate_key)
}
pub fn from_bytes(bytes: &[u8], algorithm: AeadAlgorithm) -> Result<Self, Error> {
let key = AeadKey::new(bytes.to_vec());
key.into_typed(algorithm)
}
#[cfg(feature = "kdf")]
pub fn derive_from_kdf(
bytes: &[u8],
kdf_algorithm: KdfKeyAlgorithm,
salt: Option<&[u8]>,
info: Option<&[u8]>,
symmetric_algorithm: AeadAlgorithm,
) -> Result<Self, Error> {
use crate::traits::KdfKeyAlgorithmTrait;
let derived_key_bytes = kdf_algorithm.into_wrapper().derive(
bytes,
salt,
info,
symmetric_algorithm.into_wrapper().key_size(),
)?;
Ok(TypedAeadKey::from_bytes(
derived_key_bytes.as_slice(),
symmetric_algorithm,
)?)
}
#[cfg(feature = "xof")]
pub fn derive_from_xof(
xof_reader: &mut XofReaderWrapper,
symmetric_algorithm: AeadAlgorithm,
) -> Result<Self, Error> {
let mut derived_key_bytes = vec![0u8; symmetric_algorithm.into_wrapper().key_size()];
xof_reader.read(&mut derived_key_bytes);
Ok(TypedAeadKey::from_bytes(
derived_key_bytes.as_slice(),
symmetric_algorithm,
)?)
}
#[cfg(feature = "kdf")]
pub fn derive_from_password(
password: &SecretBox<[u8]>,
algorithm: KdfPasswordWrapper,
salt: &[u8],
symmetric_algorithm: AeadAlgorithm,
) -> Result<Self, Error> {
use crate::traits::KdfPasswordAlgorithmTrait;
let derived_key_bytes = algorithm.derive(
password,
salt,
symmetric_algorithm.into_wrapper().key_size(),
)?;
Ok(TypedAeadKey::from_bytes(
derived_key_bytes.as_slice(),
symmetric_algorithm,
)?)
}
pub fn algorithm(&self) -> AeadAlgorithm {
self.algorithm
}
pub fn untyped(&self) -> AeadKey {
self.key.clone()
}
pub fn as_bytes(&self) -> &[u8] {
self.key.as_bytes()
}
pub fn into_bytes(self) -> Zeroizing<Vec<u8>> {
self.key.into_bytes()
}
pub fn to_bytes(&self) -> Vec<u8> {
self.key.to_bytes()
}
}
impl AsRef<[u8]> for TypedAeadKey {
fn as_ref(&self) -> &[u8] {
self.key.as_bytes()
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AeadKey(pub Zeroizing<Vec<u8>>);
impl bincode::Encode for AeadKey {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> core::result::Result<(), bincode::error::EncodeError> {
let bytes = self.0.as_slice();
bincode::Encode::encode(bytes, encoder)?;
Ok(())
}
}
impl<Context> bincode::Decode<Context> for AeadKey {
fn decode<D: bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> core::result::Result<Self, bincode::error::DecodeError> {
let bytes = bincode::Decode::decode(decoder)?;
Ok(Self(Zeroizing::new(bytes)))
}
}
impl<'de, Context> bincode::BorrowDecode<'de, Context> for AeadKey {
fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> core::result::Result<Self, bincode::error::DecodeError> {
let bytes = bincode::BorrowDecode::borrow_decode(decoder)?;
Ok(Self(Zeroizing::new(bytes)))
}
}
impl AeadKey {
pub fn new(bytes: impl Into<Zeroizing<Vec<u8>>>) -> Self {
Self(bytes.into())
}
pub fn generate(len: usize) -> Result<Self, Error> {
use rand::{TryRngCore, rngs::OsRng};
let mut key_bytes = vec![0; len];
OsRng.try_fill_bytes(&mut key_bytes)?;
Ok(Self::new(key_bytes))
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_vec()
}
pub fn into_bytes(self) -> Zeroizing<Vec<u8>> {
self.0
}
pub fn into_typed(self, algorithm: AeadAlgorithm) -> Result<TypedAeadKey, Error> {
macro_rules! into_typed_key {
($key_type:ty, $alg_enum:expr) => {{
let key = <$key_type as SymmetricKeySet>::Key::from_bytes(self.as_bytes())?;
Ok(TypedAeadKey {
key: AeadKey::new(key.to_bytes().map_err(Error::from)?),
algorithm: $alg_enum,
})
}};
}
dispatch_aead!(algorithm, into_typed_key)
}
}