use chacha20poly1305::aead::{Aead, NewAead};
use litl::{serde::DeserializeError, Litl, impl_debug_as_litl};
use rand07::{rngs::OsRng, RngCore};
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
use std::{fmt::Debug, marker::PhantomData, ops::Deref};
use thiserror::Error;
use zeroize::Zeroizing;
#[derive(Serialize, Deserialize)]
#[serde(rename = "Conundrum/EncrKey:Chacha20Poly1305")]
pub struct RawEncrKeyChacha20Poly1305(chacha20poly1305::Key);
use crate::serde_bytes_array;
#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct EncrKeyID(
#[serde(with = "serde_bytes_array")]
[u8; 16]
);
impl_debug_as_litl!(EncrKeyID);
#[derive(Serialize, Deserialize)]
pub struct RawEncrKey {
pub id: EncrKeyID,
key: RawEncrKeyChacha20Poly1305,
}
impl RawEncrKey {
pub fn new_random() -> Self {
let mut key = [0u8; 32];
OsRng {}.fill_bytes(&mut key);
let mut id = [0u8; 16];
OsRng {}.fill_bytes(&mut id);
RawEncrKey {
id: EncrKeyID(id),
key: RawEncrKeyChacha20Poly1305(*chacha20poly1305::Key::from_slice(&key)),
}
}
}
impl Deref for RawEncrKey {
type Target = chacha20poly1305::Key;
fn deref(&self) -> &Self::Target {
&self.key.0
}
}
impl Debug for RawEncrKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("(Secret RawEncrKey)")
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct EncrKey<S> {
key: RawEncrKey,
purpose: S,
}
impl<S: Default> EncrKey<S> {
pub fn new_random() -> Self {
EncrKey {
key: RawEncrKey::new_random(),
purpose: S::default(),
}
}
}
impl<S> Deref for EncrKey<S> {
type Target = RawEncrKey;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl<S: Clone> EncrKey<S> {
pub fn encrypt<T: Serialize>(&self, value: &T) -> Encrypted<T, S> {
let cipher = chacha20poly1305::ChaCha20Poly1305::new(self);
let mut nonce_bytes = [0; 12];
OsRng {}.fill_bytes(&mut nonce_bytes);
let nonce = chacha20poly1305::Nonce::from(nonce_bytes);
Encrypted {
encrypted: RawEncrypted {
encrypted: RawEncryptedChacha20Poly1305(RawEncryptedChacha20Poly1305Inner {
ciphertext: cipher
.encrypt(&nonce, Zeroizing::new(Litl::write_from(value)).as_slice())
.expect("Failed to encrypt"),
nonce: nonce_bytes,
}),
for_key: self.id,
},
purpose: self.purpose.clone(),
_marker: PhantomData,
}
}
pub fn decrypt<'de, T: Deserialize<'de>>(
self,
encrypted: &Encrypted<T, S>,
) -> Result<T, DecryptionError> {
let cipher = chacha20poly1305::ChaCha20Poly1305::new(&self);
let plaintext = cipher
.decrypt(
chacha20poly1305::Nonce::from_slice(&encrypted.encrypted.encrypted.0.nonce),
encrypted.encrypted.encrypted.0.ciphertext.as_slice(),
)
.map(Zeroizing::new)
.map_err(DecryptionError::DecryptionError)?;
Litl::read_as::<T>(&plaintext).map_err(DecryptionError::DeserializeError)
}
}
#[derive(Error, Debug)]
pub enum DecryptionError {
#[error("Decryption error.")]
DecryptionError(chacha20poly1305::aead::Error),
#[error("Error converting from decrypted bytes.")]
DeserializeError(DeserializeError),
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RawEncryptedChacha20Poly1305Inner {
#[serde(with = "serde_bytes")]
pub ciphertext: Vec<u8>,
pub nonce: [u8; 12],
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename = "Conundrum/Encrypted:Chacha20Poly1305")]
pub struct RawEncryptedChacha20Poly1305(RawEncryptedChacha20Poly1305Inner);
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RawEncrypted {
for_key: EncrKeyID,
encrypted: RawEncryptedChacha20Poly1305,
}
#[derive(Serialize, Deserialize)]
pub struct Encrypted<T, S> {
encrypted: RawEncrypted,
purpose: S,
_marker: PhantomData<T>,
}
impl<T, S: Serialize> Debug for Encrypted<T, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Litl::from_se(self).fmt(f)
}
}
impl<T, S: Clone> Clone for Encrypted<T, S> {
fn clone(&self) -> Self {
Encrypted {
encrypted: self.encrypted.clone(),
purpose: self.purpose.clone(),
_marker: PhantomData,
}
}
}
impl <T, S: PartialEq> PartialEq for Encrypted<T, S> {
fn eq(&self, other: &Self) -> bool {
self.encrypted == other.encrypted && self.purpose == other.purpose
}
}
impl <T, S: Eq> Eq for Encrypted<T, S> {}