sentinel_crypto/encrypt/
xchacha20_poly1305.rs1use chacha20poly1305::{
2 aead::{Aead, KeyInit},
3 Key,
4 XChaCha20Poly1305,
5 XNonce,
6};
7use rand::RngCore;
8use tracing::{debug, trace};
9
10use crate::{encrypt_trait::EncryptionAlgorithm, error::CryptoError};
11
12pub struct XChaCha20Poly1305Encryptor;
21
22impl EncryptionAlgorithm for XChaCha20Poly1305Encryptor {
23 fn encrypt_data(data: &[u8], key: &[u8; 32]) -> Result<String, CryptoError> {
24 trace!(
25 "Encrypting data with XChaCha20Poly1305, data length: {}",
26 data.len()
27 );
28 let cipher = XChaCha20Poly1305::new(Key::from_slice(key));
29 let mut nonce_bytes = [0u8; 24]; rand::rng().fill_bytes(&mut nonce_bytes);
31 let nonce = XNonce::from_slice(&nonce_bytes);
32
33 let ciphertext = cipher
34 .encrypt(nonce, data)
35 .map_err(|_| CryptoError::Encryption)?;
36 let mut result = nonce_bytes.to_vec();
37 result.extend_from_slice(&ciphertext);
38 let encrypted_hex = hex::encode(result);
39 debug!(
40 "XChaCha20Poly1305 encryption completed, encrypted length: {}",
41 encrypted_hex.len()
42 );
43 Ok(encrypted_hex)
44 }
45
46 fn decrypt_data(encrypted_data: &str, key: &[u8; 32]) -> Result<Vec<u8>, CryptoError> {
47 trace!(
48 "Decrypting data with XChaCha20Poly1305, encrypted length: {}",
49 encrypted_data.len()
50 );
51 let data = hex::decode(encrypted_data).map_err(|_| CryptoError::Decryption)?;
52 if data.len() < 40 {
53 debug!("Encrypted data too short: {} bytes", data.len());
55 return Err(CryptoError::Decryption);
56 }
57 let (nonce_bytes, ciphertext) = data.split_at(24);
58 let cipher = XChaCha20Poly1305::new(Key::from_slice(key));
59 let nonce = XNonce::from_slice(nonce_bytes);
60 let plaintext = cipher
61 .decrypt(nonce, ciphertext)
62 .map_err(|_| CryptoError::Decryption)?;
63 debug!(
64 "XChaCha20Poly1305 decryption completed, plaintext length: {}",
65 plaintext.len()
66 );
67 Ok(plaintext)
68 }
69}
70
71impl crate::encrypt_trait::private::Sealed for XChaCha20Poly1305Encryptor {}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_encrypt_decrypt() {
79 let key = [0u8; 32];
80 let data = b"Hello, world!";
81 let encrypted = XChaCha20Poly1305Encryptor::encrypt_data(data, &key).unwrap();
82 let decrypted = XChaCha20Poly1305Encryptor::decrypt_data(&encrypted, &key).unwrap();
83 assert_eq!(decrypted, data);
84 }
85
86 #[test]
87 fn test_decrypt_invalid_hex() {
88 let key = [0u8; 32];
89 let result = XChaCha20Poly1305Encryptor::decrypt_data("invalid_hex", &key);
90 assert!(result.is_err());
91 }
92}