leptos_sync_core/security/
encryption.rs

1//! Encryption functionality with comprehensive algorithm support
2
3use crate::SyncError;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use tokio::sync::RwLock;
7use chrono::{DateTime, Utc};
8use rand::{Rng, rngs::OsRng};
9use base64::{Engine as _, engine::general_purpose};
10
11/// Encryption algorithms supported by the system
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum EncryptionAlgorithm {
14    Aes256,
15    Aes128,
16}
17
18/// Encryption key with metadata
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct EncryptionKey {
21    pub id: String,
22    pub algorithm: EncryptionAlgorithm,
23    pub key_data: Vec<u8>,
24    pub created_at: DateTime<Utc>,
25    pub expires_at: Option<DateTime<Utc>>,
26    pub version: u32,
27}
28
29/// Encryption manager for handling various encryption algorithms
30pub struct EncryptionManager {
31    algorithm: EncryptionAlgorithm,
32}
33
34impl EncryptionManager {
35    /// Create a new encryption manager
36    pub fn new(algorithm: EncryptionAlgorithm) -> Self {
37        Self { algorithm }
38    }
39
40    /// Encrypt data with the specified key
41    pub async fn encrypt(&self, data: &[u8], key: &EncryptionKey) -> Result<Vec<u8>, SyncError> {
42        if key.algorithm != self.algorithm {
43            return Err(SyncError::EncryptionError(format!(
44                "Key algorithm {:?} does not match manager algorithm {:?}",
45                key.algorithm, self.algorithm
46            )));
47        }
48
49        // Check if key is expired
50        if let Some(expires_at) = key.expires_at {
51            if Utc::now() > expires_at {
52                return Err(SyncError::EncryptionError("Key has expired".to_string()));
53            }
54        }
55
56        match self.algorithm {
57            EncryptionAlgorithm::Aes256 => self.encrypt_aes256(data, &key.key_data).await,
58            EncryptionAlgorithm::Aes128 => self.encrypt_aes128(data, &key.key_data).await,
59        }
60    }
61
62    /// Decrypt data with the specified key
63    pub async fn decrypt(&self, encrypted_data: &[u8], key: &EncryptionKey) -> Result<Vec<u8>, SyncError> {
64        if key.algorithm != self.algorithm {
65            return Err(SyncError::EncryptionError(format!(
66                "Key algorithm {:?} does not match manager algorithm {:?}",
67                key.algorithm, self.algorithm
68            )));
69        }
70
71        // Check if key is expired
72        if let Some(expires_at) = key.expires_at {
73            if Utc::now() > expires_at {
74                return Err(SyncError::EncryptionError("Key has expired".to_string()));
75            }
76        }
77
78        match self.algorithm {
79            EncryptionAlgorithm::Aes256 => self.decrypt_aes256(encrypted_data, &key.key_data).await,
80            EncryptionAlgorithm::Aes128 => self.decrypt_aes128(encrypted_data, &key.key_data).await,
81        }
82    }
83
84    /// Encrypt data using AES-256-GCM
85    async fn encrypt_aes256(&self, data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, SyncError> {
86        #[cfg(feature = "encryption")]
87        {
88            use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
89            
90            let key = Key::<Aes256Gcm>::from_slice(key_data);
91            let cipher = Aes256Gcm::new(key);
92            
93            // Generate random nonce
94            let mut nonce_bytes = [0u8; 12];
95            OsRng.fill(&mut nonce_bytes);
96            let nonce = Nonce::from_slice(&nonce_bytes);
97            
98            // Encrypt data
99            let ciphertext = cipher.encrypt(nonce, data)
100                .map_err(|e| SyncError::EncryptionError(format!("AES-256 encryption failed: {}", e)))?;
101            
102            // Prepend nonce to ciphertext
103            let mut result = nonce_bytes.to_vec();
104            result.extend_from_slice(&ciphertext);
105            
106            Ok(result)
107        }
108        #[cfg(not(feature = "encryption"))]
109        {
110            Err(SyncError::EncryptionError("Encryption feature not enabled".to_string()))
111        }
112    }
113
114    /// Decrypt data using AES-256-GCM
115    async fn decrypt_aes256(&self, encrypted_data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, SyncError> {
116        #[cfg(feature = "encryption")]
117        {
118            use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
119            
120            if encrypted_data.len() < 12 {
121                return Err(SyncError::EncryptionError("Invalid encrypted data length".to_string()));
122            }
123
124            let key = Key::<Aes256Gcm>::from_slice(key_data);
125            let cipher = Aes256Gcm::new(key);
126            
127            // Extract nonce and ciphertext
128            let nonce = Nonce::from_slice(&encrypted_data[..12]);
129            let ciphertext = &encrypted_data[12..];
130            
131            // Decrypt data
132            let plaintext = cipher.decrypt(nonce, ciphertext)
133                .map_err(|e| SyncError::EncryptionError(format!("AES-256 decryption failed: {}", e)))?;
134            
135            Ok(plaintext)
136        }
137        #[cfg(not(feature = "encryption"))]
138        {
139            Err(SyncError::EncryptionError("Encryption feature not enabled".to_string()))
140        }
141    }
142
143    /// Encrypt data using AES-128-GCM
144    async fn encrypt_aes128(&self, data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, SyncError> {
145        #[cfg(feature = "encryption")]
146        {
147            use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
148            
149            // Use AES-256-GCM with 128-bit key (first 16 bytes)
150            let key = Key::<Aes256Gcm>::from_slice(&key_data[..16]);
151            let cipher = Aes256Gcm::new(key);
152            
153            let mut nonce_bytes = [0u8; 12];
154            OsRng.fill(&mut nonce_bytes);
155            let nonce = Nonce::from_slice(&nonce_bytes);
156            
157            let ciphertext = cipher.encrypt(nonce, data)
158                .map_err(|e| SyncError::EncryptionError(format!("AES-128 encryption failed: {}", e)))?;
159            
160            let mut result = nonce_bytes.to_vec();
161            result.extend_from_slice(&ciphertext);
162            
163            Ok(result)
164        }
165        #[cfg(not(feature = "encryption"))]
166        {
167            Err(SyncError::EncryptionError("Encryption feature not enabled".to_string()))
168        }
169    }
170
171    /// Decrypt data using AES-128-GCM
172    async fn decrypt_aes128(&self, encrypted_data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, SyncError> {
173        #[cfg(feature = "encryption")]
174        {
175            use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
176            
177            if encrypted_data.len() < 12 {
178                return Err(SyncError::EncryptionError("Invalid encrypted data length".to_string()));
179            }
180
181            let key = Key::<Aes256Gcm>::from_slice(&key_data[..16]);
182            let cipher = Aes256Gcm::new(key);
183            
184            let nonce = Nonce::from_slice(&encrypted_data[..12]);
185            let ciphertext = &encrypted_data[12..];
186            
187            let plaintext = cipher.decrypt(nonce, ciphertext)
188                .map_err(|e| SyncError::EncryptionError(format!("AES-128 decryption failed: {}", e)))?;
189            
190            Ok(plaintext)
191        }
192        #[cfg(not(feature = "encryption"))]
193        {
194            Err(SyncError::EncryptionError("Encryption feature not enabled".to_string()))
195        }
196    }
197
198}
199
200/// Key manager for generating, rotating, and managing encryption keys
201pub struct KeyManager {
202    key_store: RwLock<HashMap<String, EncryptionKey>>,
203}
204
205impl KeyManager {
206    /// Create a new key manager
207    pub fn new() -> Self {
208        Self {
209            key_store: RwLock::new(HashMap::new()),
210        }
211    }
212
213    /// Generate a new encryption key
214    pub async fn generate_key(&self, algorithm: EncryptionAlgorithm) -> Result<EncryptionKey, SyncError> {
215        let key_id = self.generate_key_id();
216        let key_data = match algorithm {
217            EncryptionAlgorithm::Aes256 => self.generate_aes256_key().await?,
218            EncryptionAlgorithm::Aes128 => self.generate_aes128_key().await?,
219        };
220
221        let key = EncryptionKey {
222            id: key_id.clone(),
223            algorithm,
224            key_data,
225            created_at: Utc::now(),
226            expires_at: None,
227            version: 1,
228        };
229
230        // Store key
231        let mut store = self.key_store.write().await;
232        store.insert(key_id, key.clone());
233
234        Ok(key)
235    }
236
237
238    /// Rotate an existing key
239    pub async fn rotate_key(&self, old_key: &EncryptionKey) -> Result<EncryptionKey, SyncError> {
240        let new_key = self.generate_key(old_key.algorithm.clone()).await?;
241        
242        // Mark old key as expired
243        let mut store = self.key_store.write().await;
244        if let Some(existing_key) = store.get_mut(&old_key.id) {
245            existing_key.expires_at = Some(Utc::now());
246        }
247
248        Ok(new_key)
249    }
250
251    /// Derive key from password using SHA-256
252    pub async fn derive_key_from_password(&self, password: &str, salt: &[u8]) -> Result<Vec<u8>, SyncError> {
253        use sha2::{Sha256, Digest};
254        
255        let mut hasher = Sha256::new();
256        hasher.update(password.as_bytes());
257        hasher.update(salt);
258        let derived_key = hasher.finalize().to_vec();
259        
260        Ok(derived_key)
261    }
262
263    /// Generate AES-256 key
264    async fn generate_aes256_key(&self) -> Result<Vec<u8>, SyncError> {
265        let mut key = [0u8; 32];
266        OsRng.fill(&mut key);
267        Ok(key.to_vec())
268    }
269
270    /// Generate AES-128 key
271    async fn generate_aes128_key(&self) -> Result<Vec<u8>, SyncError> {
272        let mut key = [0u8; 16];
273        OsRng.fill(&mut key);
274        Ok(key.to_vec())
275    }
276
277
278    /// Generate unique key ID
279    fn generate_key_id(&self) -> String {
280        let mut rng = OsRng;
281        let random_bytes: [u8; 16] = rng.r#gen();
282        format!("key_{}", general_purpose::STANDARD.encode(random_bytes))
283    }
284
285    /// Get key by ID
286    pub async fn get_key(&self, key_id: &str) -> Option<EncryptionKey> {
287        let store = self.key_store.read().await;
288        store.get(key_id).cloned()
289    }
290
291    /// Revoke key
292    pub async fn revoke_key(&self, key_id: &str) -> Result<(), SyncError> {
293        let mut store = self.key_store.write().await;
294        if let Some(key) = store.get_mut(key_id) {
295            key.expires_at = Some(Utc::now());
296            Ok(())
297        } else {
298            Err(SyncError::EncryptionError("Key not found".to_string()))
299        }
300    }
301
302    /// List all keys
303    pub async fn list_keys(&self) -> Vec<EncryptionKey> {
304        let store = self.key_store.read().await;
305        store.values().cloned().collect()
306    }
307
308    /// Clean up expired keys
309    pub async fn cleanup_expired_keys(&self) -> usize {
310        let mut store = self.key_store.write().await;
311        let now = Utc::now();
312        let expired_keys: Vec<String> = store
313            .iter()
314            .filter(|(_, key)| key.expires_at.map_or(false, |expires| expires < now))
315            .map(|(id, _)| id.clone())
316            .collect();
317        
318        for key_id in &expired_keys {
319            store.remove(key_id);
320        }
321        
322        expired_keys.len()
323    }
324}
325
326#[cfg(test)]
327mod tests {
328    use super::*;
329
330    #[tokio::test]
331    async fn test_aes256_encryption_decryption() {
332        let key_manager = KeyManager::new();
333        let encryption_manager = EncryptionManager::new(EncryptionAlgorithm::Aes256);
334        
335        let plaintext = b"Hello, World! This is a test message.";
336        let key = key_manager.generate_key(EncryptionAlgorithm::Aes256).await.unwrap();
337        
338        // Encrypt
339        let encrypted = encryption_manager.encrypt(plaintext, &key).await.unwrap();
340        assert_ne!(encrypted, plaintext);
341        
342        // Decrypt
343        let decrypted = encryption_manager.decrypt(&encrypted, &key).await.unwrap();
344        assert_eq!(decrypted, plaintext);
345    }
346
347    #[tokio::test]
348    async fn test_key_rotation() {
349        let key_manager = KeyManager::new();
350        let encryption_manager = EncryptionManager::new(EncryptionAlgorithm::Aes256);
351        
352        let plaintext = b"Test data for key rotation";
353        
354        // Generate initial key
355        let key1 = key_manager.generate_key(EncryptionAlgorithm::Aes256).await.unwrap();
356        let encrypted1 = encryption_manager.encrypt(plaintext, &key1).await.unwrap();
357        
358        // Rotate key
359        let key2 = key_manager.rotate_key(&key1).await.unwrap();
360        let encrypted2 = encryption_manager.encrypt(plaintext, &key2).await.unwrap();
361        
362        // Verify both keys work
363        let decrypted1 = encryption_manager.decrypt(&encrypted1, &key1).await.unwrap();
364        let decrypted2 = encryption_manager.decrypt(&encrypted2, &key2).await.unwrap();
365        
366        assert_eq!(decrypted1, plaintext);
367        assert_eq!(decrypted2, plaintext);
368        assert_ne!(encrypted1, encrypted2);
369    }
370
371    #[tokio::test]
372    async fn test_password_derivation() {
373        let key_manager = KeyManager::new();
374        let password = "test_password_123";
375        let salt = b"test_salt";
376        
377        let derived_key = key_manager.derive_key_from_password(password, salt).await.unwrap();
378        assert!(!derived_key.is_empty());
379        
380        // Same password and salt should produce same key
381        let derived_key2 = key_manager.derive_key_from_password(password, salt).await.unwrap();
382        assert_eq!(derived_key, derived_key2);
383    }
384}