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        use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
87        
88        let key = Key::<Aes256Gcm>::from_slice(key_data);
89        let cipher = Aes256Gcm::new(key);
90        
91        // Generate random nonce
92        let mut nonce_bytes = [0u8; 12];
93        OsRng.fill(&mut nonce_bytes);
94        let nonce = Nonce::from_slice(&nonce_bytes);
95        
96        // Encrypt data
97        let ciphertext = cipher.encrypt(nonce, data)
98            .map_err(|e| SyncError::EncryptionError(format!("AES-256 encryption failed: {}", e)))?;
99        
100        // Prepend nonce to ciphertext
101        let mut result = nonce_bytes.to_vec();
102        result.extend_from_slice(&ciphertext);
103        
104        Ok(result)
105    }
106
107    /// Decrypt data using AES-256-GCM
108    async fn decrypt_aes256(&self, encrypted_data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, SyncError> {
109        use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
110        
111        if encrypted_data.len() < 12 {
112            return Err(SyncError::EncryptionError("Invalid encrypted data length".to_string()));
113        }
114
115        let key = Key::<Aes256Gcm>::from_slice(key_data);
116        let cipher = Aes256Gcm::new(key);
117        
118        // Extract nonce and ciphertext
119        let nonce = Nonce::from_slice(&encrypted_data[..12]);
120        let ciphertext = &encrypted_data[12..];
121        
122        // Decrypt data
123        let plaintext = cipher.decrypt(nonce, ciphertext)
124            .map_err(|e| SyncError::EncryptionError(format!("AES-256 decryption failed: {}", e)))?;
125        
126        Ok(plaintext)
127    }
128
129    /// Encrypt data using AES-128-GCM
130    async fn encrypt_aes128(&self, data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, SyncError> {
131        use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
132        
133        // Use AES-256-GCM with 128-bit key (first 16 bytes)
134        let key = Key::<Aes256Gcm>::from_slice(&key_data[..16]);
135        let cipher = Aes256Gcm::new(key);
136        
137        let mut nonce_bytes = [0u8; 12];
138        OsRng.fill(&mut nonce_bytes);
139        let nonce = Nonce::from_slice(&nonce_bytes);
140        
141        let ciphertext = cipher.encrypt(nonce, data)
142            .map_err(|e| SyncError::EncryptionError(format!("AES-128 encryption failed: {}", e)))?;
143        
144        let mut result = nonce_bytes.to_vec();
145        result.extend_from_slice(&ciphertext);
146        
147        Ok(result)
148    }
149
150    /// Decrypt data using AES-128-GCM
151    async fn decrypt_aes128(&self, encrypted_data: &[u8], key_data: &[u8]) -> Result<Vec<u8>, SyncError> {
152        use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
153        
154        if encrypted_data.len() < 12 {
155            return Err(SyncError::EncryptionError("Invalid encrypted data length".to_string()));
156        }
157
158        let key = Key::<Aes256Gcm>::from_slice(&key_data[..16]);
159        let cipher = Aes256Gcm::new(key);
160        
161        let nonce = Nonce::from_slice(&encrypted_data[..12]);
162        let ciphertext = &encrypted_data[12..];
163        
164        let plaintext = cipher.decrypt(nonce, ciphertext)
165            .map_err(|e| SyncError::EncryptionError(format!("AES-128 decryption failed: {}", e)))?;
166        
167        Ok(plaintext)
168    }
169
170}
171
172/// Key manager for generating, rotating, and managing encryption keys
173pub struct KeyManager {
174    key_store: RwLock<HashMap<String, EncryptionKey>>,
175}
176
177impl KeyManager {
178    /// Create a new key manager
179    pub fn new() -> Self {
180        Self {
181            key_store: RwLock::new(HashMap::new()),
182        }
183    }
184
185    /// Generate a new encryption key
186    pub async fn generate_key(&self, algorithm: EncryptionAlgorithm) -> Result<EncryptionKey, SyncError> {
187        let key_id = self.generate_key_id();
188        let key_data = match algorithm {
189            EncryptionAlgorithm::Aes256 => self.generate_aes256_key().await?,
190            EncryptionAlgorithm::Aes128 => self.generate_aes128_key().await?,
191        };
192
193        let key = EncryptionKey {
194            id: key_id.clone(),
195            algorithm,
196            key_data,
197            created_at: Utc::now(),
198            expires_at: None,
199            version: 1,
200        };
201
202        // Store key
203        let mut store = self.key_store.write().await;
204        store.insert(key_id, key.clone());
205
206        Ok(key)
207    }
208
209
210    /// Rotate an existing key
211    pub async fn rotate_key(&self, old_key: &EncryptionKey) -> Result<EncryptionKey, SyncError> {
212        let new_key = self.generate_key(old_key.algorithm.clone()).await?;
213        
214        // Mark old key as expired
215        let mut store = self.key_store.write().await;
216        if let Some(existing_key) = store.get_mut(&old_key.id) {
217            existing_key.expires_at = Some(Utc::now());
218        }
219
220        Ok(new_key)
221    }
222
223    /// Derive key from password using SHA-256
224    pub async fn derive_key_from_password(&self, password: &str, salt: &[u8]) -> Result<Vec<u8>, SyncError> {
225        use sha2::{Sha256, Digest};
226        
227        let mut hasher = Sha256::new();
228        hasher.update(password.as_bytes());
229        hasher.update(salt);
230        let derived_key = hasher.finalize().to_vec();
231        
232        Ok(derived_key)
233    }
234
235    /// Generate AES-256 key
236    async fn generate_aes256_key(&self) -> Result<Vec<u8>, SyncError> {
237        let mut key = [0u8; 32];
238        OsRng.fill(&mut key);
239        Ok(key.to_vec())
240    }
241
242    /// Generate AES-128 key
243    async fn generate_aes128_key(&self) -> Result<Vec<u8>, SyncError> {
244        let mut key = [0u8; 16];
245        OsRng.fill(&mut key);
246        Ok(key.to_vec())
247    }
248
249
250    /// Generate unique key ID
251    fn generate_key_id(&self) -> String {
252        let mut rng = OsRng;
253        let random_bytes: [u8; 16] = rng.r#gen();
254        format!("key_{}", general_purpose::STANDARD.encode(random_bytes))
255    }
256
257    /// Get key by ID
258    pub async fn get_key(&self, key_id: &str) -> Option<EncryptionKey> {
259        let store = self.key_store.read().await;
260        store.get(key_id).cloned()
261    }
262
263    /// Revoke key
264    pub async fn revoke_key(&self, key_id: &str) -> Result<(), SyncError> {
265        let mut store = self.key_store.write().await;
266        if let Some(key) = store.get_mut(key_id) {
267            key.expires_at = Some(Utc::now());
268            Ok(())
269        } else {
270            Err(SyncError::EncryptionError("Key not found".to_string()))
271        }
272    }
273
274    /// List all keys
275    pub async fn list_keys(&self) -> Vec<EncryptionKey> {
276        let store = self.key_store.read().await;
277        store.values().cloned().collect()
278    }
279
280    /// Clean up expired keys
281    pub async fn cleanup_expired_keys(&self) -> usize {
282        let mut store = self.key_store.write().await;
283        let now = Utc::now();
284        let expired_keys: Vec<String> = store
285            .iter()
286            .filter(|(_, key)| key.expires_at.map_or(false, |expires| expires < now))
287            .map(|(id, _)| id.clone())
288            .collect();
289        
290        for key_id in &expired_keys {
291            store.remove(key_id);
292        }
293        
294        expired_keys.len()
295    }
296}
297
298#[cfg(test)]
299mod tests {
300    use super::*;
301
302    #[tokio::test]
303    async fn test_aes256_encryption_decryption() {
304        let key_manager = KeyManager::new();
305        let encryption_manager = EncryptionManager::new(EncryptionAlgorithm::Aes256);
306        
307        let plaintext = b"Hello, World! This is a test message.";
308        let key = key_manager.generate_key(EncryptionAlgorithm::Aes256).await.unwrap();
309        
310        // Encrypt
311        let encrypted = encryption_manager.encrypt(plaintext, &key).await.unwrap();
312        assert_ne!(encrypted, plaintext);
313        
314        // Decrypt
315        let decrypted = encryption_manager.decrypt(&encrypted, &key).await.unwrap();
316        assert_eq!(decrypted, plaintext);
317    }
318
319    #[tokio::test]
320    async fn test_key_rotation() {
321        let key_manager = KeyManager::new();
322        let encryption_manager = EncryptionManager::new(EncryptionAlgorithm::Aes256);
323        
324        let plaintext = b"Test data for key rotation";
325        
326        // Generate initial key
327        let key1 = key_manager.generate_key(EncryptionAlgorithm::Aes256).await.unwrap();
328        let encrypted1 = encryption_manager.encrypt(plaintext, &key1).await.unwrap();
329        
330        // Rotate key
331        let key2 = key_manager.rotate_key(&key1).await.unwrap();
332        let encrypted2 = encryption_manager.encrypt(plaintext, &key2).await.unwrap();
333        
334        // Verify both keys work
335        let decrypted1 = encryption_manager.decrypt(&encrypted1, &key1).await.unwrap();
336        let decrypted2 = encryption_manager.decrypt(&encrypted2, &key2).await.unwrap();
337        
338        assert_eq!(decrypted1, plaintext);
339        assert_eq!(decrypted2, plaintext);
340        assert_ne!(encrypted1, encrypted2);
341    }
342
343    #[tokio::test]
344    async fn test_password_derivation() {
345        let key_manager = KeyManager::new();
346        let password = "test_password_123";
347        let salt = b"test_salt";
348        
349        let derived_key = key_manager.derive_key_from_password(password, salt).await.unwrap();
350        assert!(!derived_key.is_empty());
351        
352        // Same password and salt should produce same key
353        let derived_key2 = key_manager.derive_key_from_password(password, salt).await.unwrap();
354        assert_eq!(derived_key, derived_key2);
355    }
356}