include_crypt_bytes_cipher/
lib.rs

1use argon2::Config;
2use chacha20poly1305::{
3    aead::{Aead, KeyInit, OsRng},
4    ChaCha20Poly1305, Nonce, Error as CipherError,
5};
6use rand::RngCore;
7use crypto_common::InvalidLength;
8
9#[derive(thiserror::Error, Debug)]
10pub enum CryptError {
11    #[error("Hashing Failed: {0}")]
12    HashError(#[from] argon2::Error),
13    #[error("Cipher Failed: {0}")]
14    CipherError(#[from] CipherError),
15    #[error("Invalid length: {0}")]
16    InvalidLength(#[from] InvalidLength),
17}
18
19type Result<T> = core::result::Result<T, CryptError>;
20
21pub fn encrypt_bytes(bytes: &[u8], password: &[u8]) -> Result<(Vec<u8>, [u8; 12], [u8; 32])> {
22    // Generate random salt and nonce
23    let mut salt = [0u8; 32];
24    let mut nonce = [0u8; 12];
25    OsRng.fill_bytes(&mut salt);
26    OsRng.fill_bytes(&mut nonce);
27
28    // Hash password for key
29    let config = Config::default();
30    let key = argon2::hash_raw(password, &salt, &config)?;
31
32    // Encrypt
33    let nonce_array = Nonce::from_slice(&nonce);
34    let cipher = ChaCha20Poly1305::new_from_slice(&key)?;
35    let ciphertext = cipher.encrypt(nonce_array, bytes)?;
36
37    Ok((ciphertext, nonce, salt))
38}
39
40pub fn decrypt_bytes(
41    bytes: &[u8],
42    password: &[u8],
43    nonce: &[u8; 12],
44    salt: &[u8; 32],
45) -> Result<Vec<u8>> {
46    // Hash password for key
47    let config = Config::default();
48    let key = argon2::hash_raw(password, salt, &config)?;
49
50    // Decrypt
51    let cipher = ChaCha20Poly1305::new_from_slice(key.as_ref())?;
52    let nonce_array = Nonce::from_slice(nonce);
53
54    Ok(cipher.decrypt(nonce_array, bytes)?)
55}
56
57
58#[test]
59fn test_encrypt_decrypt() {
60    let mut message = [0u8; 256];
61    let mut password = [0u8; 64];
62    OsRng.fill_bytes(&mut message);
63    OsRng.fill_bytes(&mut password);
64    let (ciphertext, nonce, salt) = encrypt_bytes(&message, &password).unwrap();
65    let decrypted = decrypt_bytes(&ciphertext, &password, &nonce, &salt).unwrap();
66
67    assert_eq!(message, decrypted.as_ref())
68}
69
70#[test]
71fn test_encrypt_decrypt_err() {
72    let mut message = [0u8; 256];
73    let mut password = [0u8; 64];
74    let mut invalid_password = [0u8; 64];
75    OsRng.fill_bytes(&mut message);
76    OsRng.fill_bytes(&mut password);
77    OsRng.fill_bytes(&mut invalid_password);
78    let (ciphertext, nonce, salt) = encrypt_bytes(&message, &password).unwrap();
79    let decrypted = decrypt_bytes(&ciphertext, &invalid_password, &nonce, &salt);
80
81    assert!(decrypted.is_err());
82    assert_eq!(format!("{}", decrypted.err().unwrap()), "Cipher Failed: aead::Error");
83}
84
85#[test]
86fn test_encrypt_zero_length() {
87    let message: Vec<u8> = vec![];
88    let password: Vec<u8> = vec![];
89    let (ciphertext, nonce, salt) = encrypt_bytes(message.as_ref(), password.as_ref()).unwrap();
90    let decrypted: Vec<u8> = decrypt_bytes(&ciphertext, password.as_ref(), &nonce, &salt).unwrap();
91
92    assert_eq!(message, decrypted)
93}