shadow_crypt_core/v1/
crypt.rs

1use chacha20poly1305::{KeyInit, XChaCha20Poly1305, aead::Aead};
2
3use crate::{algorithm::Algorithm, errors::CryptError, memory::SecureBytes};
4
5pub fn encrypt_bytes(
6    plaintext: &[u8],
7    key: &[u8; 32],
8    nonce: &[u8; 24],
9) -> Result<(Vec<u8>, Algorithm), CryptError> {
10    let cipher = XChaCha20Poly1305::new(key.into());
11    let ciphertext = cipher
12        .encrypt(nonce.into(), plaintext)
13        .map_err(|e| CryptError::EncryptionError(format!("Encryption failed: {}", e)))?;
14
15    Ok((ciphertext, Algorithm::XChaCha20Poly1305))
16}
17
18/// Decrypts the given ciphertext into an insecure byte vector.
19pub fn decrypt_bytes(
20    ciphertext: &[u8],
21    key: &[u8; 32],
22    nonce: &[u8; 24],
23) -> Result<(SecureBytes, Algorithm), CryptError> {
24    let cipher = XChaCha20Poly1305::new(key.into());
25    let plaintext = cipher
26        .decrypt(nonce.into(), ciphertext)
27        .map_err(|e| CryptError::DecryptionError(format!("Decryption failed: {}", e)))?;
28
29    Ok((SecureBytes::new(plaintext), Algorithm::XChaCha20Poly1305))
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    #[test]
37    fn test_encrypt_decrypt_round_trip() {
38        let plaintext = b"Hello, world!";
39        let key = [0u8; 32];
40        let nonce = [0u8; 24];
41
42        let (ciphertext, algorithm) = encrypt_bytes(plaintext, &key, &nonce).unwrap();
43        assert_eq!(algorithm, Algorithm::XChaCha20Poly1305);
44        assert_ne!(ciphertext, plaintext);
45
46        let (decrypted, algorithm) = decrypt_bytes(&ciphertext, &key, &nonce).unwrap();
47        assert_eq!(algorithm, Algorithm::XChaCha20Poly1305);
48        assert_eq!(decrypted.as_slice(), plaintext);
49    }
50
51    #[test]
52    fn test_encrypt_different_nonce_produces_different_ciphertext() {
53        let plaintext = b"Test message";
54        let key = [1u8; 32];
55        let nonce1 = [0u8; 24];
56        let nonce2 = [1u8; 24];
57
58        let (ciphertext1, _) = encrypt_bytes(plaintext, &key, &nonce1).unwrap();
59        let (ciphertext2, _) = encrypt_bytes(plaintext, &key, &nonce2).unwrap();
60
61        assert_ne!(ciphertext1, ciphertext2);
62    }
63
64    #[test]
65    fn test_encrypt_same_inputs_produce_same_output() {
66        let plaintext = b"Deterministic test";
67        let key = [2u8; 32];
68        let nonce = [2u8; 24];
69
70        let (ciphertext1, _) = encrypt_bytes(plaintext, &key, &nonce).unwrap();
71        let (ciphertext2, _) = encrypt_bytes(plaintext, &key, &nonce).unwrap();
72
73        assert_eq!(ciphertext1, ciphertext2);
74    }
75
76    #[test]
77    fn test_decrypt_with_wrong_key_fails() {
78        let plaintext = b"Secret message";
79        let key = [3u8; 32];
80        let wrong_key = [4u8; 32];
81        let nonce = [3u8; 24];
82
83        let (ciphertext, _) = encrypt_bytes(plaintext, &key, &nonce).unwrap();
84        let result = decrypt_bytes(&ciphertext, &wrong_key, &nonce);
85
86        assert!(result.is_err());
87    }
88
89    #[test]
90    fn test_decrypt_with_wrong_nonce_fails() {
91        let plaintext = b"Secret message";
92        let key = [5u8; 32];
93        let nonce = [5u8; 24];
94        let wrong_nonce = [6u8; 24];
95
96        let (ciphertext, _) = encrypt_bytes(plaintext, &key, &nonce).unwrap();
97        let result = decrypt_bytes(&ciphertext, &key, &wrong_nonce);
98
99        assert!(result.is_err());
100    }
101
102    #[test]
103    fn test_encrypt_empty_plaintext() {
104        let plaintext = b"";
105        let key = [7u8; 32];
106        let nonce = [7u8; 24];
107
108        let (ciphertext, algorithm) = encrypt_bytes(plaintext, &key, &nonce).unwrap();
109        assert_eq!(algorithm, Algorithm::XChaCha20Poly1305);
110
111        let (decrypted, algorithm) = decrypt_bytes(&ciphertext, &key, &nonce).unwrap();
112        assert_eq!(algorithm, Algorithm::XChaCha20Poly1305);
113        assert_eq!(decrypted.as_slice(), plaintext);
114    }
115}