eventuali_core/security/
encryption.rs

1use crate::{EventData, EventualiError, Result};
2use base64::{Engine as _, engine::general_purpose};
3use serde::{Deserialize, Serialize};
4use sha2::{Digest, Sha256};
5use std::collections::HashMap;
6
7/// AES-256-GCM encryption implementation for event data
8pub struct EventEncryption {
9    key_manager: KeyManager,
10}
11
12/// Key management system for encryption keys
13#[derive(Debug, Clone)]
14pub struct KeyManager {
15    keys: HashMap<String, EncryptionKey>,
16    default_key_id: String,
17}
18
19/// Encryption key with metadata
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct EncryptionKey {
22    pub id: String,
23    pub key_data: Vec<u8>, // 32 bytes for AES-256
24    pub created_at: chrono::DateTime<chrono::Utc>,
25    pub algorithm: EncryptionAlgorithm,
26}
27
28/// Supported encryption algorithms
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
30pub enum EncryptionAlgorithm {
31    Aes256Gcm,
32}
33
34/// Encrypted event data with metadata
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36pub struct EncryptedEventData {
37    pub algorithm: EncryptionAlgorithm,
38    pub key_id: String,
39    pub iv: Vec<u8>,
40    pub encrypted_data: Vec<u8>,
41    pub tag: Vec<u8>,
42}
43
44impl EventEncryption {
45    /// Create new encryption instance with a key manager
46    pub fn new(key_manager: KeyManager) -> Self {
47        Self { key_manager }
48    }
49
50    /// Create a new encryption instance with a single key
51    pub fn with_key(key_id: String, key_data: Vec<u8>) -> Result<Self> {
52        let mut keys = HashMap::new();
53        let encryption_key = EncryptionKey {
54            id: key_id.clone(),
55            key_data,
56            created_at: chrono::Utc::now(),
57            algorithm: EncryptionAlgorithm::Aes256Gcm,
58        };
59        keys.insert(key_id.clone(), encryption_key);
60        
61        let key_manager = KeyManager {
62            keys,
63            default_key_id: key_id,
64        };
65        
66        Ok(Self::new(key_manager))
67    }
68
69    /// Encrypt event data using the default key
70    pub fn encrypt_event_data(&self, data: &EventData) -> Result<EncryptedEventData> {
71        self.encrypt_event_data_with_key(data, &self.key_manager.default_key_id)
72    }
73
74    /// Encrypt event data using a specific key
75    pub fn encrypt_event_data_with_key(&self, data: &EventData, key_id: &str) -> Result<EncryptedEventData> {
76        let key = self.key_manager.get_key(key_id)?;
77        let plaintext = self.serialize_event_data(data)?;
78        
79        // Generate random IV (12 bytes for GCM)
80        let iv = self.generate_iv()?;
81        
82        // Encrypt using AES-256-GCM
83        let (encrypted_data, tag) = self.encrypt_aes_256_gcm(&plaintext, &key.key_data, &iv)?;
84        
85        Ok(EncryptedEventData {
86            algorithm: EncryptionAlgorithm::Aes256Gcm,
87            key_id: key_id.to_string(),
88            iv,
89            encrypted_data,
90            tag,
91        })
92    }
93
94    /// Decrypt event data
95    pub fn decrypt_event_data(&self, encrypted_data: &EncryptedEventData) -> Result<EventData> {
96        let key = self.key_manager.get_key(&encrypted_data.key_id)?;
97        
98        match encrypted_data.algorithm {
99            EncryptionAlgorithm::Aes256Gcm => {
100                let plaintext = self.decrypt_aes_256_gcm(
101                    &encrypted_data.encrypted_data,
102                    &key.key_data,
103                    &encrypted_data.iv,
104                    &encrypted_data.tag,
105                )?;
106                self.deserialize_event_data(&plaintext)
107            }
108        }
109    }
110
111    /// Serialize event data to bytes for encryption
112    fn serialize_event_data(&self, data: &EventData) -> Result<Vec<u8>> {
113        match data {
114            EventData::Json(value) => {
115                let json_string = serde_json::to_string(value)?;
116                Ok(json_string.into_bytes())
117            }
118            EventData::Protobuf(bytes) => Ok(bytes.clone()),
119        }
120    }
121
122    /// Deserialize event data from decrypted bytes
123    fn deserialize_event_data(&self, bytes: &[u8]) -> Result<EventData> {
124        // Try to parse as JSON first, fallback to protobuf
125        if let Ok(json_str) = std::str::from_utf8(bytes) {
126            if let Ok(json_value) = serde_json::from_str(json_str) {
127                return Ok(EventData::Json(json_value));
128            }
129        }
130        // Fallback to protobuf
131        Ok(EventData::Protobuf(bytes.to_vec()))
132    }
133
134    /// Generate a random IV for AES-GCM
135    fn generate_iv(&self) -> Result<Vec<u8>> {
136        use std::time::{SystemTime, UNIX_EPOCH};
137        
138        // Generate a 12-byte IV using system time and random data
139        let timestamp = SystemTime::now()
140            .duration_since(UNIX_EPOCH)
141            .map_err(|e| EventualiError::Encryption(format!("Time error: {e}")))?
142            .as_nanos() as u64;
143        
144        let mut iv = Vec::with_capacity(12);
145        iv.extend_from_slice(&timestamp.to_be_bytes());
146        
147        // Add 4 more random bytes using a simple PRNG
148        let random_seed = (timestamp.wrapping_mul(1103515245).wrapping_add(12345)) % (1u64 << 31);
149        iv.extend_from_slice(&(random_seed as u32).to_be_bytes());
150        
151        Ok(iv)
152    }
153
154    /// Encrypt data using AES-256-GCM
155    fn encrypt_aes_256_gcm(&self, plaintext: &[u8], key: &[u8], iv: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
156        use aes_gcm::{Aes256Gcm, KeyInit, Nonce};
157        use aes_gcm::aead::{Aead, generic_array::GenericArray};
158        
159        let cipher = Aes256Gcm::new(GenericArray::from_slice(key));
160        let nonce = Nonce::from_slice(iv);
161        
162        let ciphertext = cipher
163            .encrypt(nonce, plaintext)
164            .map_err(|e| EventualiError::Encryption(format!("AES-256-GCM encryption failed: {e}")))?;
165        
166        // Extract tag (last 16 bytes)
167        let tag_start = ciphertext.len() - 16;
168        let encrypted_data = ciphertext[..tag_start].to_vec();
169        let tag = ciphertext[tag_start..].to_vec();
170        
171        Ok((encrypted_data, tag))
172    }
173
174    /// Decrypt data using AES-256-GCM
175    fn decrypt_aes_256_gcm(&self, ciphertext: &[u8], key: &[u8], iv: &[u8], tag: &[u8]) -> Result<Vec<u8>> {
176        use aes_gcm::{Aes256Gcm, KeyInit, Nonce};
177        use aes_gcm::aead::{Aead, generic_array::GenericArray};
178        
179        let cipher = Aes256Gcm::new(GenericArray::from_slice(key));
180        let nonce = Nonce::from_slice(iv);
181        
182        // Reconstruct full ciphertext with tag
183        let mut full_ciphertext = ciphertext.to_vec();
184        full_ciphertext.extend_from_slice(tag);
185        
186        let plaintext = cipher
187            .decrypt(nonce, full_ciphertext.as_ref())
188            .map_err(|e| EventualiError::Encryption(format!("AES-256-GCM decryption failed: {e}")))?;
189        
190        Ok(plaintext)
191    }
192}
193
194impl KeyManager {
195    /// Create a new key manager
196    pub fn new() -> Self {
197        Self {
198            keys: HashMap::new(),
199            default_key_id: String::new(),
200        }
201    }
202
203    /// Add a key to the manager
204    pub fn add_key(&mut self, key: EncryptionKey) -> Result<()> {
205        if key.key_data.len() != 32 {
206            return Err(EventualiError::Encryption(
207                "AES-256 requires 32-byte keys".to_string()
208            ));
209        }
210        
211        if self.keys.is_empty() {
212            self.default_key_id = key.id.clone();
213        }
214        
215        self.keys.insert(key.id.clone(), key);
216        Ok(())
217    }
218
219    /// Generate a new AES-256 key
220    pub fn generate_key(id: String) -> Result<EncryptionKey> {
221        let key_data = Self::generate_random_key()?;
222        Ok(EncryptionKey {
223            id,
224            key_data,
225            created_at: chrono::Utc::now(),
226            algorithm: EncryptionAlgorithm::Aes256Gcm,
227        })
228    }
229
230    /// Generate a key from a password using PBKDF2
231    pub fn derive_key_from_password(id: String, password: &str, salt: &[u8]) -> Result<EncryptionKey> {
232        use pbkdf2::{pbkdf2_hmac};
233        use sha2::Sha256;
234        
235        let mut key_data = [0u8; 32];
236        pbkdf2_hmac::<Sha256>(password.as_bytes(), salt, 100_000, &mut key_data);
237        
238        Ok(EncryptionKey {
239            id,
240            key_data: key_data.to_vec(),
241            created_at: chrono::Utc::now(),
242            algorithm: EncryptionAlgorithm::Aes256Gcm,
243        })
244    }
245
246    /// Get a key by ID
247    pub fn get_key(&self, key_id: &str) -> Result<&EncryptionKey> {
248        self.keys.get(key_id).ok_or_else(|| {
249            EventualiError::Encryption(format!("Key not found: {key_id}"))
250        })
251    }
252
253    /// Set the default key
254    pub fn set_default_key(&mut self, key_id: &str) -> Result<()> {
255        if !self.keys.contains_key(key_id) {
256            return Err(EventualiError::Encryption(
257                format!("Key not found: {key_id}")
258            ));
259        }
260        self.default_key_id = key_id.to_string();
261        Ok(())
262    }
263
264    /// Generate a cryptographically secure random 32-byte key
265    fn generate_random_key() -> Result<Vec<u8>> {
266        use std::time::{SystemTime, UNIX_EPOCH};
267        
268        // Use system time as seed for key generation
269        let timestamp = SystemTime::now()
270            .duration_since(UNIX_EPOCH)
271            .map_err(|e| EventualiError::Encryption(format!("Time error: {e}")))?
272            .as_nanos();
273        
274        // Generate key using SHA-256 of timestamp and additional entropy
275        let mut hasher = Sha256::new();
276        hasher.update(timestamp.to_be_bytes());
277        hasher.update(b"eventuali-encryption-key");
278        
279        // Add more entropy from process ID and memory address
280        let pid = std::process::id();
281        hasher.update(pid.to_be_bytes());
282        
283        // Use stack address for additional entropy
284        let stack_var: u64 = 42;
285        let stack_addr = &stack_var as *const u64 as usize;
286        hasher.update(stack_addr.to_be_bytes());
287        
288        let key_hash = hasher.finalize();
289        Ok(key_hash.to_vec())
290    }
291}
292
293impl Default for KeyManager {
294    fn default() -> Self {
295        Self::new()
296    }
297}
298
299/// Encrypted event data serialization methods
300impl EncryptedEventData {
301    /// Serialize to base64 string for storage
302    pub fn to_base64(&self) -> String {
303        let serialized = serde_json::to_vec(self).unwrap_or_default();
304        general_purpose::STANDARD.encode(serialized)
305    }
306
307    /// Deserialize from base64 string
308    pub fn from_base64(data: &str) -> Result<Self> {
309        let bytes = general_purpose::STANDARD
310            .decode(data)
311            .map_err(|e| EventualiError::Encryption(format!("Base64 decode error: {e}")))?;
312        
313        serde_json::from_slice(&bytes)
314            .map_err(EventualiError::from)
315    }
316}
317
318#[cfg(test)]
319mod tests {
320    use super::*;
321    use serde_json::json;
322
323    #[test]
324    fn test_key_generation() {
325        let key = KeyManager::generate_key("test-key".to_string()).unwrap();
326        assert_eq!(key.key_data.len(), 32);
327        assert_eq!(key.id, "test-key");
328        assert_eq!(key.algorithm, EncryptionAlgorithm::Aes256Gcm);
329    }
330
331    #[test]
332    fn test_password_key_derivation() {
333        let salt = b"test-salt";
334        let key = KeyManager::derive_key_from_password(
335            "test-key".to_string(),
336            "test-password",
337            salt
338        ).unwrap();
339        
340        assert_eq!(key.key_data.len(), 32);
341        
342        // Same password and salt should produce same key
343        let key2 = KeyManager::derive_key_from_password(
344            "test-key-2".to_string(),
345            "test-password",
346            salt
347        ).unwrap();
348        
349        assert_eq!(key.key_data, key2.key_data);
350    }
351
352    #[test]
353    fn test_json_encryption_decryption() {
354        let key = KeyManager::generate_key("test-key".to_string()).unwrap();
355        let encryption = EventEncryption::with_key("test-key".to_string(), key.key_data).unwrap();
356        
357        let original_data = EventData::Json(json!({
358            "user_id": "user123",
359            "action": "create_order",
360            "amount": 100.50
361        }));
362        
363        let encrypted = encryption.encrypt_event_data(&original_data).unwrap();
364        assert_eq!(encrypted.algorithm, EncryptionAlgorithm::Aes256Gcm);
365        assert_eq!(encrypted.key_id, "test-key");
366        assert_eq!(encrypted.iv.len(), 12);
367        assert!(!encrypted.encrypted_data.is_empty());
368        assert_eq!(encrypted.tag.len(), 16);
369        
370        let decrypted = encryption.decrypt_event_data(&encrypted).unwrap();
371        assert_eq!(original_data, decrypted);
372    }
373
374    #[test]
375    fn test_protobuf_encryption_decryption() {
376        let key = KeyManager::generate_key("test-key".to_string()).unwrap();
377        let encryption = EventEncryption::with_key("test-key".to_string(), key.key_data).unwrap();
378        
379        let original_data = EventData::Protobuf(vec![0x08, 0x96, 0x01, 0x12, 0x04, 0x74, 0x65, 0x73, 0x74]);
380        
381        let encrypted = encryption.encrypt_event_data(&original_data).unwrap();
382        let decrypted = encryption.decrypt_event_data(&encrypted).unwrap();
383        
384        assert_eq!(original_data, decrypted);
385    }
386
387    #[test]
388    fn test_multiple_keys() {
389        let mut key_manager = KeyManager::new();
390        
391        let key1 = KeyManager::generate_key("key1".to_string()).unwrap();
392        let key2 = KeyManager::generate_key("key2".to_string()).unwrap();
393        
394        key_manager.add_key(key1.clone()).unwrap();
395        key_manager.add_key(key2.clone()).unwrap();
396        
397        let encryption = EventEncryption::new(key_manager);
398        let data = EventData::Json(json!({"test": "data"}));
399        
400        let encrypted1 = encryption.encrypt_event_data_with_key(&data, "key1").unwrap();
401        let encrypted2 = encryption.encrypt_event_data_with_key(&data, "key2").unwrap();
402        
403        assert_eq!(encrypted1.key_id, "key1");
404        assert_eq!(encrypted2.key_id, "key2");
405        
406        let decrypted1 = encryption.decrypt_event_data(&encrypted1).unwrap();
407        let decrypted2 = encryption.decrypt_event_data(&encrypted2).unwrap();
408        
409        assert_eq!(data, decrypted1);
410        assert_eq!(data, decrypted2);
411    }
412
413    #[test]
414    fn test_base64_serialization() {
415        let key = KeyManager::generate_key("test-key".to_string()).unwrap();
416        let encryption = EventEncryption::with_key("test-key".to_string(), key.key_data).unwrap();
417        
418        let data = EventData::Json(json!({"test": "data"}));
419        let encrypted = encryption.encrypt_event_data(&data).unwrap();
420        
421        let base64_str = encrypted.to_base64();
422        assert!(!base64_str.is_empty());
423        
424        let deserialized = EncryptedEventData::from_base64(&base64_str).unwrap();
425        assert_eq!(encrypted, deserialized);
426        
427        let decrypted = encryption.decrypt_event_data(&deserialized).unwrap();
428        assert_eq!(data, decrypted);
429    }
430}