use aead::{generic_array::GenericArray, Aead, AeadCore, Key, KeyInit, KeySizeUser, OsRng};
use secrecy::{ExposeSecret, Secret, SecretVec, Zeroize};
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
use crate::serialization::{decode::Decoder, encode::Encoder};
#[derive(Debug, Serialize, Deserialize)]
pub struct Encrypted<Data> {
nonce: Vec<u8>,
data: Vec<u8>,
#[serde(skip)]
phantom: PhantomData<Data>,
}
#[derive(Deserialize)]
pub struct Decrypted<Data> {
data: SecretVec<u8>,
#[serde(skip)]
phantom: PhantomData<Data>,
}
#[derive(Debug, Deserialize)]
pub struct DecryptedExposed<Data> {
data: Vec<u8>,
#[serde(skip)]
phantom: PhantomData<Data>,
}
type GenericErr = Box<(dyn std::error::Error)>;
pub trait Encryption {
type Cipher: Aead + AeadCore + KeyInit + KeySizeUser;
type Scheme: Encoder + Decoder;
fn encode<Data>(data: &Encrypted<Data>) -> Result<Vec<u8>, GenericErr> {
Self::Scheme::encode(data)
}
fn decode<Data>(data: &[u8]) -> Result<Encrypted<Data>, Box<(dyn std::error::Error)>> {
Self::Scheme::decode(data)
}
fn extract<'de, Data: Deserialize<'de> + Zeroize>(
decrypted: &'de Decrypted<Data>,
) -> Result<Secret<Data>, Box<(dyn std::error::Error)>> {
Self::Scheme::decode(decrypted.data.expose_secret()).map(|x| Secret::new(x))
}
fn extract_exposed<'de, Data: Deserialize<'de>>(
decrypted: &'de DecryptedExposed<Data>,
) -> Result<Data, Box<(dyn std::error::Error)>> {
Self::Scheme::decode(&decrypted.data)
}
fn encrypt<Data: Serialize>(
data: &Data,
key: &Key<Self::Cipher>,
) -> Result<Encrypted<Data>, GenericErr> {
let cipher = Self::Cipher::new(key);
let nonce = Self::Cipher::generate_nonce(&mut OsRng);
let serialized = Self::Scheme::encode(data)?;
let encrypted = cipher.encrypt(&nonce, serialized.as_ref())?;
Ok(Encrypted {
nonce: nonce.to_vec(),
data: encrypted,
phantom: PhantomData,
})
}
fn decrypt<Data>(
encrypted: &Encrypted<Data>,
key: &GenericArray<u8, <Self::Cipher as KeySizeUser>::KeySize>,
) -> Result<Decrypted<Data>, GenericErr> {
let cipher = Self::Cipher::new(key);
let data = cipher.decrypt(
GenericArray::from_slice(encrypted.nonce.as_ref()),
encrypted.data.as_ref(),
)?;
Ok(Decrypted {
data: data.into(),
phantom: PhantomData,
})
}
fn decrypt_exposed<Data>(
encrypted: &Encrypted<Data>,
key: &GenericArray<u8, <Self::Cipher as KeySizeUser>::KeySize>,
) -> Result<DecryptedExposed<Data>, GenericErr> {
let cipher = Self::Cipher::new(key);
let data = cipher.decrypt(
GenericArray::from_slice(encrypted.nonce.as_ref()),
encrypted.data.as_ref(),
)?;
Ok(DecryptedExposed {
data,
phantom: PhantomData,
})
}
}