eventuali_core/security/
signatures.rs

1use crate::{Event, EventualiError, Result};
2use base64::{Engine as _, engine::general_purpose};
3use serde::{Deserialize, Serialize};
4use sha2::{Digest, Sha256};
5use std::collections::HashMap;
6
7/// Digital signature implementation for event integrity verification
8pub struct EventSigner {
9    key_manager: SigningKeyManager,
10}
11
12/// Signing key management system
13#[derive(Debug, Clone)]
14pub struct SigningKeyManager {
15    keys: HashMap<String, SigningKey>,
16    default_key_id: String,
17}
18
19/// Signing key with metadata
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct SigningKey {
22    pub id: String,
23    pub key_data: Vec<u8>, // HMAC signing key
24    pub created_at: chrono::DateTime<chrono::Utc>,
25    pub algorithm: SignatureAlgorithm,
26}
27
28/// Supported signature algorithms
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
30pub enum SignatureAlgorithm {
31    HmacSha256,
32    HmacSha512,
33}
34
35/// Event signature with metadata
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
37pub struct EventSignature {
38    pub algorithm: SignatureAlgorithm,
39    pub key_id: String,
40    pub signature: Vec<u8>,
41    pub timestamp: chrono::DateTime<chrono::Utc>,
42    pub event_hash: Vec<u8>, // SHA-256 of the event data for verification
43}
44
45/// Signed event data
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct SignedEvent {
48    pub event: Event,
49    pub signature: EventSignature,
50}
51
52impl EventSigner {
53    /// Create new signer instance with a key manager
54    pub fn new(key_manager: SigningKeyManager) -> Self {
55        Self { key_manager }
56    }
57
58    /// Create a new signer instance with a single key
59    pub fn with_key(key_id: String, key_data: Vec<u8>) -> Result<Self> {
60        let mut keys = HashMap::new();
61        let signing_key = SigningKey {
62            id: key_id.clone(),
63            key_data,
64            created_at: chrono::Utc::now(),
65            algorithm: SignatureAlgorithm::HmacSha256,
66        };
67        keys.insert(key_id.clone(), signing_key);
68        
69        let key_manager = SigningKeyManager {
70            keys,
71            default_key_id: key_id,
72        };
73        
74        Ok(Self::new(key_manager))
75    }
76
77    /// Sign an event using the default key
78    pub fn sign_event(&self, event: &Event) -> Result<SignedEvent> {
79        self.sign_event_with_key(event, &self.key_manager.default_key_id)
80    }
81
82    /// Sign an event using a specific key
83    pub fn sign_event_with_key(&self, event: &Event, key_id: &str) -> Result<SignedEvent> {
84        let key = self.key_manager.get_key(key_id)?;
85        let event_bytes = self.serialize_event(event)?;
86        let event_hash = self.hash_event_data(&event_bytes);
87        
88        let signature_bytes = match key.algorithm {
89            SignatureAlgorithm::HmacSha256 => self.hmac_sha256(&event_bytes, &key.key_data)?,
90            SignatureAlgorithm::HmacSha512 => self.hmac_sha512(&event_bytes, &key.key_data)?,
91        };
92        
93        let signature = EventSignature {
94            algorithm: key.algorithm.clone(),
95            key_id: key_id.to_string(),
96            signature: signature_bytes,
97            timestamp: chrono::Utc::now(),
98            event_hash,
99        };
100        
101        Ok(SignedEvent {
102            event: event.clone(),
103            signature,
104        })
105    }
106
107    /// Verify an event signature
108    pub fn verify_signature(&self, signed_event: &SignedEvent) -> Result<bool> {
109        let key = self.key_manager.get_key(&signed_event.signature.key_id)?;
110        let event_bytes = self.serialize_event(&signed_event.event)?;
111        
112        // Verify event hash first
113        let computed_hash = self.hash_event_data(&event_bytes);
114        if computed_hash != signed_event.signature.event_hash {
115            return Ok(false);
116        }
117        
118        // Compute expected signature
119        let expected_signature = match signed_event.signature.algorithm {
120            SignatureAlgorithm::HmacSha256 => self.hmac_sha256(&event_bytes, &key.key_data)?,
121            SignatureAlgorithm::HmacSha512 => self.hmac_sha512(&event_bytes, &key.key_data)?,
122        };
123        
124        // Constant-time comparison to prevent timing attacks
125        Ok(self.constant_time_compare(&expected_signature, &signed_event.signature.signature))
126    }
127
128    /// Verify signature without needing the full key manager (using provided key)
129    pub fn verify_signature_with_key(&self, signed_event: &SignedEvent, key_data: &[u8]) -> Result<bool> {
130        let event_bytes = self.serialize_event(&signed_event.event)?;
131        
132        // Verify event hash first
133        let computed_hash = self.hash_event_data(&event_bytes);
134        if computed_hash != signed_event.signature.event_hash {
135            return Ok(false);
136        }
137        
138        // Compute expected signature
139        let expected_signature = match signed_event.signature.algorithm {
140            SignatureAlgorithm::HmacSha256 => self.hmac_sha256(&event_bytes, key_data)?,
141            SignatureAlgorithm::HmacSha512 => self.hmac_sha512(&event_bytes, key_data)?,
142        };
143        
144        // Constant-time comparison
145        Ok(self.constant_time_compare(&expected_signature, &signed_event.signature.signature))
146    }
147
148    /// Create a signature for raw data (not an event)
149    pub fn sign_data(&self, data: &[u8], key_id: &str) -> Result<EventSignature> {
150        let key = self.key_manager.get_key(key_id)?;
151        let data_hash = self.hash_event_data(data);
152        
153        let signature_bytes = match key.algorithm {
154            SignatureAlgorithm::HmacSha256 => self.hmac_sha256(data, &key.key_data)?,
155            SignatureAlgorithm::HmacSha512 => self.hmac_sha512(data, &key.key_data)?,
156        };
157        
158        Ok(EventSignature {
159            algorithm: key.algorithm.clone(),
160            key_id: key_id.to_string(),
161            signature: signature_bytes,
162            timestamp: chrono::Utc::now(),
163            event_hash: data_hash,
164        })
165    }
166
167    /// Verify a signature for raw data
168    pub fn verify_data_signature(&self, data: &[u8], signature: &EventSignature) -> Result<bool> {
169        let key = self.key_manager.get_key(&signature.key_id)?;
170        
171        // Verify data hash
172        let computed_hash = self.hash_event_data(data);
173        if computed_hash != signature.event_hash {
174            return Ok(false);
175        }
176        
177        // Compute expected signature
178        let expected_signature = match signature.algorithm {
179            SignatureAlgorithm::HmacSha256 => self.hmac_sha256(data, &key.key_data)?,
180            SignatureAlgorithm::HmacSha512 => self.hmac_sha512(data, &key.key_data)?,
181        };
182        
183        Ok(self.constant_time_compare(&expected_signature, &signature.signature))
184    }
185
186    /// Serialize event to bytes for signing
187    fn serialize_event(&self, event: &Event) -> Result<Vec<u8>> {
188        serde_json::to_vec(event)
189            .map_err(EventualiError::Serialization)
190    }
191
192    /// Hash event data using SHA-256
193    fn hash_event_data(&self, data: &[u8]) -> Vec<u8> {
194        let mut hasher = Sha256::new();
195        hasher.update(data);
196        hasher.finalize().to_vec()
197    }
198
199    /// Compute HMAC-SHA256
200    fn hmac_sha256(&self, data: &[u8], key: &[u8]) -> Result<Vec<u8>> {
201        use hmac::{Hmac, Mac};
202        type HmacSha256 = Hmac<Sha256>;
203        
204        let mut mac = HmacSha256::new_from_slice(key)
205            .map_err(|e| EventualiError::Configuration(format!("Invalid HMAC key: {e}")))?;
206        mac.update(data);
207        Ok(mac.finalize().into_bytes().to_vec())
208    }
209
210    /// Compute HMAC-SHA512
211    fn hmac_sha512(&self, data: &[u8], key: &[u8]) -> Result<Vec<u8>> {
212        use hmac::{Hmac, Mac};
213        use sha2::Sha512;
214        type HmacSha512 = Hmac<Sha512>;
215        
216        let mut mac = HmacSha512::new_from_slice(key)
217            .map_err(|e| EventualiError::Configuration(format!("Invalid HMAC key: {e}")))?;
218        mac.update(data);
219        Ok(mac.finalize().into_bytes().to_vec())
220    }
221
222    /// Constant-time comparison to prevent timing attacks
223    fn constant_time_compare(&self, a: &[u8], b: &[u8]) -> bool {
224        if a.len() != b.len() {
225            return false;
226        }
227        
228        let mut result = 0u8;
229        for (byte_a, byte_b) in a.iter().zip(b.iter()) {
230            result |= byte_a ^ byte_b;
231        }
232        
233        result == 0
234    }
235}
236
237impl SigningKeyManager {
238    /// Create a new signing key manager
239    pub fn new() -> Self {
240        Self {
241            keys: HashMap::new(),
242            default_key_id: String::new(),
243        }
244    }
245
246    /// Add a key to the manager
247    pub fn add_key(&mut self, key: SigningKey) -> Result<()> {
248        if key.key_data.is_empty() {
249            return Err(EventualiError::Configuration(
250                "Signing key cannot be empty".to_string()
251            ));
252        }
253        
254        if self.keys.is_empty() {
255            self.default_key_id = key.id.clone();
256        }
257        
258        self.keys.insert(key.id.clone(), key);
259        Ok(())
260    }
261
262    /// Generate a new HMAC signing key
263    pub fn generate_key(id: String, algorithm: SignatureAlgorithm) -> Result<SigningKey> {
264        let key_data = Self::generate_random_key(algorithm.key_size())?;
265        Ok(SigningKey {
266            id,
267            key_data,
268            created_at: chrono::Utc::now(),
269            algorithm,
270        })
271    }
272
273    /// Derive a signing key from a password using PBKDF2
274    pub fn derive_key_from_password(
275        id: String,
276        password: &str,
277        salt: &[u8],
278        algorithm: SignatureAlgorithm,
279    ) -> Result<SigningKey> {
280        use pbkdf2::{pbkdf2_hmac};
281        use sha2::Sha256;
282        
283        let key_size = algorithm.key_size();
284        let mut key_data = vec![0u8; key_size];
285        pbkdf2_hmac::<Sha256>(password.as_bytes(), salt, 100_000, &mut key_data);
286        
287        Ok(SigningKey {
288            id,
289            key_data,
290            created_at: chrono::Utc::now(),
291            algorithm,
292        })
293    }
294
295    /// Get a key by ID
296    pub fn get_key(&self, key_id: &str) -> Result<&SigningKey> {
297        self.keys.get(key_id).ok_or_else(|| {
298            EventualiError::Configuration(format!("Signing key not found: {key_id}"))
299        })
300    }
301
302    /// Set the default key
303    pub fn set_default_key(&mut self, key_id: &str) -> Result<()> {
304        if !self.keys.contains_key(key_id) {
305            return Err(EventualiError::Configuration(
306                format!("Signing key not found: {key_id}")
307            ));
308        }
309        self.default_key_id = key_id.to_string();
310        Ok(())
311    }
312
313    /// List all key IDs
314    pub fn list_key_ids(&self) -> Vec<String> {
315        self.keys.keys().cloned().collect()
316    }
317
318    /// Generate a cryptographically secure random signing key
319    fn generate_random_key(size: usize) -> Result<Vec<u8>> {
320        use std::time::{SystemTime, UNIX_EPOCH};
321        
322        // Use system time as seed for key generation
323        let timestamp = SystemTime::now()
324            .duration_since(UNIX_EPOCH)
325            .map_err(|e| EventualiError::Configuration(format!("Time error: {e}")))?
326            .as_nanos();
327        
328        // Generate key using multiple SHA-256 rounds for entropy
329        let mut key = Vec::with_capacity(size);
330        let mut current_hash = timestamp.to_be_bytes().to_vec();
331        
332        while key.len() < size {
333            let mut hasher = Sha256::new();
334            hasher.update(&current_hash);
335            hasher.update(b"eventuali-signing-key");
336            hasher.update((key.len() as u64).to_be_bytes());
337            
338            // Add more entropy from process ID and memory address
339            let pid = std::process::id();
340            hasher.update(pid.to_be_bytes());
341            
342            current_hash = hasher.finalize().to_vec();
343            
344            let remaining = size - key.len();
345            if remaining >= current_hash.len() {
346                key.extend_from_slice(&current_hash);
347            } else {
348                key.extend_from_slice(&current_hash[..remaining]);
349            }
350        }
351        
352        Ok(key)
353    }
354}
355
356impl Default for SigningKeyManager {
357    fn default() -> Self {
358        Self::new()
359    }
360}
361
362impl SignatureAlgorithm {
363    /// Get the recommended key size for the algorithm
364    pub fn key_size(&self) -> usize {
365        match self {
366            SignatureAlgorithm::HmacSha256 => 32, // 256 bits
367            SignatureAlgorithm::HmacSha512 => 64, // 512 bits
368        }
369    }
370
371    /// Get the output size of the signature
372    pub fn signature_size(&self) -> usize {
373        match self {
374            SignatureAlgorithm::HmacSha256 => 32, // 256 bits
375            SignatureAlgorithm::HmacSha512 => 64, // 512 bits
376        }
377    }
378}
379
380/// Signed event data serialization methods
381impl SignedEvent {
382    /// Serialize to base64 string for storage
383    pub fn to_base64(&self) -> String {
384        let serialized = serde_json::to_vec(self).unwrap_or_default();
385        general_purpose::STANDARD.encode(serialized)
386    }
387
388    /// Deserialize from base64 string
389    pub fn from_base64(data: &str) -> Result<Self> {
390        let bytes = general_purpose::STANDARD
391            .decode(data)
392            .map_err(|e| EventualiError::Configuration(format!("Base64 decode error: {e}")))?;
393        
394        serde_json::from_slice(&bytes)
395            .map_err(EventualiError::from)
396    }
397}
398
399impl EventSignature {
400    /// Serialize to base64 string for storage
401    pub fn to_base64(&self) -> String {
402        let serialized = serde_json::to_vec(self).unwrap_or_default();
403        general_purpose::STANDARD.encode(serialized)
404    }
405
406    /// Deserialize from base64 string
407    pub fn from_base64(data: &str) -> Result<Self> {
408        let bytes = general_purpose::STANDARD
409            .decode(data)
410            .map_err(|e| EventualiError::Configuration(format!("Base64 decode error: {e}")))?;
411        
412        serde_json::from_slice(&bytes)
413            .map_err(EventualiError::from)
414    }
415}
416
417#[cfg(test)]
418mod tests {
419    use super::*;
420    use crate::{EventData, EventMetadata};
421    use uuid::Uuid;
422
423    fn create_test_event() -> Event {
424        Event {
425            id: Uuid::new_v4(),
426            aggregate_id: "test-aggregate".to_string(),
427            aggregate_type: "TestAggregate".to_string(),
428            event_type: "TestEvent".to_string(),
429            event_version: 1,
430            aggregate_version: 1,
431            data: EventData::Json(serde_json::json!({"test": "data"})),
432            metadata: EventMetadata::default(),
433            timestamp: chrono::Utc::now(),
434        }
435    }
436
437    #[test]
438    fn test_key_generation() {
439        let key = SigningKeyManager::generate_key(
440            "test-key".to_string(),
441            SignatureAlgorithm::HmacSha256
442        ).unwrap();
443        
444        assert_eq!(key.key_data.len(), 32);
445        assert_eq!(key.id, "test-key");
446        assert_eq!(key.algorithm, SignatureAlgorithm::HmacSha256);
447    }
448
449    #[test]
450    fn test_password_key_derivation() {
451        let salt = b"test-salt";
452        let key = SigningKeyManager::derive_key_from_password(
453            "test-key".to_string(),
454            "test-password",
455            salt,
456            SignatureAlgorithm::HmacSha256
457        ).unwrap();
458        
459        assert_eq!(key.key_data.len(), 32);
460        
461        // Same password and salt should produce same key
462        let key2 = SigningKeyManager::derive_key_from_password(
463            "test-key-2".to_string(),
464            "test-password",
465            salt,
466            SignatureAlgorithm::HmacSha256
467        ).unwrap();
468        
469        assert_eq!(key.key_data, key2.key_data);
470    }
471
472    #[test]
473    fn test_event_signing_and_verification() {
474        let key = SigningKeyManager::generate_key(
475            "test-key".to_string(),
476            SignatureAlgorithm::HmacSha256
477        ).unwrap();
478        
479        let signer = EventSigner::with_key("test-key".to_string(), key.key_data).unwrap();
480        let event = create_test_event();
481        
482        let signed_event = signer.sign_event(&event).unwrap();
483        
484        assert_eq!(signed_event.signature.algorithm, SignatureAlgorithm::HmacSha256);
485        assert_eq!(signed_event.signature.key_id, "test-key");
486        assert_eq!(signed_event.signature.signature.len(), 32);
487        assert!(!signed_event.signature.signature.is_empty());
488        
489        let is_valid = signer.verify_signature(&signed_event).unwrap();
490        assert!(is_valid);
491    }
492
493    #[test]
494    fn test_signature_verification_with_different_keys() {
495        let key1 = SigningKeyManager::generate_key(
496            "key1".to_string(),
497            SignatureAlgorithm::HmacSha256
498        ).unwrap();
499        
500        let key2 = SigningKeyManager::generate_key(
501            "key2".to_string(),
502            SignatureAlgorithm::HmacSha256
503        ).unwrap();
504        
505        let signer1 = EventSigner::with_key("key1".to_string(), key1.key_data).unwrap();
506        let signer2 = EventSigner::with_key("key2".to_string(), key2.key_data).unwrap();
507        
508        let event = create_test_event();
509        let signed_event = signer1.sign_event(&event).unwrap();
510        
511        // Should verify with correct signer
512        assert!(signer1.verify_signature(&signed_event).unwrap());
513        
514        // Should fail with wrong signer (different key)
515        assert!(!signer2.verify_signature(&signed_event).unwrap_or(true));
516    }
517
518    #[test]
519    fn test_tampered_event_detection() {
520        let key = SigningKeyManager::generate_key(
521            "test-key".to_string(),
522            SignatureAlgorithm::HmacSha256
523        ).unwrap();
524        
525        let signer = EventSigner::with_key("test-key".to_string(), key.key_data).unwrap();
526        let event = create_test_event();
527        
528        let mut signed_event = signer.sign_event(&event).unwrap();
529        
530        // Original should verify
531        assert!(signer.verify_signature(&signed_event).unwrap());
532        
533        // Tamper with the event data
534        signed_event.event.data = EventData::Json(serde_json::json!({"tampered": "data"}));
535        
536        // Should fail verification due to tampering
537        assert!(!signer.verify_signature(&signed_event).unwrap());
538    }
539
540    #[test]
541    fn test_hmac_sha512() {
542        let key = SigningKeyManager::generate_key(
543            "test-key".to_string(),
544            SignatureAlgorithm::HmacSha512
545        ).unwrap();
546        
547        assert_eq!(key.key_data.len(), 64);
548        
549        let signer = EventSigner::with_key("test-key".to_string(), key.key_data).unwrap();
550        let event = create_test_event();
551        
552        let signed_event = signer.sign_event(&event).unwrap();
553        
554        assert_eq!(signed_event.signature.algorithm, SignatureAlgorithm::HmacSha512);
555        assert_eq!(signed_event.signature.signature.len(), 64);
556        assert!(signer.verify_signature(&signed_event).unwrap());
557    }
558
559    #[test]
560    fn test_data_signing() {
561        let key = SigningKeyManager::generate_key(
562            "test-key".to_string(),
563            SignatureAlgorithm::HmacSha256
564        ).unwrap();
565        
566        let signer = EventSigner::with_key("test-key".to_string(), key.key_data).unwrap();
567        let data = b"Hello, World!";
568        
569        let signature = signer.sign_data(data, "test-key").unwrap();
570        assert!(signer.verify_data_signature(data, &signature).unwrap());
571        
572        // Different data should fail verification
573        let other_data = b"Hello, World?";
574        assert!(!signer.verify_data_signature(other_data, &signature).unwrap());
575    }
576
577    #[test]
578    fn test_base64_serialization() {
579        let key = SigningKeyManager::generate_key(
580            "test-key".to_string(),
581            SignatureAlgorithm::HmacSha256
582        ).unwrap();
583        
584        let signer = EventSigner::with_key("test-key".to_string(), key.key_data).unwrap();
585        let event = create_test_event();
586        
587        let signed_event = signer.sign_event(&event).unwrap();
588        
589        let base64_str = signed_event.to_base64();
590        assert!(!base64_str.is_empty());
591        
592        let deserialized = SignedEvent::from_base64(&base64_str).unwrap();
593        assert_eq!(signed_event.signature.key_id, deserialized.signature.key_id);
594        assert_eq!(signed_event.signature.signature, deserialized.signature.signature);
595        
596        assert!(signer.verify_signature(&deserialized).unwrap());
597    }
598}