shadow_crypt_core/v3/
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(|_| {
54 CryptError::DecryptionError(
55 "authentication failed (wrong password, or the file is corrupted)".to_string(),
56 )
57 })?;
58
59 Ok((SecureBytes::new(plaintext), Algorithm::XChaCha20Poly1305))
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_encrypt_decrypt_round_trip() {
68 let plaintext = b"Hello, world!";
69 let key = [0u8; 32];
70 let nonce = [0u8; 24];
71 let aad = b"header binding";
72
73 let (ciphertext, algorithm) = encrypt_bytes(plaintext, &key, &nonce, aad).unwrap();
74 assert_eq!(algorithm, Algorithm::XChaCha20Poly1305);
75 assert_ne!(ciphertext, plaintext);
76
77 let (decrypted, _) = decrypt_bytes(&ciphertext, &key, &nonce, aad).unwrap();
78 assert_eq!(decrypted.as_slice(), plaintext);
79 }
80
81 #[test]
82 fn test_decrypt_with_wrong_aad_fails() {
83 let plaintext = b"Secret message";
84 let key = [1u8; 32];
85 let nonce = [1u8; 24];
86
87 let (ciphertext, _) = encrypt_bytes(plaintext, &key, &nonce, b"aad one").unwrap();
88 let result = decrypt_bytes(&ciphertext, &key, &nonce, b"aad two");
89
90 assert!(result.is_err());
91 }
92
93 #[test]
94 fn test_decrypt_with_wrong_key_fails() {
95 let plaintext = b"Secret message";
96 let key = [3u8; 32];
97 let wrong_key = [4u8; 32];
98 let nonce = [3u8; 24];
99 let aad = b"aad";
100
101 let (ciphertext, _) = encrypt_bytes(plaintext, &key, &nonce, aad).unwrap();
102 assert!(decrypt_bytes(&ciphertext, &wrong_key, &nonce, aad).is_err());
103 }
104
105 #[test]
106 fn test_decrypt_with_wrong_nonce_fails() {
107 let plaintext = b"Secret message";
108 let key = [5u8; 32];
109 let nonce = [5u8; 24];
110 let wrong_nonce = [6u8; 24];
111 let aad = b"aad";
112
113 let (ciphertext, _) = encrypt_bytes(plaintext, &key, &nonce, aad).unwrap();
114 assert!(decrypt_bytes(&ciphertext, &key, &wrong_nonce, aad).is_err());
115 }
116
117 #[test]
118 fn test_encrypt_empty_plaintext_and_empty_aad() {
119 let plaintext = b"";
120 let key = [7u8; 32];
121 let nonce = [7u8; 24];
122 let aad = b"";
123
124 let (ciphertext, _) = encrypt_bytes(plaintext, &key, &nonce, aad).unwrap();
125 let (decrypted, _) = decrypt_bytes(&ciphertext, &key, &nonce, aad).unwrap();
126 assert_eq!(decrypted.as_slice(), plaintext);
127 }
128}