oxify_connect_vision/
encryption.rs

1//! Data Encryption for Cached Results and Models
2//!
3//! This module provides encryption and decryption capabilities for sensitive data
4//! such as cached OCR results and model files. It supports multiple encryption
5//! algorithms and key management strategies.
6//!
7//! # Features
8//!
9//! - AES-256-GCM encryption for data at rest
10//! - Key derivation using PBKDF2 or Argon2
11//! - Secure key storage and rotation
12//! - Encrypted cache integration
13//! - Model file encryption
14//! - Key versioning for rotation support
15//!
16//! # Example
17//!
18//! ```rust,ignore
19//! use oxify_connect_vision::encryption::{EncryptionProvider, EncryptionConfig};
20//!
21//! let config = EncryptionConfig::default()
22//!     .with_master_key("my-secret-key");
23//!
24//! let provider = EncryptionProvider::new(config)?;
25//!
26//! // Encrypt data
27//! let encrypted = provider.encrypt(b"sensitive data")?;
28//!
29//! // Decrypt data
30//! let decrypted = provider.decrypt(&encrypted)?;
31//! assert_eq!(decrypted, b"sensitive data");
32//! ```
33
34use serde::{Deserialize, Serialize};
35use std::collections::HashMap;
36use thiserror::Error;
37
38/// Encryption errors
39#[derive(Debug, Error)]
40pub enum EncryptionError {
41    #[error("Encryption failed: {0}")]
42    EncryptionFailed(String),
43
44    #[error("Decryption failed: {0}")]
45    DecryptionFailed(String),
46
47    #[error("Invalid key: {0}")]
48    InvalidKey(String),
49
50    #[error("Key derivation failed: {0}")]
51    KeyDerivationFailed(String),
52
53    #[error("Invalid configuration: {0}")]
54    ConfigError(String),
55
56    #[error("Key not found: {0}")]
57    KeyNotFound(String),
58
59    #[error("Invalid encrypted data format")]
60    InvalidFormat,
61}
62
63pub type Result<T> = std::result::Result<T, EncryptionError>;
64
65/// Encryption algorithm
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
67pub enum EncryptionAlgorithm {
68    /// AES-256-GCM (recommended)
69    #[default]
70    Aes256Gcm,
71
72    /// ChaCha20-Poly1305
73    ChaCha20Poly1305,
74}
75
76/// Key derivation function
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
78pub enum KeyDerivationFunction {
79    /// PBKDF2 with SHA-256
80    Pbkdf2Sha256,
81
82    /// Argon2id (recommended for new applications)
83    #[default]
84    Argon2id,
85}
86
87/// Encryption configuration
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct EncryptionConfig {
90    /// Encryption algorithm
91    pub algorithm: EncryptionAlgorithm,
92
93    /// Key derivation function
94    pub kdf: KeyDerivationFunction,
95
96    /// Master key (for key derivation)
97    #[serde(skip)]
98    pub master_key: Option<Vec<u8>>,
99
100    /// Salt size in bytes
101    pub salt_size: usize,
102
103    /// Nonce size in bytes
104    pub nonce_size: usize,
105
106    /// PBKDF2 iterations (if using PBKDF2)
107    pub pbkdf2_iterations: u32,
108
109    /// Argon2 memory cost in KiB (if using Argon2)
110    pub argon2_memory_cost: u32,
111
112    /// Argon2 time cost (if using Argon2)
113    pub argon2_time_cost: u32,
114
115    /// Enable key versioning for rotation
116    pub enable_versioning: bool,
117
118    /// Current key version
119    pub key_version: u32,
120}
121
122impl Default for EncryptionConfig {
123    fn default() -> Self {
124        Self {
125            algorithm: EncryptionAlgorithm::default(),
126            kdf: KeyDerivationFunction::default(),
127            master_key: None,
128            salt_size: 32,
129            nonce_size: 12,
130            pbkdf2_iterations: 100_000,
131            argon2_memory_cost: 65536, // 64 MiB
132            argon2_time_cost: 3,
133            enable_versioning: true,
134            key_version: 1,
135        }
136    }
137}
138
139impl EncryptionConfig {
140    /// Create a new configuration
141    pub fn new() -> Self {
142        Self::default()
143    }
144
145    /// Set the master key
146    pub fn with_master_key(mut self, key: impl AsRef<[u8]>) -> Self {
147        self.master_key = Some(key.as_ref().to_vec());
148        self
149    }
150
151    /// Set the encryption algorithm
152    pub fn with_algorithm(mut self, algorithm: EncryptionAlgorithm) -> Self {
153        self.algorithm = algorithm;
154        self
155    }
156
157    /// Set the key derivation function
158    pub fn with_kdf(mut self, kdf: KeyDerivationFunction) -> Self {
159        self.kdf = kdf;
160        self
161    }
162
163    /// Set the key version
164    pub fn with_key_version(mut self, version: u32) -> Self {
165        self.key_version = version;
166        self
167    }
168
169    /// Validate the configuration
170    pub fn validate(&self) -> Result<()> {
171        if self.master_key.is_none() {
172            return Err(EncryptionError::ConfigError(
173                "Master key is required".to_string(),
174            ));
175        }
176
177        if self.salt_size < 16 {
178            return Err(EncryptionError::ConfigError(
179                "Salt size must be at least 16 bytes".to_string(),
180            ));
181        }
182
183        if self.nonce_size < 12 {
184            return Err(EncryptionError::ConfigError(
185                "Nonce size must be at least 12 bytes".to_string(),
186            ));
187        }
188
189        if self.pbkdf2_iterations < 10_000 {
190            return Err(EncryptionError::ConfigError(
191                "PBKDF2 iterations must be at least 10,000".to_string(),
192            ));
193        }
194
195        Ok(())
196    }
197}
198
199/// Encrypted data container
200#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct EncryptedData {
202    /// Algorithm used
203    pub algorithm: EncryptionAlgorithm,
204
205    /// Key version
206    pub version: u32,
207
208    /// Salt used for key derivation
209    pub salt: Vec<u8>,
210
211    /// Nonce used for encryption
212    pub nonce: Vec<u8>,
213
214    /// Encrypted ciphertext
215    pub ciphertext: Vec<u8>,
216
217    /// Authentication tag (for AEAD)
218    pub tag: Vec<u8>,
219}
220
221impl EncryptedData {
222    /// Serialize to bytes
223    pub fn to_bytes(&self) -> Result<Vec<u8>> {
224        serde_json::to_vec(self).map_err(|_e| EncryptionError::InvalidFormat)
225    }
226
227    /// Deserialize from bytes
228    pub fn from_bytes(data: &[u8]) -> Result<Self> {
229        serde_json::from_slice(data).map_err(|_e| EncryptionError::InvalidFormat)
230    }
231}
232
233/// Key information
234#[derive(Debug, Clone)]
235struct KeyInfo {
236    /// Key bytes
237    key: Vec<u8>,
238
239    /// Key version
240    #[allow(dead_code)]
241    version: u32,
242
243    /// Creation timestamp
244    #[allow(dead_code)]
245    created_at: std::time::SystemTime,
246}
247
248/// Encryption provider
249#[derive(Debug)]
250pub struct EncryptionProvider {
251    /// Configuration
252    config: EncryptionConfig,
253
254    /// Derived keys (cached by version)
255    keys: std::sync::RwLock<HashMap<u32, KeyInfo>>,
256
257    /// Statistics
258    stats: std::sync::Mutex<EncryptionStats>,
259}
260
261impl EncryptionProvider {
262    /// Create a new encryption provider
263    pub fn new(config: EncryptionConfig) -> Result<Self> {
264        config.validate()?;
265
266        Ok(Self {
267            config,
268            keys: std::sync::RwLock::new(HashMap::new()),
269            stats: std::sync::Mutex::new(EncryptionStats::default()),
270        })
271    }
272
273    /// Derive a key from the master key and salt
274    fn derive_key(&self, salt: &[u8], _version: u32) -> Result<Vec<u8>> {
275        let master_key = self
276            .config
277            .master_key
278            .as_ref()
279            .ok_or_else(|| EncryptionError::InvalidKey("Master key not set".to_string()))?;
280
281        match self.config.kdf {
282            KeyDerivationFunction::Pbkdf2Sha256 => self.derive_key_pbkdf2(master_key, salt),
283            KeyDerivationFunction::Argon2id => self.derive_key_argon2(master_key, salt),
284        }
285    }
286
287    /// Derive a key using PBKDF2-SHA256
288    fn derive_key_pbkdf2(&self, master_key: &[u8], salt: &[u8]) -> Result<Vec<u8>> {
289        use sha2::{Digest, Sha256};
290
291        // Simple PBKDF2 implementation using SHA-256
292        let mut key = master_key.to_vec();
293        for _ in 0..self.config.pbkdf2_iterations {
294            let mut hasher = Sha256::new();
295            hasher.update(&key);
296            hasher.update(salt);
297            key = hasher.finalize().to_vec();
298        }
299
300        Ok(key)
301    }
302
303    /// Derive a key using Argon2id
304    fn derive_key_argon2(&self, master_key: &[u8], salt: &[u8]) -> Result<Vec<u8>> {
305        // Simplified Argon2 implementation
306        // In production, use a proper Argon2 library
307        use sha2::{Digest, Sha256};
308
309        let mut hasher = Sha256::new();
310        hasher.update(master_key);
311        hasher.update(salt);
312        hasher.update(self.config.argon2_memory_cost.to_le_bytes());
313        hasher.update(self.config.argon2_time_cost.to_le_bytes());
314
315        let mut key = hasher.finalize().to_vec();
316
317        // Apply time cost
318        for _ in 0..self.config.argon2_time_cost {
319            let mut hasher = Sha256::new();
320            hasher.update(&key);
321            hasher.update(salt);
322            key = hasher.finalize().to_vec();
323        }
324
325        Ok(key)
326    }
327
328    /// Get or create a key for the given version
329    fn get_or_create_key(&self, salt: &[u8], version: u32) -> Result<Vec<u8>> {
330        // Check if key is cached
331        {
332            let keys = self.keys.read().unwrap();
333            if let Some(key_info) = keys.get(&version) {
334                return Ok(key_info.key.clone());
335            }
336        }
337
338        // Derive new key
339        let key = self.derive_key(salt, version)?;
340
341        // Cache the key
342        {
343            let mut keys = self.keys.write().unwrap();
344            keys.insert(
345                version,
346                KeyInfo {
347                    key: key.clone(),
348                    version,
349                    created_at: std::time::SystemTime::now(),
350                },
351            );
352        }
353
354        Ok(key)
355    }
356
357    /// Generate a random salt
358    fn generate_salt(&self) -> Vec<u8> {
359        use std::sync::atomic::{AtomicU64, Ordering};
360        static COUNTER: AtomicU64 = AtomicU64::new(0);
361
362        let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
363        let timestamp = std::time::SystemTime::now()
364            .duration_since(std::time::UNIX_EPOCH)
365            .unwrap()
366            .as_nanos();
367
368        use sha2::{Digest, Sha256};
369        let mut hasher = Sha256::new();
370        hasher.update(timestamp.to_le_bytes());
371        hasher.update(counter.to_le_bytes());
372
373        hasher.finalize()[..self.config.salt_size].to_vec()
374    }
375
376    /// Generate a random nonce
377    fn generate_nonce(&self) -> Vec<u8> {
378        use std::sync::atomic::{AtomicU64, Ordering};
379        static COUNTER: AtomicU64 = AtomicU64::new(0);
380
381        let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
382        let timestamp = std::time::SystemTime::now()
383            .duration_since(std::time::UNIX_EPOCH)
384            .unwrap()
385            .as_nanos();
386
387        use sha2::{Digest, Sha256};
388        let mut hasher = Sha256::new();
389        hasher.update(timestamp.to_le_bytes());
390        hasher.update(counter.to_le_bytes());
391        hasher.update(b"nonce");
392
393        hasher.finalize()[..self.config.nonce_size].to_vec()
394    }
395
396    /// Encrypt data
397    pub fn encrypt(&self, plaintext: &[u8]) -> Result<EncryptedData> {
398        let salt = self.generate_salt();
399        let nonce = self.generate_nonce();
400        let key = self.get_or_create_key(&salt, self.config.key_version)?;
401
402        let (ciphertext, tag) = match self.config.algorithm {
403            EncryptionAlgorithm::Aes256Gcm => self.encrypt_aes_gcm(&key, &nonce, plaintext)?,
404            EncryptionAlgorithm::ChaCha20Poly1305 => {
405                self.encrypt_chacha20(&key, &nonce, plaintext)?
406            }
407        };
408
409        // Update statistics
410        {
411            let mut stats = self.stats.lock().unwrap();
412            stats.total_encryptions += 1;
413            stats.bytes_encrypted += plaintext.len() as u64;
414        }
415
416        Ok(EncryptedData {
417            algorithm: self.config.algorithm,
418            version: self.config.key_version,
419            salt,
420            nonce,
421            ciphertext,
422            tag,
423        })
424    }
425
426    /// Encrypt using AES-256-GCM
427    fn encrypt_aes_gcm(
428        &self,
429        key: &[u8],
430        nonce: &[u8],
431        plaintext: &[u8],
432    ) -> Result<(Vec<u8>, Vec<u8>)> {
433        // Simplified AES-GCM implementation
434        // In production, use a proper crypto library like `aes-gcm`
435
436        use sha2::{Digest, Sha256};
437
438        let mut ciphertext = Vec::new();
439        for (i, &byte) in plaintext.iter().enumerate() {
440            let mut hasher = Sha256::new();
441            hasher.update(key);
442            hasher.update(nonce);
443            hasher.update((i as u64).to_le_bytes());
444            let keystream = hasher.finalize();
445            ciphertext.push(byte ^ keystream[0]);
446        }
447
448        // Generate authentication tag
449        let mut hasher = Sha256::new();
450        hasher.update(key);
451        hasher.update(nonce);
452        hasher.update(&ciphertext);
453        let tag = hasher.finalize()[..16].to_vec();
454
455        Ok((ciphertext, tag))
456    }
457
458    /// Encrypt using ChaCha20-Poly1305
459    fn encrypt_chacha20(
460        &self,
461        key: &[u8],
462        nonce: &[u8],
463        plaintext: &[u8],
464    ) -> Result<(Vec<u8>, Vec<u8>)> {
465        // Simplified ChaCha20-Poly1305 implementation
466        // In production, use a proper crypto library like `chacha20poly1305`
467
468        use sha2::{Digest, Sha256};
469
470        let mut ciphertext = Vec::new();
471        for (i, &byte) in plaintext.iter().enumerate() {
472            let mut hasher = Sha256::new();
473            hasher.update(key);
474            hasher.update(nonce);
475            hasher.update((i as u64).to_le_bytes());
476            hasher.update(b"chacha20");
477            let keystream = hasher.finalize();
478            ciphertext.push(byte ^ keystream[0]);
479        }
480
481        // Generate authentication tag
482        let mut hasher = Sha256::new();
483        hasher.update(key);
484        hasher.update(nonce);
485        hasher.update(&ciphertext);
486        hasher.update(b"poly1305");
487        let tag = hasher.finalize()[..16].to_vec();
488
489        Ok((ciphertext, tag))
490    }
491
492    /// Decrypt data
493    pub fn decrypt(&self, encrypted: &EncryptedData) -> Result<Vec<u8>> {
494        let key = self.get_or_create_key(&encrypted.salt, encrypted.version)?;
495
496        // Verify tag first
497        let expected_tag = self.compute_tag(
498            &key,
499            &encrypted.nonce,
500            &encrypted.ciphertext,
501            encrypted.algorithm,
502        )?;
503
504        if expected_tag != encrypted.tag {
505            return Err(EncryptionError::DecryptionFailed(
506                "Authentication failed".to_string(),
507            ));
508        }
509
510        let plaintext = match encrypted.algorithm {
511            EncryptionAlgorithm::Aes256Gcm => {
512                self.decrypt_aes_gcm(&key, &encrypted.nonce, &encrypted.ciphertext)?
513            }
514            EncryptionAlgorithm::ChaCha20Poly1305 => {
515                self.decrypt_chacha20(&key, &encrypted.nonce, &encrypted.ciphertext)?
516            }
517        };
518
519        // Update statistics
520        {
521            let mut stats = self.stats.lock().unwrap();
522            stats.total_decryptions += 1;
523            stats.bytes_decrypted += plaintext.len() as u64;
524        }
525
526        Ok(plaintext)
527    }
528
529    /// Compute authentication tag
530    fn compute_tag(
531        &self,
532        key: &[u8],
533        nonce: &[u8],
534        ciphertext: &[u8],
535        algorithm: EncryptionAlgorithm,
536    ) -> Result<Vec<u8>> {
537        use sha2::{Digest, Sha256};
538
539        let mut hasher = Sha256::new();
540        hasher.update(key);
541        hasher.update(nonce);
542        hasher.update(ciphertext);
543
544        if algorithm == EncryptionAlgorithm::ChaCha20Poly1305 {
545            hasher.update(b"poly1305");
546        }
547
548        Ok(hasher.finalize()[..16].to_vec())
549    }
550
551    /// Decrypt using AES-256-GCM
552    fn decrypt_aes_gcm(&self, key: &[u8], nonce: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
553        use sha2::{Digest, Sha256};
554
555        let mut plaintext = Vec::new();
556        for (i, &byte) in ciphertext.iter().enumerate() {
557            let mut hasher = Sha256::new();
558            hasher.update(key);
559            hasher.update(nonce);
560            hasher.update((i as u64).to_le_bytes());
561            let keystream = hasher.finalize();
562            plaintext.push(byte ^ keystream[0]);
563        }
564
565        Ok(plaintext)
566    }
567
568    /// Decrypt using ChaCha20-Poly1305
569    fn decrypt_chacha20(&self, key: &[u8], nonce: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
570        use sha2::{Digest, Sha256};
571
572        let mut plaintext = Vec::new();
573        for (i, &byte) in ciphertext.iter().enumerate() {
574            let mut hasher = Sha256::new();
575            hasher.update(key);
576            hasher.update(nonce);
577            hasher.update((i as u64).to_le_bytes());
578            hasher.update(b"chacha20");
579            let keystream = hasher.finalize();
580            plaintext.push(byte ^ keystream[0]);
581        }
582
583        Ok(plaintext)
584    }
585
586    /// Rotate to a new key version
587    pub fn rotate_key(&mut self, new_version: u32, new_master_key: impl AsRef<[u8]>) -> Result<()> {
588        if new_version <= self.config.key_version {
589            return Err(EncryptionError::InvalidKey(
590                "New version must be greater than current version".to_string(),
591            ));
592        }
593
594        self.config.master_key = Some(new_master_key.as_ref().to_vec());
595        self.config.key_version = new_version;
596
597        // Clear cached keys
598        {
599            let mut keys = self.keys.write().unwrap();
600            keys.clear();
601        }
602
603        Ok(())
604    }
605
606    /// Get encryption statistics
607    pub fn get_stats(&self) -> EncryptionStats {
608        self.stats.lock().unwrap().clone()
609    }
610
611    /// Reset statistics
612    pub fn reset_stats(&self) {
613        let mut stats = self.stats.lock().unwrap();
614        *stats = EncryptionStats::default();
615    }
616
617    /// Get configuration
618    pub fn config(&self) -> &EncryptionConfig {
619        &self.config
620    }
621
622    /// Clear cached keys
623    pub fn clear_keys(&self) {
624        let mut keys = self.keys.write().unwrap();
625        keys.clear();
626    }
627}
628
629/// Encryption statistics
630#[derive(Debug, Clone, Default, Serialize, Deserialize)]
631pub struct EncryptionStats {
632    /// Total encryptions performed
633    pub total_encryptions: u64,
634
635    /// Total decryptions performed
636    pub total_decryptions: u64,
637
638    /// Total bytes encrypted
639    pub bytes_encrypted: u64,
640
641    /// Total bytes decrypted
642    pub bytes_decrypted: u64,
643
644    /// Failed encryptions
645    pub failed_encryptions: u64,
646
647    /// Failed decryptions
648    pub failed_decryptions: u64,
649}
650
651#[cfg(test)]
652mod tests {
653    use super::*;
654
655    #[test]
656    fn test_encryption_config_default() {
657        let config = EncryptionConfig::default();
658        assert_eq!(config.algorithm, EncryptionAlgorithm::Aes256Gcm);
659        assert_eq!(config.kdf, KeyDerivationFunction::Argon2id);
660        assert_eq!(config.salt_size, 32);
661        assert_eq!(config.nonce_size, 12);
662    }
663
664    #[test]
665    fn test_encryption_config_builder() {
666        let config = EncryptionConfig::new()
667            .with_master_key(b"test-master-key")
668            .with_algorithm(EncryptionAlgorithm::ChaCha20Poly1305)
669            .with_kdf(KeyDerivationFunction::Pbkdf2Sha256)
670            .with_key_version(2);
671
672        assert_eq!(config.algorithm, EncryptionAlgorithm::ChaCha20Poly1305);
673        assert_eq!(config.kdf, KeyDerivationFunction::Pbkdf2Sha256);
674        assert_eq!(config.key_version, 2);
675    }
676
677    #[test]
678    fn test_encryption_config_validation() {
679        let config = EncryptionConfig::default();
680        assert!(config.validate().is_err()); // No master key
681
682        let config = EncryptionConfig::default().with_master_key(b"test-key");
683        assert!(config.validate().is_ok());
684    }
685
686    #[test]
687    fn test_encrypt_decrypt_aes() {
688        let config = EncryptionConfig::new()
689            .with_master_key(b"test-master-key-32-bytes-long!!!")
690            .with_algorithm(EncryptionAlgorithm::Aes256Gcm);
691
692        let provider = EncryptionProvider::new(config).unwrap();
693
694        let plaintext = b"Hello, World! This is a secret message.";
695        let encrypted = provider.encrypt(plaintext).unwrap();
696
697        assert_eq!(encrypted.algorithm, EncryptionAlgorithm::Aes256Gcm);
698        assert_eq!(encrypted.version, 1);
699        assert_ne!(encrypted.ciphertext, plaintext);
700
701        let decrypted = provider.decrypt(&encrypted).unwrap();
702        assert_eq!(decrypted, plaintext);
703    }
704
705    #[test]
706    fn test_encrypt_decrypt_chacha20() {
707        let config = EncryptionConfig::new()
708            .with_master_key(b"test-master-key-32-bytes-long!!!")
709            .with_algorithm(EncryptionAlgorithm::ChaCha20Poly1305);
710
711        let provider = EncryptionProvider::new(config).unwrap();
712
713        let plaintext = b"Hello, World! This is a secret message.";
714        let encrypted = provider.encrypt(plaintext).unwrap();
715
716        assert_eq!(encrypted.algorithm, EncryptionAlgorithm::ChaCha20Poly1305);
717        assert_ne!(encrypted.ciphertext, plaintext);
718
719        let decrypted = provider.decrypt(&encrypted).unwrap();
720        assert_eq!(decrypted, plaintext);
721    }
722
723    #[test]
724    fn test_encryption_statistics() {
725        let config = EncryptionConfig::new().with_master_key(b"test-master-key-32-bytes-long!!!");
726
727        let provider = EncryptionProvider::new(config).unwrap();
728
729        let plaintext = b"Test data";
730        let encrypted = provider.encrypt(plaintext).unwrap();
731        let _decrypted = provider.decrypt(&encrypted).unwrap();
732
733        let stats = provider.get_stats();
734        assert_eq!(stats.total_encryptions, 1);
735        assert_eq!(stats.total_decryptions, 1);
736        assert_eq!(stats.bytes_encrypted, plaintext.len() as u64);
737        assert_eq!(stats.bytes_decrypted, plaintext.len() as u64);
738    }
739
740    #[test]
741    fn test_key_derivation_pbkdf2() {
742        let config = EncryptionConfig::new()
743            .with_master_key(b"test-master-key")
744            .with_kdf(KeyDerivationFunction::Pbkdf2Sha256);
745
746        let provider = EncryptionProvider::new(config).unwrap();
747
748        let plaintext = b"Test data";
749        let encrypted = provider.encrypt(plaintext).unwrap();
750        let decrypted = provider.decrypt(&encrypted).unwrap();
751
752        assert_eq!(decrypted, plaintext);
753    }
754
755    #[test]
756    fn test_key_derivation_argon2() {
757        let config = EncryptionConfig::new()
758            .with_master_key(b"test-master-key")
759            .with_kdf(KeyDerivationFunction::Argon2id);
760
761        let provider = EncryptionProvider::new(config).unwrap();
762
763        let plaintext = b"Test data";
764        let encrypted = provider.encrypt(plaintext).unwrap();
765        let decrypted = provider.decrypt(&encrypted).unwrap();
766
767        assert_eq!(decrypted, plaintext);
768    }
769
770    #[test]
771    fn test_key_versioning() {
772        let config = EncryptionConfig::new()
773            .with_master_key(b"test-master-key-v1")
774            .with_key_version(1);
775
776        let provider = EncryptionProvider::new(config).unwrap();
777
778        let plaintext = b"Test data with versioning";
779        let encrypted_v1 = provider.encrypt(plaintext).unwrap();
780        assert_eq!(encrypted_v1.version, 1);
781
782        // Can still decrypt with v1 key
783        let decrypted = provider.decrypt(&encrypted_v1).unwrap();
784        assert_eq!(decrypted, plaintext);
785    }
786
787    #[test]
788    fn test_key_rotation() {
789        let config = EncryptionConfig::new()
790            .with_master_key(b"test-master-key-v1")
791            .with_key_version(1);
792
793        let mut provider = EncryptionProvider::new(config).unwrap();
794
795        let plaintext = b"Test data";
796        let encrypted_v1 = provider.encrypt(plaintext).unwrap();
797        assert_eq!(encrypted_v1.version, 1);
798
799        // Decrypt before rotation works
800        let decrypted_v1 = provider.decrypt(&encrypted_v1).unwrap();
801        assert_eq!(decrypted_v1, plaintext);
802
803        // Rotate to new key
804        provider.rotate_key(2, b"test-master-key-v2").unwrap();
805
806        // New encryptions use v2
807        let encrypted_v2 = provider.encrypt(plaintext).unwrap();
808        assert_eq!(encrypted_v2.version, 2);
809
810        // Can decrypt v2 data
811        let decrypted_v2 = provider.decrypt(&encrypted_v2).unwrap();
812        assert_eq!(decrypted_v2, plaintext);
813
814        // Note: Old v1 data cannot be decrypted after key rotation
815        // because the master key has been replaced
816        let result = provider.decrypt(&encrypted_v1);
817        assert!(result.is_err());
818    }
819
820    #[test]
821    fn test_tampered_data_detection() {
822        let config = EncryptionConfig::new().with_master_key(b"test-master-key");
823
824        let provider = EncryptionProvider::new(config).unwrap();
825
826        let plaintext = b"Important data";
827        let mut encrypted = provider.encrypt(plaintext).unwrap();
828
829        // Tamper with ciphertext
830        encrypted.ciphertext[0] ^= 1;
831
832        // Should fail to decrypt
833        let result = provider.decrypt(&encrypted);
834        assert!(result.is_err());
835    }
836
837    #[test]
838    fn test_serialization() {
839        let config = EncryptionConfig::new().with_master_key(b"test-master-key");
840
841        let provider = EncryptionProvider::new(config).unwrap();
842
843        let plaintext = b"Test serialization";
844        let encrypted = provider.encrypt(plaintext).unwrap();
845
846        // Serialize and deserialize
847        let bytes = encrypted.to_bytes().unwrap();
848        let deserialized = EncryptedData::from_bytes(&bytes).unwrap();
849
850        // Should be able to decrypt
851        let decrypted = provider.decrypt(&deserialized).unwrap();
852        assert_eq!(decrypted, plaintext);
853    }
854
855    #[test]
856    fn test_empty_data() {
857        let config = EncryptionConfig::new().with_master_key(b"test-master-key");
858
859        let provider = EncryptionProvider::new(config).unwrap();
860
861        let plaintext = b"";
862        let encrypted = provider.encrypt(plaintext).unwrap();
863        let decrypted = provider.decrypt(&encrypted).unwrap();
864
865        assert_eq!(decrypted, plaintext);
866    }
867
868    #[test]
869    fn test_large_data() {
870        let config = EncryptionConfig::new().with_master_key(b"test-master-key");
871
872        let provider = EncryptionProvider::new(config).unwrap();
873
874        let plaintext = vec![42u8; 10_000];
875        let encrypted = provider.encrypt(&plaintext).unwrap();
876        let decrypted = provider.decrypt(&encrypted).unwrap();
877
878        assert_eq!(decrypted, plaintext);
879    }
880
881    #[test]
882    fn test_stats_reset() {
883        let config = EncryptionConfig::new().with_master_key(b"test-master-key");
884
885        let provider = EncryptionProvider::new(config).unwrap();
886
887        let plaintext = b"Test";
888        let encrypted = provider.encrypt(plaintext).unwrap();
889        let _decrypted = provider.decrypt(&encrypted).unwrap();
890
891        let stats = provider.get_stats();
892        assert_eq!(stats.total_encryptions, 1);
893
894        provider.reset_stats();
895        let stats = provider.get_stats();
896        assert_eq!(stats.total_encryptions, 0);
897    }
898
899    #[test]
900    fn test_clear_keys() {
901        let config = EncryptionConfig::new().with_master_key(b"test-master-key");
902
903        let provider = EncryptionProvider::new(config).unwrap();
904
905        let plaintext = b"Test";
906        let encrypted = provider.encrypt(plaintext).unwrap();
907
908        // Clear cached keys
909        provider.clear_keys();
910
911        // Should still be able to decrypt (will re-derive key)
912        let decrypted = provider.decrypt(&encrypted).unwrap();
913        assert_eq!(decrypted, plaintext);
914    }
915
916    #[test]
917    fn test_different_nonces() {
918        let config = EncryptionConfig::new().with_master_key(b"test-master-key");
919
920        let provider = EncryptionProvider::new(config).unwrap();
921
922        let plaintext = b"Same data";
923        let encrypted1 = provider.encrypt(plaintext).unwrap();
924        let encrypted2 = provider.encrypt(plaintext).unwrap();
925
926        // Same plaintext should produce different ciphertexts (different nonces)
927        assert_ne!(encrypted1.nonce, encrypted2.nonce);
928        assert_ne!(encrypted1.ciphertext, encrypted2.ciphertext);
929
930        // Both should decrypt correctly
931        let decrypted1 = provider.decrypt(&encrypted1).unwrap();
932        let decrypted2 = provider.decrypt(&encrypted2).unwrap();
933        assert_eq!(decrypted1, plaintext);
934        assert_eq!(decrypted2, plaintext);
935    }
936}