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