prima_bridge 0.29.0

A library to implement the bridge pattern
Documentation
use chacha20poly1305::aead::{Aead, AeadCore, KeyInit, OsRng};
use chacha20poly1305::XChaCha20Poly1305;
use serde::{Deserialize, Serialize};

const NONCE_SIZE: usize = 24;

#[derive(thiserror::Error, Debug)]
pub enum CryptoError {
    #[error(transparent)]
    Serde(#[from] serde_json::Error),
    #[error(transparent)]
    ChaCha20Poly1305(#[from] chacha20poly1305::Error),
}

pub fn encrypt<T: Serialize>(value_ref: &T, token_encryption_key_str: &str) -> Result<Vec<u8>, CryptoError> {
    let json: String = serde_json::to_string(value_ref)?;

    let enc = XChaCha20Poly1305::new_from_slice(token_encryption_key_str.as_bytes()).unwrap();
    let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);

    let mut ciphertext = enc.encrypt(&nonce, json.as_bytes())?;
    ciphertext.extend(nonce);

    Ok(ciphertext)
}

pub fn decrypt<T>(token_encryption_key_str: &str, encrypted: &[u8]) -> Result<T, CryptoError>
where
    for<'de> T: Deserialize<'de>,
{
    let dec = XChaCha20Poly1305::new_from_slice(token_encryption_key_str.as_bytes()).unwrap();

    let ciphertext = encrypted.get(..encrypted.len() - NONCE_SIZE);
    let nonce = encrypted.get(encrypted.len() - NONCE_SIZE..);

    let (Some(ciphertext), Some(nonce)) = (ciphertext, nonce) else {
        return Err(CryptoError::ChaCha20Poly1305(chacha20poly1305::Error));
    };

    let nonce = chacha20poly1305::XNonce::from_slice(nonce);
    let plaintext = dec.decrypt(nonce, ciphertext)?;
    Ok(serde_json::from_slice(&plaintext)?)
}