#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
use crate::{MResult, ServerError};
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
use crate::{CResult, CliError};
#[derive(Clone)]
pub struct CipherKey {
inner: InnerCipherKey,
}
#[non_exhaustive]
#[derive(Clone)]
enum InnerCipherKey {
Chacha20Poly1305([u8; 32]),
}
impl InnerCipherKey {
fn encrypt(&self, message: &impl serde::Serialize) -> MResult<(Vec<u8>, Vec<u8>)> {
#[allow(unreachable_patterns)]
match self {
Self::Chacha20Poly1305(key) => {
use chacha20poly1305::{
ChaCha20Poly1305,
aead::{Aead, AeadCore, KeyInit, OsRng, generic_array::GenericArray},
consts::U32,
};
let serialized = rmp_serde::to_vec(message).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize data to encrypt!")
.with_500()
})?;
let key = GenericArray::<u8, U32>::from_slice(key);
let cipher = ChaCha20Poly1305::new(key);
let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
let ciphertext = cipher.encrypt(&nonce, serialized.as_ref()).map_err(|e| {
ServerError::from_private_str(e.to_string())
.with_private_str("Can't encrypt given data!")
.with_500()
})?;
Ok((ciphertext, nonce.to_vec()))
}
_ => unreachable!(),
}
}
fn decrypt<T: serde::de::DeserializeOwned>(&self, ciphertext: &[u8], nonce: &[u8]) -> MResult<T> {
#[allow(unreachable_patterns)]
match self {
Self::Chacha20Poly1305(key) => {
use chacha20poly1305::{
ChaCha20Poly1305,
aead::{Aead, KeyInit, generic_array::GenericArray},
consts::{U12, U32},
};
let key = GenericArray::<u8, U32>::from_slice(key);
let cipher = ChaCha20Poly1305::new(key);
let nonce = GenericArray::<u8, U12>::from_slice(nonce);
let plaintext = cipher.decrypt(nonce, ciphertext).map_err(|e| {
ServerError::from_private_str(e.to_string())
.with_private_str("Can't decrypt given ciphertext!")
.with_500()
})?;
let deserialized = rmp_serde::from_slice::<T>(plaintext.as_slice()).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize decrypted data!")
.with_500()
})?;
Ok(deserialized)
}
_ => unreachable!(),
}
}
fn pack(&self) -> Vec<u8> {
#[allow(unreachable_patterns)]
match self {
Self::Chacha20Poly1305(key) => {
let mut packed = b"chacha20poly1305::".to_vec();
packed.extend_from_slice(key);
packed
}
_ => unreachable!(),
}
}
fn unpack(key: impl AsRef<[u8]>) -> MResult<Self> {
if key.as_ref().starts_with(b"chacha20poly1305::") {
use std::mem::MaybeUninit;
let key = &key.as_ref()[b"chacha20poly1305::".len()..];
if key.len() != 32 {
return Err(ServerError::from_private_str("Invalid encryption key length!").with_500());
}
let buffer: [MaybeUninit<u8>; 32] = unsafe { MaybeUninit::uninit().assume_init() };
let mut buffer = unsafe { std::mem::transmute::<[MaybeUninit<u8>; 32], [u8; 32]>(buffer) };
buffer.copy_from_slice(key);
return Ok(Self::Chacha20Poly1305(buffer));
}
Err(ServerError::from_private_str("Invalid packed key format!").with_500())
}
}
impl CipherKey {
pub fn new_chacha20poly1305() -> Self {
use rand::Rng;
let mut arr: [u8; 32] = [0; 32];
let mut rng = rand::rng();
rng.fill(arr.as_mut_slice());
Self {
inner: InnerCipherKey::Chacha20Poly1305(arr),
}
}
pub fn encrypt(&self, message: &impl serde::Serialize) -> MResult<(Vec<u8>, Vec<u8>)> {
self.inner.encrypt(message)
}
pub fn decrypt<T: serde::de::DeserializeOwned>(&self, ciphertext: &[u8], nonce: &[u8]) -> MResult<T> {
self.inner.decrypt(ciphertext, nonce)
}
pub fn pack(&self) -> Vec<u8> {
self.inner.pack()
}
pub fn unpack(key: impl AsRef<[u8]>) -> MResult<Self> {
Ok(CipherKey {
inner: InnerCipherKey::unpack(key)?,
})
}
}