1use aes_gcm::{
19 aead::{Aead, KeyInit, OsRng},
20 Aes256Gcm, Key, Nonce,
21};
22use argon2::{password_hash::rand_core::RngCore, Algorithm, Argon2, Params, Version};
23use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
24use chacha20poly1305::{ChaCha20Poly1305, Key as ChaChaKey, Nonce as ChaChaNonce};
25use parking_lot::RwLock;
26use serde::{Deserialize, Serialize};
27use std::collections::HashMap;
28use std::sync::Arc;
29use thiserror::Error;
30use zeroize::Zeroizing;
31
32#[derive(Debug, Error)]
34pub enum EncryptionError {
35 #[error("Encryption failed: {0}")]
36 EncryptionFailed(String),
37
38 #[error("Decryption failed: {0}")]
39 DecryptionFailed(String),
40
41 #[error("Key derivation failed: {0}")]
42 KeyDerivationFailed(String),
43
44 #[error("Invalid key length: expected {expected}, got {actual}")]
45 InvalidKeyLength { expected: usize, actual: usize },
46
47 #[error("Invalid nonce length: expected {expected}, got {actual}")]
48 InvalidNonceLength { expected: usize, actual: usize },
49
50 #[error("Key not found: {0}")]
51 KeyNotFound(String),
52
53 #[error("Invalid ciphertext format")]
54 InvalidCiphertextFormat,
55
56 #[error("Key rotation failed: {0}")]
57 KeyRotationFailed(String),
58}
59
60#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
62pub enum EncryptionAlgorithm {
63 #[default]
65 Aes256Gcm,
66 ChaCha20Poly1305,
68}
69
70impl std::fmt::Display for EncryptionAlgorithm {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 match self {
73 Self::Aes256Gcm => write!(f, "AES-256-GCM"),
74 Self::ChaCha20Poly1305 => write!(f, "ChaCha20-Poly1305"),
75 }
76 }
77}
78
79#[derive(Clone)]
81pub struct EncryptionKey {
82 key_data: Arc<Zeroizing<Vec<u8>>>,
84 algorithm: EncryptionAlgorithm,
86 key_id: String,
88 created_at: chrono::DateTime<chrono::Utc>,
90}
91
92impl EncryptionKey {
93 pub fn from_bytes(
95 key_bytes: &[u8],
96 algorithm: EncryptionAlgorithm,
97 ) -> Result<Self, EncryptionError> {
98 let expected_len = Self::key_length(algorithm);
99 if key_bytes.len() != expected_len {
100 return Err(EncryptionError::InvalidKeyLength {
101 expected: expected_len,
102 actual: key_bytes.len(),
103 });
104 }
105
106 Ok(Self {
107 key_data: Arc::new(Zeroizing::new(key_bytes.to_vec())),
108 algorithm,
109 key_id: generate_key_id(),
110 created_at: chrono::Utc::now(),
111 })
112 }
113
114 pub fn generate(algorithm: EncryptionAlgorithm) -> Result<Self, EncryptionError> {
116 let key_len = Self::key_length(algorithm);
117 let mut key_bytes = vec![0u8; key_len];
118 OsRng.fill_bytes(&mut key_bytes);
119
120 Self::from_bytes(&key_bytes, algorithm)
121 }
122
123 pub fn derive_from_password(
125 password: &str,
126 salt: &[u8],
127 algorithm: EncryptionAlgorithm,
128 ) -> Result<Self, EncryptionError> {
129 let key_len = Self::key_length(algorithm);
130 let params = Params::new(
131 Params::DEFAULT_M_COST,
132 Params::DEFAULT_T_COST,
133 Params::DEFAULT_P_COST,
134 Some(key_len),
135 )
136 .map_err(|e| EncryptionError::KeyDerivationFailed(e.to_string()))?;
137
138 let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
139 let mut key_bytes = vec![0u8; key_len];
140
141 argon2
142 .hash_password_into(password.as_bytes(), salt, &mut key_bytes)
143 .map_err(|e| EncryptionError::KeyDerivationFailed(e.to_string()))?;
144
145 Self::from_bytes(&key_bytes, algorithm)
146 }
147
148 pub fn key_length(algorithm: EncryptionAlgorithm) -> usize {
150 match algorithm {
151 EncryptionAlgorithm::Aes256Gcm => 32,
152 EncryptionAlgorithm::ChaCha20Poly1305 => 32,
153 }
154 }
155
156 pub fn nonce_length(algorithm: EncryptionAlgorithm) -> usize {
158 match algorithm {
159 EncryptionAlgorithm::Aes256Gcm => 12,
160 EncryptionAlgorithm::ChaCha20Poly1305 => 12,
161 }
162 }
163
164 pub fn as_bytes(&self) -> &[u8] {
166 &self.key_data
167 }
168
169 pub fn key_id(&self) -> &str {
171 &self.key_id
172 }
173
174 pub fn algorithm(&self) -> EncryptionAlgorithm {
176 self.algorithm
177 }
178
179 pub fn created_at(&self) -> chrono::DateTime<chrono::Utc> {
181 self.created_at
182 }
183}
184
185impl std::fmt::Debug for EncryptionKey {
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 f.debug_struct("EncryptionKey")
188 .field("key_id", &self.key_id)
189 .field("algorithm", &self.algorithm)
190 .field("created_at", &self.created_at)
191 .field("key_data", &"<redacted>")
192 .finish()
193 }
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct EncryptedData {
199 pub algorithm: EncryptionAlgorithm,
201 pub nonce: String,
203 pub ciphertext: String,
205 pub key_id: String,
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub associated_data: Option<String>,
210}
211
212impl EncryptedData {
213 pub fn to_string(&self) -> Result<String, EncryptionError> {
215 serde_json::to_string(self).map_err(|e| EncryptionError::EncryptionFailed(e.to_string()))
216 }
217
218 pub fn from_string(s: &str) -> Result<Self, EncryptionError> {
220 serde_json::from_str(s).map_err(|e| EncryptionError::DecryptionFailed(e.to_string()))
221 }
222}
223
224#[derive(Debug, Clone)]
226pub struct EncryptionConfig {
227 pub default_algorithm: EncryptionAlgorithm,
229 pub auto_key_rotation: bool,
231 pub key_validity_secs: u64,
233 pub max_keys: usize,
235}
236
237impl Default for EncryptionConfig {
238 fn default() -> Self {
239 Self {
240 default_algorithm: EncryptionAlgorithm::Aes256Gcm,
241 auto_key_rotation: false,
242 key_validity_secs: 86400 * 90, max_keys: 100,
244 }
245 }
246}
247
248pub struct EncryptionEngine {
250 keys: RwLock<HashMap<String, EncryptionKey>>,
252 default_key_id: RwLock<Option<String>>,
254 config: EncryptionConfig,
256}
257
258impl EncryptionEngine {
259 pub fn new() -> Self {
261 Self::with_config(EncryptionConfig::default())
262 }
263
264 pub fn with_config(config: EncryptionConfig) -> Self {
266 Self {
267 keys: RwLock::new(HashMap::new()),
268 default_key_id: RwLock::new(None),
269 config,
270 }
271 }
272
273 pub fn generate_key(&self) -> Result<String, EncryptionError> {
275 self.generate_key_with_algorithm(self.config.default_algorithm)
276 }
277
278 pub fn generate_key_with_algorithm(
280 &self,
281 algorithm: EncryptionAlgorithm,
282 ) -> Result<String, EncryptionError> {
283 let key = EncryptionKey::generate(algorithm)?;
284 let key_id = key.key_id().to_string();
285
286 let mut keys = self.keys.write();
288 if keys.len() >= self.config.max_keys {
289 if let Some((oldest_id, _)) = keys
291 .iter()
292 .min_by_key(|(_, k)| k.created_at())
293 .map(|(id, k)| (id.clone(), k.created_at()))
294 {
295 keys.remove(&oldest_id);
296 }
297 }
298
299 keys.insert(key_id.clone(), key);
300
301 *self.default_key_id.write() = Some(key_id.clone());
303
304 tracing::info!("Generated new encryption key: {}", key_id);
305 Ok(key_id)
306 }
307
308 pub fn derive_key_from_password(
310 &self,
311 password: &str,
312 salt: &[u8],
313 ) -> Result<String, EncryptionError> {
314 let key =
315 EncryptionKey::derive_from_password(password, salt, self.config.default_algorithm)?;
316 let key_id = key.key_id().to_string();
317
318 self.keys.write().insert(key_id.clone(), key);
319 *self.default_key_id.write() = Some(key_id.clone());
320
321 tracing::info!("Derived encryption key from password: {}", key_id);
322 Ok(key_id)
323 }
324
325 pub fn add_key(&self, key: EncryptionKey) -> Result<String, EncryptionError> {
327 let key_id = key.key_id().to_string();
328 self.keys.write().insert(key_id.clone(), key);
329 *self.default_key_id.write() = Some(key_id.clone());
330 Ok(key_id)
331 }
332
333 pub fn get_key(&self, key_id: &str) -> Result<EncryptionKey, EncryptionError> {
335 self.keys
336 .read()
337 .get(key_id)
338 .cloned()
339 .ok_or_else(|| EncryptionError::KeyNotFound(key_id.to_string()))
340 }
341
342 pub fn remove_key(&self, key_id: &str) -> Result<bool, EncryptionError> {
344 let removed = self.keys.write().remove(key_id).is_some();
345
346 if removed {
348 let mut default_id = self.default_key_id.write();
349 if default_id.as_deref() == Some(key_id) {
350 *default_id = None;
351 }
352 }
353
354 Ok(removed)
355 }
356
357 pub fn list_keys(&self) -> Vec<String> {
359 self.keys.read().keys().cloned().collect()
360 }
361
362 pub fn get_default_key(&self) -> Result<EncryptionKey, EncryptionError> {
364 let default_id = self
365 .default_key_id
366 .read()
367 .clone()
368 .ok_or_else(|| EncryptionError::KeyNotFound("default".to_string()))?;
369
370 self.get_key(&default_id)
371 }
372
373 pub fn set_default_key(&self, key_id: &str) -> Result<(), EncryptionError> {
375 if !self.keys.read().contains_key(key_id) {
376 return Err(EncryptionError::KeyNotFound(key_id.to_string()));
377 }
378
379 *self.default_key_id.write() = Some(key_id.to_string());
380 Ok(())
381 }
382
383 pub fn encrypt(&self, plaintext: &[u8]) -> Result<EncryptedData, EncryptionError> {
385 let key = self.get_default_key()?;
386 self.encrypt_with_key(&key, plaintext)
387 }
388
389 pub fn encrypt_with_key(
391 &self,
392 key: &EncryptionKey,
393 plaintext: &[u8],
394 ) -> Result<EncryptedData, EncryptionError> {
395 let nonce_len = EncryptionKey::nonce_length(key.algorithm);
397 let mut nonce_bytes = vec![0u8; nonce_len];
398 OsRng.fill_bytes(&mut nonce_bytes);
399
400 let ciphertext = match key.algorithm {
401 EncryptionAlgorithm::Aes256Gcm => {
402 let cipher_key = Key::<Aes256Gcm>::from_slice(key.as_bytes());
403 let cipher = Aes256Gcm::new(cipher_key);
404 let nonce = Nonce::from_slice(&nonce_bytes);
405
406 cipher
407 .encrypt(nonce, plaintext)
408 .map_err(|e| EncryptionError::EncryptionFailed(e.to_string()))?
409 }
410 EncryptionAlgorithm::ChaCha20Poly1305 => {
411 let cipher_key = ChaChaKey::from_slice(key.as_bytes());
412 let cipher = ChaCha20Poly1305::new(cipher_key);
413 let nonce = ChaChaNonce::from_slice(&nonce_bytes);
414
415 cipher
416 .encrypt(nonce, plaintext)
417 .map_err(|e| EncryptionError::EncryptionFailed(e.to_string()))?
418 }
419 };
420
421 Ok(EncryptedData {
422 algorithm: key.algorithm,
423 nonce: BASE64.encode(&nonce_bytes),
424 ciphertext: BASE64.encode(&ciphertext),
425 key_id: key.key_id().to_string(),
426 associated_data: None,
427 })
428 }
429
430 pub fn encrypt_string(&self, plaintext: &str) -> Result<EncryptedData, EncryptionError> {
432 self.encrypt(plaintext.as_bytes())
433 }
434
435 pub fn decrypt(&self, encrypted: &EncryptedData) -> Result<Vec<u8>, EncryptionError> {
437 let key = self.get_key(&encrypted.key_id)?;
438 self.decrypt_with_key(&key, encrypted)
439 }
440
441 pub fn decrypt_with_key(
443 &self,
444 key: &EncryptionKey,
445 encrypted: &EncryptedData,
446 ) -> Result<Vec<u8>, EncryptionError> {
447 let nonce_bytes = BASE64
449 .decode(&encrypted.nonce)
450 .map_err(|_| EncryptionError::InvalidCiphertextFormat)?;
451
452 let ciphertext = BASE64
453 .decode(&encrypted.ciphertext)
454 .map_err(|_| EncryptionError::InvalidCiphertextFormat)?;
455
456 let expected_nonce_len = EncryptionKey::nonce_length(key.algorithm);
458 if nonce_bytes.len() != expected_nonce_len {
459 return Err(EncryptionError::InvalidNonceLength {
460 expected: expected_nonce_len,
461 actual: nonce_bytes.len(),
462 });
463 }
464
465 let plaintext = match key.algorithm {
466 EncryptionAlgorithm::Aes256Gcm => {
467 let cipher_key = Key::<Aes256Gcm>::from_slice(key.as_bytes());
468 let cipher = Aes256Gcm::new(cipher_key);
469 let nonce = Nonce::from_slice(&nonce_bytes);
470
471 cipher
472 .decrypt(nonce, ciphertext.as_slice())
473 .map_err(|e| EncryptionError::DecryptionFailed(e.to_string()))?
474 }
475 EncryptionAlgorithm::ChaCha20Poly1305 => {
476 let cipher_key = ChaChaKey::from_slice(key.as_bytes());
477 let cipher = ChaCha20Poly1305::new(cipher_key);
478 let nonce = ChaChaNonce::from_slice(&nonce_bytes);
479
480 cipher
481 .decrypt(nonce, ciphertext.as_slice())
482 .map_err(|e| EncryptionError::DecryptionFailed(e.to_string()))?
483 }
484 };
485
486 Ok(plaintext)
487 }
488
489 pub fn decrypt_to_string(&self, encrypted: &EncryptedData) -> Result<String, EncryptionError> {
491 let plaintext = self.decrypt(encrypted)?;
492 String::from_utf8(plaintext).map_err(|e| EncryptionError::DecryptionFailed(e.to_string()))
493 }
494
495 pub fn rotate_key(&self, old_key_id: &str) -> Result<String, EncryptionError> {
497 if !self.keys.read().contains_key(old_key_id) {
499 return Err(EncryptionError::KeyNotFound(old_key_id.to_string()));
500 }
501
502 let new_key_id = self.generate_key()?;
504
505 tracing::info!("Key rotated: {} -> {}", old_key_id, new_key_id);
506 Ok(new_key_id)
507 }
508
509 pub fn get_keys_requiring_rotation(&self) -> Vec<String> {
511 let now = chrono::Utc::now();
512 let validity = chrono::Duration::seconds(self.config.key_validity_secs as i64);
513
514 self.keys
515 .read()
516 .iter()
517 .filter(|(_, key)| {
518 let age = now.signed_duration_since(key.created_at());
519 age > validity
520 })
521 .map(|(id, _)| id.clone())
522 .collect()
523 }
524
525 pub fn export_key(&self, key_id: &str) -> Result<String, EncryptionError> {
527 let key = self.get_key(key_id)?;
528 Ok(BASE64.encode(key.as_bytes()))
529 }
530
531 pub fn import_key(
533 &self,
534 key_b64: &str,
535 algorithm: EncryptionAlgorithm,
536 ) -> Result<String, EncryptionError> {
537 let key_bytes = BASE64
538 .decode(key_b64)
539 .map_err(|_| EncryptionError::InvalidCiphertextFormat)?;
540
541 let key = EncryptionKey::from_bytes(&key_bytes, algorithm)?;
542 self.add_key(key)
543 }
544
545 pub fn key_count(&self) -> usize {
547 self.keys.read().len()
548 }
549
550 pub fn has_default_key(&self) -> bool {
552 self.default_key_id.read().is_some()
553 }
554}
555
556impl Default for EncryptionEngine {
557 fn default() -> Self {
558 Self::new()
559 }
560}
561
562fn generate_key_id() -> String {
564 use uuid::Uuid;
565 format!("key_{}", Uuid::new_v4())
566}
567
568pub fn generate_salt() -> Vec<u8> {
570 let mut salt = vec![0u8; 16];
571 OsRng.fill_bytes(&mut salt);
572 salt
573}
574
575pub fn derive_key_from_password(
577 password: &str,
578 salt: &[u8],
579 algorithm: EncryptionAlgorithm,
580) -> Result<EncryptionKey, EncryptionError> {
581 EncryptionKey::derive_from_password(password, salt, algorithm)
582}
583
584#[cfg(test)]
585mod tests {
586 use super::*;
587
588 #[test]
589 fn test_encryption_key_generation() {
590 let key = EncryptionKey::generate(EncryptionAlgorithm::Aes256Gcm).unwrap();
591 assert_eq!(key.as_bytes().len(), 32);
592 assert!(!key.key_id().is_empty());
593 }
594
595 #[test]
596 fn test_encryption_key_from_bytes() {
597 let key_bytes = vec![0u8; 32];
598 let key = EncryptionKey::from_bytes(&key_bytes, EncryptionAlgorithm::Aes256Gcm).unwrap();
599 assert_eq!(key.as_bytes().len(), 32);
600 }
601
602 #[test]
603 fn test_encryption_key_invalid_length() {
604 let key_bytes = vec![0u8; 16];
605 let result = EncryptionKey::from_bytes(&key_bytes, EncryptionAlgorithm::Aes256Gcm);
606 assert!(result.is_err());
607 }
608
609 #[test]
610 fn test_key_derivation() {
611 let salt = generate_salt();
612 let key =
613 derive_key_from_password("password123", &salt, EncryptionAlgorithm::Aes256Gcm).unwrap();
614 assert_eq!(key.as_bytes().len(), 32);
615 }
616
617 #[test]
618 fn test_aes_gcm_encryption_decryption() {
619 let engine = EncryptionEngine::new();
620 engine.generate_key().unwrap();
621
622 let plaintext = b"Hello, World!";
623 let encrypted = engine.encrypt(plaintext).unwrap();
624 let decrypted = engine.decrypt(&encrypted).unwrap();
625
626 assert_eq!(plaintext.to_vec(), decrypted);
627 }
628
629 #[test]
630 fn test_chacha_encryption_decryption() {
631 let config = EncryptionConfig {
632 default_algorithm: EncryptionAlgorithm::ChaCha20Poly1305,
633 ..Default::default()
634 };
635 let engine = EncryptionEngine::with_config(config);
636 engine.generate_key().unwrap();
637
638 let plaintext = b"Hello, ChaCha20!";
639 let encrypted = engine.encrypt(plaintext).unwrap();
640 let decrypted = engine.decrypt(&encrypted).unwrap();
641
642 assert_eq!(plaintext.to_vec(), decrypted);
643 }
644
645 #[test]
646 fn test_string_encryption() {
647 let engine = EncryptionEngine::new();
648 engine.generate_key().unwrap();
649
650 let plaintext = "Secret message";
651 let encrypted = engine.encrypt_string(plaintext).unwrap();
652 let decrypted = engine.decrypt_to_string(&encrypted).unwrap();
653
654 assert_eq!(plaintext, decrypted);
655 }
656
657 #[test]
658 fn test_multiple_keys() {
659 let engine = EncryptionEngine::new();
660 let key_id1 = engine.generate_key().unwrap();
661 let key_id2 = engine
662 .generate_key_with_algorithm(EncryptionAlgorithm::ChaCha20Poly1305)
663 .unwrap();
664
665 assert_eq!(engine.key_count(), 2);
666 assert!(engine.list_keys().contains(&key_id1));
667 assert!(engine.list_keys().contains(&key_id2));
668 }
669
670 #[test]
671 fn test_key_removal() {
672 let engine = EncryptionEngine::new();
673 let key_id = engine.generate_key().unwrap();
674
675 assert!(engine.remove_key(&key_id).unwrap());
676 assert!(!engine.list_keys().contains(&key_id));
677 }
678
679 #[test]
680 fn test_key_rotation() {
681 let engine = EncryptionEngine::new();
682 let old_key_id = engine.generate_key().unwrap();
683
684 let new_key_id = engine.rotate_key(&old_key_id).unwrap();
685
686 assert_ne!(old_key_id, new_key_id);
687 assert!(engine.list_keys().contains(&new_key_id));
688 }
689
690 #[test]
691 fn test_encrypted_data_serialization() {
692 let engine = EncryptionEngine::new();
693 engine.generate_key().unwrap();
694
695 let encrypted = engine.encrypt_string("test").unwrap();
696 let serialized = encrypted.to_string().unwrap();
697 let deserialized = EncryptedData::from_string(&serialized).unwrap();
698
699 assert_eq!(encrypted.key_id, deserialized.key_id);
700 assert_eq!(encrypted.nonce, deserialized.nonce);
701 assert_eq!(encrypted.ciphertext, deserialized.ciphertext);
702 }
703
704 #[test]
705 fn test_key_export_import() {
706 let engine = EncryptionEngine::new();
707 let key_id = engine.generate_key().unwrap();
708
709 let exported = engine.export_key(&key_id).unwrap();
710 engine.remove_key(&key_id).unwrap();
711
712 let imported_id = engine
713 .import_key(&exported, EncryptionAlgorithm::Aes256Gcm)
714 .unwrap();
715 assert!(engine.list_keys().contains(&imported_id));
716 }
717
718 #[test]
719 fn test_different_plaintexts_different_ciphertexts() {
720 let engine = EncryptionEngine::new();
721 engine.generate_key().unwrap();
722
723 let encrypted1 = engine.encrypt(b"test").unwrap();
724 let encrypted2 = engine.encrypt(b"test").unwrap();
725
726 assert_ne!(encrypted1.ciphertext, encrypted2.ciphertext);
728 assert_ne!(encrypted1.nonce, encrypted2.nonce);
729 }
730
731 #[test]
732 fn test_large_data_encryption() {
733 let engine = EncryptionEngine::new();
734 engine.generate_key().unwrap();
735
736 let large_data = vec![0u8; 1_000_000]; let encrypted = engine.encrypt(&large_data).unwrap();
738 let decrypted = engine.decrypt(&encrypted).unwrap();
739
740 assert_eq!(large_data, decrypted);
741 }
742
743 #[test]
744 fn test_empty_data_encryption() {
745 let engine = EncryptionEngine::new();
746 engine.generate_key().unwrap();
747
748 let encrypted = engine.encrypt(b"").unwrap();
749 let decrypted = engine.decrypt(&encrypted).unwrap();
750
751 assert!(decrypted.is_empty());
752 }
753
754 #[test]
755 fn test_algorithm_display() {
756 assert_eq!(format!("{}", EncryptionAlgorithm::Aes256Gcm), "AES-256-GCM");
757 assert_eq!(
758 format!("{}", EncryptionAlgorithm::ChaCha20Poly1305),
759 "ChaCha20-Poly1305"
760 );
761 }
762
763 #[test]
764 fn test_encryption_key_debug_redaction() {
765 let key = EncryptionKey::generate(EncryptionAlgorithm::Aes256Gcm).unwrap();
766 let debug_output = format!("{:?}", key);
767
768 assert!(debug_output.contains("<redacted>"));
770 assert!(!debug_output.contains(&BASE64.encode(key.as_bytes())));
771 }
772
773 #[test]
774 fn test_default_key() {
775 let engine = EncryptionEngine::new();
776 assert!(!engine.has_default_key());
777
778 engine.generate_key().unwrap();
779 assert!(engine.has_default_key());
780 }
781
782 #[test]
783 fn test_set_default_key() {
784 let engine = EncryptionEngine::new();
785 let key_id1 = engine.generate_key().unwrap();
786 let key_id2 = engine.generate_key().unwrap();
787
788 let default_key = engine.get_default_key().unwrap();
790 assert_eq!(default_key.key_id(), key_id2);
791
792 engine.set_default_key(&key_id1).unwrap();
794 let default_key = engine.get_default_key().unwrap();
795 assert_eq!(default_key.key_id(), key_id1);
796 }
797
798 #[test]
799 fn test_wrong_algorithm_decryption() {
800 let engine = EncryptionEngine::new();
801 let aes_key = engine
802 .generate_key_with_algorithm(EncryptionAlgorithm::Aes256Gcm)
803 .unwrap();
804 let chacha_key = engine
805 .generate_key_with_algorithm(EncryptionAlgorithm::ChaCha20Poly1305)
806 .unwrap();
807
808 let aes_encrypted = engine
809 .encrypt_with_key(&engine.get_key(&aes_key).unwrap(), b"test")
810 .unwrap();
811
812 let result = engine.decrypt_with_key(&engine.get_key(&chacha_key).unwrap(), &aes_encrypted);
814 assert!(result.is_err());
815 }
816
817 #[test]
818 fn test_concurrent_encryption() {
819 use std::sync::Arc;
820 use std::thread;
821
822 let engine = Arc::new(EncryptionEngine::new());
823 engine.generate_key().unwrap();
824
825 let mut handles = vec![];
826
827 for i in 0..10 {
828 let e = Arc::clone(&engine);
829 handles.push(thread::spawn(move || {
830 let data = format!("message_{}", i);
831 let encrypted = e.encrypt_string(&data).unwrap();
832 let decrypted = e.decrypt_to_string(&encrypted).unwrap();
833 assert_eq!(data, decrypted);
834 }));
835 }
836
837 for h in handles {
838 h.join().unwrap();
839 }
840 }
841}