Skip to main content

qualia_core_db/specialized_libs/cryptographic_library/
encryption.rs

1// Part of the cryptographic_library module (split from the former mod.rs monolith
2// per CLAUDE.md §11 — pure code motion, no behaviour change).
3use super::*;
4
5/// Encryption engine for data encryption
6pub struct EncryptionEngine {
7    encryption_algorithms: HashMap<EncryptionAlgorithm, EncryptionAlgorithmImpl>,
8    decryption_algorithms: HashMap<EncryptionAlgorithm, DecryptionAlgorithmImpl>,
9    key_derivation: KeyDerivation,
10    performance_optimizer: EncryptionPerformanceOptimizer,
11}
12
13/// Encryption algorithm implementation
14#[derive(Debug, Clone)]
15pub struct EncryptionAlgorithmImpl {
16    pub algorithm_id: String,
17    pub algorithm: EncryptionAlgorithm,
18    pub key_size: usize,
19    pub iv_size: usize,
20    pub tag_size: usize,
21    pub parameters: EncryptionParameters,
22}
23
24/// Encryption parameters
25#[derive(Debug, Clone)]
26pub struct EncryptionParameters {
27    pub mode: EncryptionMode,
28    pub padding: Option<EncryptionPadding>,
29    pub additional_data: Option<Vec<u8>>,
30    pub custom_params: HashMap<String, Vec<u8>>,
31}
32
33/// Encryption modes
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35pub enum EncryptionMode {
36    GCM,
37    CCM,
38    CTR,
39    CBC,
40    CFB,
41    OFB,
42    XTS,
43}
44
45/// Encryption padding
46#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47pub enum EncryptionPadding {
48    PKCS7,
49    ISO10126,
50    ANSIX923,
51    ZeroPadding,
52    NoPadding,
53}
54
55/// Decryption algorithm implementation
56#[derive(Debug, Clone)]
57pub struct DecryptionAlgorithmImpl {
58    pub algorithm_id: String,
59    pub algorithm: EncryptionAlgorithm,
60    pub key_size: usize,
61    pub iv_size: usize,
62    pub tag_size: usize,
63    pub parameters: DecryptionParameters,
64}
65
66/// Decryption parameters
67#[derive(Debug, Clone)]
68pub struct DecryptionParameters {
69    pub mode: EncryptionMode,
70    pub padding: Option<EncryptionPadding>,
71    pub additional_data: Option<Vec<u8>>,
72    pub custom_params: HashMap<String, Vec<u8>>,
73}
74
75/// Key derivation
76pub struct KeyDerivation {
77    derivation_functions: HashMap<String, DerivationFunction>,
78    pub(super) derivation_parameters: DerivationParameters,
79}
80
81/// Derivation functions
82#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
83pub enum DerivationFunction {
84    HKDF,
85    PBKDF2,
86    Scrypt,
87    Argon2,
88    Custom(String),
89}
90
91/// Derivation parameters
92#[derive(Debug, Clone)]
93pub struct DerivationParameters {
94    pub salt: Vec<u8>,
95    pub iterations: u32,
96    pub memory_cost: u32,
97    pub parallelism: u32,
98    pub output_length: usize,
99}
100
101/// Encryption performance optimizer
102pub struct EncryptionPerformanceOptimizer {
103    optimization_strategies: Vec<EncryptionOptimizationStrategy>,
104    performance_metrics: EncryptionPerformanceMetrics,
105}
106
107/// Encryption optimization strategies
108#[derive(Debug, Clone, PartialEq)]
109pub enum EncryptionOptimizationStrategy {
110    BatchEncryption,
111    ParallelProcessing,
112    HardwareAcceleration,
113    MemoryOptimization,
114    Caching,
115}
116
117/// Encryption performance metrics
118#[derive(Debug, Clone)]
119pub struct EncryptionPerformanceMetrics {
120    pub average_encryption_time: f64,
121    pub average_decryption_time: f64,
122    pub throughput: f64,
123    pub memory_usage: u64,
124    pub cache_hit_rate: f64,
125}
126impl EncryptionEngine {
127    pub fn new() -> Self {
128        Self {
129            encryption_algorithms: HashMap::new(),
130            decryption_algorithms: HashMap::new(),
131            key_derivation: KeyDerivation::new(),
132            performance_optimizer: EncryptionPerformanceOptimizer::new(),
133        }
134    }
135
136    pub fn initialize(&mut self) -> Result<(), CryptographicError> {
137        self.key_derivation.initialize()?;
138        self.performance_optimizer.initialize()?;
139        Ok(())
140    }
141
142    /// Register an encryption algorithm implementation.
143    pub fn add_encryption_algorithm(
144        &mut self,
145        algorithm: EncryptionAlgorithm,
146        implementation: EncryptionAlgorithmImpl,
147    ) {
148        self.encryption_algorithms.insert(algorithm, implementation);
149    }
150
151    /// Look up an encryption algorithm implementation.
152    pub fn get_encryption_algorithm(
153        &self,
154        algorithm: &EncryptionAlgorithm,
155    ) -> Option<&EncryptionAlgorithmImpl> {
156        self.encryption_algorithms.get(algorithm)
157    }
158
159    /// Iterate over all registered encryption algorithm implementations.
160    pub fn list_encryption_algorithms(&self) -> impl Iterator<Item = &EncryptionAlgorithmImpl> {
161        self.encryption_algorithms.values()
162    }
163
164    /// Register a decryption algorithm implementation.
165    pub fn add_decryption_algorithm(
166        &mut self,
167        algorithm: EncryptionAlgorithm,
168        implementation: DecryptionAlgorithmImpl,
169    ) {
170        self.decryption_algorithms.insert(algorithm, implementation);
171    }
172
173    /// Look up a decryption algorithm implementation.
174    pub fn get_decryption_algorithm(
175        &self,
176        algorithm: &EncryptionAlgorithm,
177    ) -> Option<&DecryptionAlgorithmImpl> {
178        self.decryption_algorithms.get(algorithm)
179    }
180
181    /// Iterate over all registered decryption algorithm implementations.
182    pub fn list_decryption_algorithms(&self) -> impl Iterator<Item = &DecryptionAlgorithmImpl> {
183        self.decryption_algorithms.values()
184    }
185
186    /// Derive key material using HKDF-SHA256 via the embedded [`KeyDerivation`] engine.
187    pub fn derive_hkdf(&self, ikm: &[u8], info: &[u8]) -> Result<Vec<u8>, CryptographicError> {
188        self.key_derivation.derive_hkdf(ikm, info)
189    }
190
191    pub fn encrypt_data(
192        &mut self,
193        key: &Key,
194        data: &[u8],
195        additional_data: Option<&[u8]>,
196    ) -> Result<EncryptedData, CryptographicError> {
197        self.encrypt_data_with(key, data, additional_data, EncryptionAlgorithm::AES256GCM)
198    }
199
200    /// Encrypt with an explicitly chosen AEAD algorithm
201    /// (AES-256-GCM, ChaCha20-Poly1305, or XChaCha20-Poly1305).
202    pub fn encrypt_data_with(
203        &mut self,
204        key: &Key,
205        data: &[u8],
206        additional_data: Option<&[u8]>,
207        algorithm: EncryptionAlgorithm,
208    ) -> Result<EncryptedData, CryptographicError> {
209        let start_time = std::time::Instant::now();
210
211        // Generate a nonce sized for the chosen algorithm
212        let iv = self.generate_iv(&algorithm)?;
213
214        // Encrypt data
215        let (ciphertext, tag) =
216            self.encrypt_with_key(&key, data, &iv, additional_data, &algorithm)?;
217
218        let mode = match algorithm {
219            EncryptionAlgorithm::AES256GCM => EncryptionMode::GCM,
220            // ChaCha20 is a counter-mode stream cipher with a Poly1305 MAC; CTR is the
221            // closest honest descriptor in the (cosmetic) EncryptionMode enum.
222            _ => EncryptionMode::CTR,
223        };
224
225        let encrypted_data = EncryptedData {
226            data_id: format!(
227                "enc_{}",
228                std::time::SystemTime::now()
229                    .duration_since(std::time::UNIX_EPOCH)
230                    .unwrap()
231                    .as_secs()
232            ),
233            algorithm: algorithm.clone(),
234            ciphertext,
235            iv,
236            tag,
237            aad: additional_data.unwrap_or(b"").to_vec(),
238            metadata: EncryptionMetadata {
239                key_id: key.key_id.clone(),
240                algorithm,
241                mode,
242                padding: Some(EncryptionPadding::NoPadding),
243                created_at: start_time.elapsed().as_millis() as u64,
244            },
245        };
246
247        // Record performance metrics
248        self.performance_optimizer
249            .record_encryption_time(start_time.elapsed().as_millis() as f64);
250
251        Ok(encrypted_data)
252    }
253
254    pub fn decrypt_data(
255        &mut self,
256        key: &Key,
257        encrypted_data: &EncryptedData,
258    ) -> Result<Vec<u8>, CryptographicError> {
259        let start_time = std::time::Instant::now();
260        // Dispatch on the algorithm the ciphertext was produced with.
261        let aad_ref = if encrypted_data.aad.is_empty() {
262            None
263        } else {
264            Some(encrypted_data.aad.as_slice())
265        };
266        let plaintext = self.decrypt_with_key(
267            &key,
268            &encrypted_data.ciphertext,
269            &encrypted_data.iv,
270            &encrypted_data.tag,
271            aad_ref,
272            &encrypted_data.algorithm,
273        )?;
274
275        // Record performance metrics
276        self.performance_optimizer
277            .record_decryption_time(start_time.elapsed().as_millis() as f64);
278
279        Ok(plaintext)
280    }
281
282    /// Expected nonce length in bytes for the given AEAD algorithm.
283    fn nonce_len(algorithm: &EncryptionAlgorithm) -> usize {
284        match algorithm {
285            EncryptionAlgorithm::XChaCha20Poly1305 => 24,
286            _ => 12, // AES-256-GCM and ChaCha20-Poly1305
287        }
288    }
289
290    fn generate_iv(&self, algorithm: &EncryptionAlgorithm) -> Result<Vec<u8>, CryptographicError> {
291        let len = Self::nonce_len(algorithm);
292        let mut iv = vec![0u8; len];
293        for b in iv.iter_mut() {
294            *b = rand::random::<u8>();
295        }
296        Ok(iv)
297    }
298
299    fn encrypt_with_key(
300        &self,
301        key: &Key,
302        data: &[u8],
303        iv: &[u8],
304        additional_data: Option<&[u8]>,
305        algorithm: &EncryptionAlgorithm,
306    ) -> Result<(Vec<u8>, Vec<u8>), CryptographicError> {
307        use aead::{AeadInOut, KeyInit};
308        if key.key_data.len() < 32 {
309            return Err(CryptographicError::EncryptionError(
310                "AEAD key must be 32 bytes".to_string(),
311            ));
312        }
313        let expected_nonce = Self::nonce_len(algorithm);
314        if iv.len() != expected_nonce {
315            return Err(CryptographicError::EncryptionError(format!(
316                "IV must be {expected_nonce} bytes for this algorithm"
317            )));
318        }
319        let aad = additional_data.unwrap_or(b"");
320        let mut buffer = data.to_vec();
321        let tag = match algorithm {
322            EncryptionAlgorithm::AES256GCM => {
323                use aes_gcm::Aes256Gcm;
324                let cipher = Aes256Gcm::new(
325                    &aes_gcm::Key::<Aes256Gcm>::try_from(&key.key_data[..32]).unwrap(),
326                );
327                cipher
328                    .encrypt_inout_detached(
329                        &aes_gcm::Nonce::try_from(iv).unwrap(),
330                        aad,
331                        (&mut buffer[..]).into(),
332                    )
333                    .map_err(|e| CryptographicError::EncryptionError(e.to_string()))?
334                    .to_vec()
335            }
336            EncryptionAlgorithm::ChaCha20Poly1305 => {
337                use chacha20poly1305::ChaCha20Poly1305;
338                let cipher = ChaCha20Poly1305::new(
339                    &chacha20poly1305::Key::try_from(&key.key_data[..32]).unwrap(),
340                );
341                cipher
342                    .encrypt_inout_detached(
343                        &chacha20poly1305::Nonce::try_from(iv).unwrap(),
344                        aad,
345                        (&mut buffer[..]).into(),
346                    )
347                    .map_err(|e| CryptographicError::EncryptionError(e.to_string()))?
348                    .to_vec()
349            }
350            EncryptionAlgorithm::XChaCha20Poly1305 => {
351                use chacha20poly1305::XChaCha20Poly1305;
352                let cipher = XChaCha20Poly1305::new(
353                    &chacha20poly1305::Key::try_from(&key.key_data[..32]).unwrap(),
354                );
355                cipher
356                    .encrypt_inout_detached(
357                        &chacha20poly1305::XNonce::try_from(iv).unwrap(),
358                        aad,
359                        (&mut buffer[..]).into(),
360                    )
361                    .map_err(|e| CryptographicError::EncryptionError(e.to_string()))?
362                    .to_vec()
363            }
364            EncryptionAlgorithm::Custom(name) => {
365                return Err(CryptographicError::UnsupportedAlgorithm(format!(
366                    "Custom cipher '{name}' not implemented"
367                )));
368            }
369        };
370        Ok((buffer, tag))
371    }
372
373    fn decrypt_with_key(
374        &self,
375        key: &Key,
376        ciphertext: &[u8],
377        iv: &[u8],
378        tag: &[u8],
379        additional_data: Option<&[u8]>,
380        algorithm: &EncryptionAlgorithm,
381    ) -> Result<Vec<u8>, CryptographicError> {
382        use aead::{AeadInOut, KeyInit};
383        if key.key_data.len() < 32 {
384            return Err(CryptographicError::DecryptionError(
385                "AEAD key must be 32 bytes".to_string(),
386            ));
387        }
388        let expected_nonce = Self::nonce_len(algorithm);
389        if iv.len() != expected_nonce {
390            return Err(CryptographicError::DecryptionError(format!(
391                "IV must be {expected_nonce} bytes for this algorithm"
392            )));
393        }
394        if tag.len() != 16 {
395            return Err(CryptographicError::DecryptionError(
396                "AEAD tag must be 16 bytes".to_string(),
397            ));
398        }
399        let aad = additional_data.unwrap_or(b"");
400        let mut buffer = ciphertext.to_vec();
401        match algorithm {
402            EncryptionAlgorithm::AES256GCM => {
403                use aes_gcm::Aes256Gcm;
404                let cipher = Aes256Gcm::new(
405                    &aes_gcm::Key::<Aes256Gcm>::try_from(&key.key_data[..32]).unwrap(),
406                );
407                cipher
408                    .decrypt_inout_detached(
409                        &aes_gcm::Nonce::try_from(iv).unwrap(),
410                        aad,
411                        (&mut buffer[..]).into(),
412                        &aes_gcm::Tag::try_from(tag).unwrap(),
413                    )
414                    .map_err(|e| CryptographicError::DecryptionError(e.to_string()))?;
415            }
416            EncryptionAlgorithm::ChaCha20Poly1305 => {
417                use chacha20poly1305::ChaCha20Poly1305;
418                let cipher = ChaCha20Poly1305::new(
419                    &chacha20poly1305::Key::try_from(&key.key_data[..32]).unwrap(),
420                );
421                cipher
422                    .decrypt_inout_detached(
423                        &chacha20poly1305::Nonce::try_from(iv).unwrap(),
424                        aad,
425                        (&mut buffer[..]).into(),
426                        &chacha20poly1305::Tag::try_from(tag).unwrap(),
427                    )
428                    .map_err(|e| CryptographicError::DecryptionError(e.to_string()))?;
429            }
430            EncryptionAlgorithm::XChaCha20Poly1305 => {
431                use chacha20poly1305::XChaCha20Poly1305;
432                let cipher = XChaCha20Poly1305::new(
433                    &chacha20poly1305::Key::try_from(&key.key_data[..32]).unwrap(),
434                );
435                cipher
436                    .decrypt_inout_detached(
437                        &chacha20poly1305::XNonce::try_from(iv).unwrap(),
438                        aad,
439                        (&mut buffer[..]).into(),
440                        &chacha20poly1305::Tag::try_from(tag).unwrap(),
441                    )
442                    .map_err(|e| CryptographicError::DecryptionError(e.to_string()))?;
443            }
444            EncryptionAlgorithm::Custom(name) => {
445                return Err(CryptographicError::UnsupportedAlgorithm(format!(
446                    "Custom cipher '{name}' not implemented"
447                )));
448            }
449        }
450        Ok(buffer)
451    }
452}
453
454impl KeyDerivation {
455    pub fn new() -> Self {
456        Self {
457            derivation_functions: HashMap::new(),
458            derivation_parameters: DerivationParameters {
459                salt: vec![0u8; 16],
460                iterations: 100000,
461                memory_cost: 65536,
462                parallelism: 4,
463                output_length: 32,
464            },
465        }
466    }
467
468    pub fn initialize(&mut self) -> Result<(), CryptographicError> {
469        Ok(())
470    }
471
472    /// Register a derivation function under a named key.
473    pub fn add_derivation_function(&mut self, name: String, function: DerivationFunction) {
474        self.derivation_functions.insert(name, function);
475    }
476
477    /// Look up a derivation function by name.
478    pub fn get_derivation_function(&self, name: &str) -> Option<&DerivationFunction> {
479        self.derivation_functions.get(name)
480    }
481
482    /// Iterate over all registered derivation function names.
483    pub fn list_derivation_functions(
484        &self,
485    ) -> impl Iterator<Item = (&String, &DerivationFunction)> {
486        self.derivation_functions.iter()
487    }
488
489    /// Derive `output_length` bytes from input keying material using HKDF-SHA256.
490    ///
491    /// Uses the configured `derivation_parameters.salt` and `output_length`. `info`
492    /// is the application-specific context/label that domain-separates derived keys.
493    pub fn derive_hkdf(&self, ikm: &[u8], info: &[u8]) -> Result<Vec<u8>, CryptographicError> {
494        use hkdf::Hkdf;
495        use sha2::Sha256;
496        let hk = Hkdf::<Sha256>::new(Some(&self.derivation_parameters.salt), ikm);
497        let mut okm = vec![0u8; self.derivation_parameters.output_length];
498        hk.expand(info, &mut okm)
499            .map_err(|e| CryptographicError::EncryptionError(format!("HKDF expand failed: {e}")))?;
500        Ok(okm)
501    }
502}
503
504impl EncryptionPerformanceOptimizer {
505    pub fn new() -> Self {
506        Self {
507            optimization_strategies: vec![
508                EncryptionOptimizationStrategy::BatchEncryption,
509                EncryptionOptimizationStrategy::ParallelProcessing,
510            ],
511            performance_metrics: EncryptionPerformanceMetrics {
512                average_encryption_time: 0.0,
513                average_decryption_time: 0.0,
514                throughput: 0.0,
515                memory_usage: 0,
516                cache_hit_rate: 0.0,
517            },
518        }
519    }
520
521    pub fn initialize(&mut self) -> Result<(), CryptographicError> {
522        Ok(())
523    }
524
525    /// Get the configured optimization strategies.
526    pub fn optimization_strategies(&self) -> &[EncryptionOptimizationStrategy] {
527        &self.optimization_strategies
528    }
529
530    /// Add an optimization strategy if not already present.
531    pub fn add_optimization_strategy(&mut self, strategy: EncryptionOptimizationStrategy) {
532        if !self.optimization_strategies.contains(&strategy) {
533            self.optimization_strategies.push(strategy);
534        }
535    }
536
537    /// Record an encryption operation duration (milliseconds).
538    pub fn record_encryption_time(&mut self, duration_ms: f64) {
539        let m = &mut self.performance_metrics;
540        if m.average_encryption_time == 0.0 {
541            m.average_encryption_time = duration_ms;
542        } else {
543            m.average_encryption_time = 0.9 * m.average_encryption_time + 0.1 * duration_ms;
544        }
545        if m.average_encryption_time > 0.0 {
546            m.throughput = 1000.0 / m.average_encryption_time;
547        }
548    }
549
550    /// Record a decryption operation duration (milliseconds).
551    pub fn record_decryption_time(&mut self, duration_ms: f64) {
552        let m = &mut self.performance_metrics;
553        if m.average_decryption_time == 0.0 {
554            m.average_decryption_time = duration_ms;
555        } else {
556            m.average_decryption_time = 0.9 * m.average_decryption_time + 0.1 * duration_ms;
557        }
558    }
559
560    /// Get a snapshot of the current performance metrics.
561    pub fn metrics(&self) -> &EncryptionPerformanceMetrics {
562        &self.performance_metrics
563    }
564}
565
566impl EncryptionPerformanceMetrics {
567    pub fn new() -> Self {
568        Self {
569            average_encryption_time: 0.0,
570            average_decryption_time: 0.0,
571            throughput: 0.0,
572            memory_usage: 0,
573            cache_hit_rate: 0.0,
574        }
575    }
576}