workflow_encryption/
chacha20poly1305.rs

1use crate::error::Error;
2use crate::imports::*;
3use chacha20poly1305::{
4    aead::{AeadCore, AeadInPlace, KeyInit, OsRng},
5    Key, XChaCha20Poly1305,
6};
7
8/// Encrypts the given data using `XChaCha20Poly1305` algorithm.
9pub fn encrypt<T>(data: &T, secret: &Secret) -> Result<Vec<u8>>
10where
11    T: Serializer,
12{
13    let mut buffer = vec![];
14    data.serialize(&mut buffer)?;
15    encrypt_slice(&buffer, secret)
16}
17
18pub fn encrypt_slice(data: &[u8], secret: &Secret) -> Result<Vec<u8>> {
19    let private_key_bytes = argon2_sha256(secret.as_ref(), 32)?;
20    let key = Key::from_slice(private_key_bytes.as_ref());
21    let cipher = XChaCha20Poly1305::new(key);
22    let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng); // 96-bits; unique per message
23    let mut buffer = data.to_vec();
24    buffer.reserve(24);
25    cipher.encrypt_in_place(&nonce, &[], &mut buffer)?;
26    buffer.extend(nonce.iter().cloned());
27    Ok(buffer)
28}
29
30pub fn decrypt<T>(data: &[u8], secret: &Secret) -> Result<T>
31where
32    T: Deserializer,
33{
34    let data = decrypt_slice(data, secret)?;
35    Ok(T::try_from_slice(data.as_slice())?)
36}
37
38/// Decrypts the given data using `XChaCha20Poly1305` algorithm.
39pub fn decrypt_slice(data: &[u8], secret: &Secret) -> Result<Secret> {
40    if data.len() < 24 {
41        return Err(Error::DecryptionDataLength);
42    }
43    let private_key_bytes = argon2_sha256(secret.as_ref(), 32)?;
44    let key = Key::from_slice(private_key_bytes.as_ref());
45    let cipher = XChaCha20Poly1305::new(key);
46    let len = data.len() - 24;
47    let nonce = &data[len..];
48    let mut buffer = data[..len].to_vec();
49    cipher.decrypt_in_place(nonce.into(), &[], &mut buffer)?;
50    Ok(Secret::new(buffer))
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_encrypt_decrypt() -> Result<()> {
59        use crate::imports::*;
60
61        println!("testing encrypt/decrypt");
62
63        let password = b"password";
64        let original = b"hello world".to_vec();
65        // println!("original: {}", original.to_hex());
66        let password = Secret::new(password.to_vec());
67        let encrypted = encrypt_slice(&original, &password).unwrap();
68        // println!("encrypted: {}", encrypted.to_hex());
69        let decrypted = decrypt_slice(&encrypted, &password).unwrap();
70        // println!("decrypted: {}", decrypted.to_hex());
71        assert_eq!(decrypted.as_ref(), original);
72
73        Ok(())
74    }
75}