Rust · 39146 bytes Raw Blame History
1 //! Malicious content detection and isolation for ZephyrFS
2 //!
3 //! Provides content-blind threat detection capabilities that work on encrypted data
4 //! without ever accessing plaintext content. Uses heuristic analysis, pattern detection,
5 //! and behavioral analysis to identify potentially malicious content while maintaining
6 //! zero-knowledge guarantees.
7
8 use anyhow::{Context, Result};
9 use ring::digest::{digest, SHA256, SHA512};
10 use serde::{Deserialize, Serialize};
11 use std::collections::{HashMap, HashSet, VecDeque};
12 use std::sync::Arc;
13 use std::time::{Duration, SystemTime, UNIX_EPOCH};
14 use tokio::sync::{RwLock, Mutex};
15 use tracing::{debug, info, warn, error};
16 use uuid::Uuid;
17
18 use crate::security::chunk_isolation::{IsolationLevel, ThreatLevel, SecurityEvent, SecurityEventType};
19 use crate::crypto::EncryptedData;
20
21 /// Maximum analysis queue size to prevent DoS
22 const MAX_ANALYSIS_QUEUE_SIZE: usize = 10000;
23
24 /// Time window for behavioral analysis (1 hour)
25 const BEHAVIORAL_WINDOW: Duration = Duration::from_secs(3600);
26
27 /// Malicious content detection engine
28 pub struct MaliciousContentDetector {
29 /// Threat signature database (encrypted patterns)
30 signatures: Arc<RwLock<ThreatSignatureDatabase>>,
31
32 /// Behavioral analysis engine
33 behavioral_analyzer: Arc<BehavioralAnalyzer>,
34
35 /// Analysis queue for processing
36 analysis_queue: Arc<Mutex<VecDeque<AnalysisRequest>>>,
37
38 /// Detection statistics
39 stats: Arc<RwLock<DetectionStatistics>>,
40
41 /// Pattern matching engine
42 pattern_matcher: Arc<PatternMatcher>,
43
44 /// Quarantine manager
45 quarantine_manager: Arc<QuarantineManager>,
46 }
47
48 /// Request for content analysis
49 #[derive(Debug, Clone)]
50 pub struct AnalysisRequest {
51 pub chunk_id: Uuid,
52 pub encrypted_data: EncryptedData,
53 pub priority: AnalysisPriority,
54 pub submitted_at: SystemTime,
55 pub requester_context: AnalysisContext,
56 }
57
58 /// Priority levels for analysis requests
59 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
60 pub enum AnalysisPriority {
61 Low,
62 Normal,
63 High,
64 Critical,
65 }
66
67 /// Context information for analysis
68 #[derive(Debug, Clone, Serialize, Deserialize)]
69 pub struct AnalysisContext {
70 /// Chunk identifier being analyzed
71 pub chunk_id: Option<uuid::Uuid>,
72
73 /// Source of the chunk (upload, replication, etc.)
74 pub source: String,
75
76 /// Network peer information (if applicable)
77 pub peer_info: Option<PeerInfo>,
78
79 /// Upload characteristics
80 pub upload_metadata: HashMap<String, String>,
81
82 /// Time-based context
83 pub temporal_context: TemporalContext,
84 }
85
86 /// Peer information for network-based analysis
87 #[derive(Debug, Clone, Serialize, Deserialize)]
88 pub struct PeerInfo {
89 pub peer_id: String,
90 pub peer_reputation: f64,
91 pub connection_count: u32,
92 pub historical_violations: u32,
93 }
94
95 /// Temporal context for time-based analysis
96 #[derive(Debug, Clone, Serialize, Deserialize)]
97 pub struct TemporalContext {
98 pub upload_time: u64,
99 pub burst_indicator: bool,
100 pub unusual_timing: bool,
101 pub rate_limit_triggered: bool,
102 }
103
104 /// Comprehensive threat analysis result
105 #[derive(Debug, Clone, Serialize, Deserialize)]
106 pub struct ThreatAnalysisResult {
107 pub chunk_id: Uuid,
108 pub overall_threat_level: ThreatLevel,
109 pub confidence: f64,
110 pub analysis_components: Vec<AnalysisComponent>,
111 pub recommended_actions: Vec<RecommendedAction>,
112 pub quarantine_recommendation: QuarantineRecommendation,
113 pub analysis_timestamp: u64,
114 }
115
116 /// Individual analysis component result
117 #[derive(Debug, Clone, Serialize, Deserialize)]
118 pub struct AnalysisComponent {
119 pub component_type: AnalysisComponentType,
120 pub threat_level: ThreatLevel,
121 pub confidence: f64,
122 pub details: String,
123 pub indicators: Vec<String>,
124 }
125
126 /// Types of analysis components
127 #[derive(Debug, Clone, Serialize, Deserialize)]
128 pub enum AnalysisComponentType {
129 SignatureMatching,
130 BehavioralAnalysis,
131 StatisticalAnalysis,
132 PatternRecognition,
133 NetworkAnalysis,
134 TemporalAnalysis,
135 }
136
137 /// Recommended actions based on analysis
138 #[derive(Debug, Clone, Serialize, Deserialize)]
139 pub enum RecommendedAction {
140 Allow,
141 Monitor,
142 EnhancedMonitoring,
143 RateLimitPeer,
144 QuarantineChunk,
145 BlockPeer,
146 AlertAdministrator,
147 ImmediateDelete,
148 }
149
150 /// Quarantine recommendation with details
151 #[derive(Debug, Clone, Serialize, Deserialize)]
152 pub struct QuarantineRecommendation {
153 pub should_quarantine: bool,
154 pub isolation_level: IsolationLevel,
155 pub reason: String,
156 pub duration: Option<Duration>,
157 pub monitoring_required: bool,
158 }
159
160 /// Threat signature database for pattern matching
161 pub struct ThreatSignatureDatabase {
162 /// Known malicious patterns (encrypted/hashed)
163 malicious_patterns: HashMap<String, ThreatSignature>,
164
165 /// Suspicious pattern indicators
166 suspicious_patterns: HashMap<String, SuspiciousPattern>,
167
168 /// Behavioral signatures
169 behavioral_signatures: Vec<BehavioralSignature>,
170
171 /// Last update timestamp
172 last_updated: SystemTime,
173 }
174
175 /// Individual threat signature
176 #[derive(Debug, Clone, Serialize, Deserialize)]
177 pub struct ThreatSignature {
178 pub signature_id: String,
179 pub pattern_hash: String,
180 pub threat_type: ThreatType,
181 pub severity: ThreatLevel,
182 pub description: String,
183 pub created_at: u64,
184 pub confidence: f64,
185 }
186
187 /// Types of threats that can be detected
188 #[derive(Debug, Clone, Serialize, Deserialize)]
189 pub enum ThreatType {
190 KnownMalware,
191 SuspiciousEncryption,
192 DataExfiltration,
193 RansomwarePattern,
194 BotneTCommand,
195 AnomalousTraffic,
196 UnusualCompression,
197 SuspiciousFrequency,
198 }
199
200 /// Suspicious pattern (less severe than threats)
201 #[derive(Debug, Clone, Serialize, Deserialize)]
202 pub struct SuspiciousPattern {
203 pub pattern_id: String,
204 pub pattern_description: String,
205 pub risk_level: f64,
206 pub false_positive_rate: f64,
207 }
208
209 /// Behavioral signature for pattern analysis
210 #[derive(Debug, Clone, Serialize, Deserialize)]
211 pub struct BehavioralSignature {
212 pub signature_id: String,
213 pub description: String,
214 pub trigger_conditions: Vec<TriggerCondition>,
215 pub severity: ThreatLevel,
216 }
217
218 /// Conditions that trigger behavioral signatures
219 #[derive(Debug, Clone, Serialize, Deserialize)]
220 pub enum TriggerCondition {
221 HighVolumeUpload { threshold: u64, window: Duration },
222 RapidFireUploads { count: u32, window: Duration },
223 UnusualFileSizes { min_size: u64, max_size: u64 },
224 SuspiciousEntropy { min_entropy: f64, max_entropy: f64 },
225 PeerReputationBelow { threshold: f64 },
226 TimeOfDayAnomaly { suspicious_hours: Vec<u8> },
227 }
228
229 /// Behavioral analysis engine
230 pub struct BehavioralAnalyzer {
231 /// Recent upload patterns by peer
232 peer_patterns: Arc<RwLock<HashMap<String, VecDeque<UploadEvent>>>>,
233
234 /// Global upload statistics
235 global_stats: Arc<RwLock<GlobalUploadStats>>,
236
237 /// Time-based analysis
238 temporal_analyzer: Arc<TemporalAnalyzer>,
239 }
240
241 /// Individual upload event for behavioral analysis
242 #[derive(Debug, Clone)]
243 pub struct UploadEvent {
244 pub timestamp: SystemTime,
245 pub chunk_id: Uuid,
246 pub size: u64,
247 pub entropy: f64,
248 pub peer_id: String,
249 }
250
251 /// Global statistics for anomaly detection
252 #[derive(Debug, Clone, Default)]
253 pub struct GlobalUploadStats {
254 pub total_uploads: u64,
255 pub average_chunk_size: f64,
256 pub average_entropy: f64,
257 pub uploads_per_hour: VecDeque<u32>,
258 pub size_distribution: HashMap<u64, u32>,
259 }
260
261 /// Temporal analysis for time-based threats
262 pub struct TemporalAnalyzer {
263 /// Hourly upload patterns
264 hourly_patterns: Arc<RwLock<[u32; 24]>>,
265
266 /// Day-of-week patterns
267 daily_patterns: Arc<RwLock<[u32; 7]>>,
268
269 /// Anomaly detection thresholds
270 anomaly_thresholds: TemporalThresholds,
271 }
272
273 /// Thresholds for temporal anomaly detection
274 #[derive(Debug, Clone)]
275 pub struct TemporalThresholds {
276 pub hourly_deviation_threshold: f64,
277 pub burst_detection_threshold: u32,
278 pub unusual_timing_threshold: f64,
279 }
280
281 /// Pattern matching engine for encrypted content
282 pub struct PatternMatcher {
283 /// Compiled pattern matchers
284 matchers: Arc<RwLock<Vec<CompiledPattern>>>,
285
286 /// Pattern matching statistics
287 match_stats: Arc<RwLock<PatternMatchStats>>,
288 }
289
290 /// Compiled pattern for efficient matching
291 #[derive(Debug, Clone)]
292 pub struct CompiledPattern {
293 pub pattern_id: String,
294 pub pattern_bytes: Vec<u8>,
295 pub pattern_mask: Vec<u8>, // For fuzzy matching
296 pub threat_level: ThreatLevel,
297 }
298
299 /// Statistics for pattern matching performance
300 #[derive(Debug, Clone, Default)]
301 pub struct PatternMatchStats {
302 pub total_matches: u64,
303 pub false_positives: u64,
304 pub true_positives: u64,
305 pub patterns_checked: u64,
306 pub average_match_time: Duration,
307 }
308
309 /// Quarantine management system
310 pub struct QuarantineManager {
311 /// Currently quarantined chunks
312 quarantined_chunks: Arc<RwLock<HashMap<Uuid, QuarantinedChunk>>>,
313
314 /// Quarantine policies
315 policies: Arc<RwLock<Vec<QuarantinePolicy>>>,
316
317 /// Quarantine statistics
318 stats: Arc<RwLock<QuarantineStats>>,
319 }
320
321 /// Quarantined chunk information
322 #[derive(Debug, Clone, Serialize, Deserialize)]
323 pub struct QuarantinedChunk {
324 pub chunk_id: Uuid,
325 pub quarantine_reason: String,
326 pub quarantined_at: SystemTime,
327 pub quarantine_duration: Option<Duration>,
328 pub threat_level: ThreatLevel,
329 pub automated: bool,
330 pub review_required: bool,
331 }
332
333 /// Quarantine policy configuration
334 #[derive(Debug, Clone, Serialize, Deserialize)]
335 pub struct QuarantinePolicy {
336 pub policy_id: String,
337 pub trigger_threat_level: ThreatLevel,
338 pub automatic_quarantine: bool,
339 pub quarantine_duration: Option<Duration>,
340 pub require_manual_review: bool,
341 pub delete_after_quarantine: bool,
342 }
343
344 /// Quarantine statistics
345 #[derive(Debug, Clone, Default, Serialize, Deserialize)]
346 pub struct QuarantineStats {
347 pub total_quarantined: u64,
348 pub currently_quarantined: u64,
349 pub false_positives: u64,
350 pub threats_blocked: u64,
351 pub automatic_quarantines: u64,
352 pub manual_quarantines: u64,
353 }
354
355 /// Detection statistics
356 #[derive(Debug, Clone, Default, Serialize, Deserialize)]
357 pub struct DetectionStatistics {
358 pub total_analyses: u64,
359 pub threats_detected: u64,
360 pub false_positive_rate: f64,
361 pub average_analysis_time: Duration,
362 pub signature_matches: u64,
363 pub behavioral_detections: u64,
364 pub quarantine_actions: u64,
365 }
366
367 impl MaliciousContentDetector {
368 /// Create new malicious content detector
369 pub fn new() -> Self {
370 Self {
371 signatures: Arc::new(RwLock::new(ThreatSignatureDatabase::new())),
372 behavioral_analyzer: Arc::new(BehavioralAnalyzer::new()),
373 analysis_queue: Arc::new(Mutex::new(VecDeque::new())),
374 stats: Arc::new(RwLock::new(DetectionStatistics::default())),
375 pattern_matcher: Arc::new(PatternMatcher::new()),
376 quarantine_manager: Arc::new(QuarantineManager::new()),
377 }
378 }
379
380 /// Submit chunk for malicious content analysis
381 pub async fn analyze_chunk(
382 &self,
383 chunk_id: Uuid,
384 encrypted_data: EncryptedData,
385 context: AnalysisContext,
386 priority: AnalysisPriority,
387 ) -> Result<ThreatAnalysisResult> {
388 let request = AnalysisRequest {
389 chunk_id,
390 encrypted_data,
391 priority,
392 submitted_at: SystemTime::now(),
393 requester_context: context,
394 };
395
396 // Queue for analysis
397 {
398 let mut queue = self.analysis_queue.lock().await;
399 if queue.len() >= MAX_ANALYSIS_QUEUE_SIZE {
400 warn!("Analysis queue full, dropping low priority requests");
401 queue.retain(|req| req.priority >= AnalysisPriority::Normal);
402 }
403
404 // Insert based on priority
405 let pos = queue.iter().position(|req| req.priority < request.priority)
406 .unwrap_or(queue.len());
407 queue.insert(pos, request.clone());
408 }
409
410 // Perform immediate analysis
411 self.perform_analysis(request).await
412 }
413
414 /// Perform comprehensive threat analysis
415 async fn perform_analysis(&self, request: AnalysisRequest) -> Result<ThreatAnalysisResult> {
416 let start_time = SystemTime::now();
417
418 let mut analysis_components = Vec::new();
419
420 // 1. Signature matching analysis
421 let signature_result = self.analyze_signatures(&request.encrypted_data).await?;
422 analysis_components.push(signature_result);
423
424 // 2. Behavioral analysis
425 let behavioral_result = self.behavioral_analyzer
426 .analyze_behavior(&request.chunk_id, &request.requester_context).await?;
427 analysis_components.push(behavioral_result);
428
429 // 3. Statistical analysis
430 let statistical_result = self.analyze_statistics(&request.encrypted_data).await?;
431 analysis_components.push(statistical_result);
432
433 // 4. Pattern recognition
434 let pattern_result = self.pattern_matcher
435 .match_patterns(&request.encrypted_data).await?;
436 analysis_components.push(pattern_result);
437
438 // 5. Network analysis
439 let network_result = self.analyze_network_context(&request.requester_context).await?;
440 analysis_components.push(network_result);
441
442 // 6. Temporal analysis
443 let temporal_result = self.behavioral_analyzer.temporal_analyzer
444 .analyze_temporal_patterns(&request.requester_context.temporal_context).await?;
445 analysis_components.push(temporal_result);
446
447 // Aggregate results
448 let overall_threat_level = self.calculate_overall_threat_level(&analysis_components);
449 let confidence = self.calculate_confidence(&analysis_components);
450 let recommended_actions = self.generate_recommendations(&analysis_components);
451 let quarantine_recommendation = self.generate_quarantine_recommendation(&analysis_components);
452
453 let result = ThreatAnalysisResult {
454 chunk_id: request.chunk_id,
455 overall_threat_level,
456 confidence,
457 analysis_components,
458 recommended_actions,
459 quarantine_recommendation,
460 analysis_timestamp: SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs(),
461 };
462
463 // Update statistics
464 {
465 let mut stats = self.stats.write().await;
466 stats.total_analyses += 1;
467 if overall_threat_level != ThreatLevel::Low {
468 stats.threats_detected += 1;
469 }
470 stats.average_analysis_time = start_time.elapsed().unwrap_or(Duration::ZERO);
471 }
472
473 // Take action if necessary
474 if result.quarantine_recommendation.should_quarantine {
475 self.quarantine_manager.quarantine_chunk(
476 request.chunk_id,
477 result.quarantine_recommendation.reason.clone(),
478 result.overall_threat_level,
479 true, // automated
480 ).await?;
481 }
482
483 info!("Completed threat analysis for chunk {} with level {:?} (confidence: {:.2})",
484 request.chunk_id, overall_threat_level, confidence);
485
486 Ok(result)
487 }
488
489 /// Analyze against known threat signatures
490 async fn analyze_signatures(&self, encrypted_data: &EncryptedData) -> Result<AnalysisComponent> {
491 let signatures = self.signatures.read().await;
492 let mut threat_level = ThreatLevel::Low;
493 let mut confidence: f64 = 0.0;
494 let mut indicators = Vec::new();
495
496 // Hash the encrypted data for comparison
497 let data_hash = hex::encode(digest(&SHA256, &encrypted_data.ciphertext).as_ref());
498
499 // Check against malicious patterns
500 if let Some(signature) = signatures.malicious_patterns.get(&data_hash) {
501 threat_level = signature.severity;
502 confidence = signature.confidence;
503 indicators.push(format!("Matches signature: {}", signature.description));
504 }
505
506 // Check for suspicious patterns
507 for (pattern_hash, pattern) in &signatures.suspicious_patterns {
508 if encrypted_data.ciphertext.windows(pattern_hash.len())
509 .any(|window| hex::encode(digest(&SHA256, window).as_ref()) == *pattern_hash) {
510 if threat_level == ThreatLevel::Low {
511 threat_level = ThreatLevel::Medium;
512 }
513 confidence = confidence.max(pattern.risk_level);
514 indicators.push(format!("Suspicious pattern: {}", pattern.pattern_description));
515 }
516 }
517
518 Ok(AnalysisComponent {
519 component_type: AnalysisComponentType::SignatureMatching,
520 threat_level,
521 confidence,
522 details: format!("Checked {} signatures", signatures.malicious_patterns.len()),
523 indicators,
524 })
525 }
526
527 /// Analyze statistical properties of encrypted data
528 async fn analyze_statistics(&self, encrypted_data: &EncryptedData) -> Result<AnalysisComponent> {
529 let mut threat_level = ThreatLevel::Low;
530 let mut confidence: f64 = 0.0;
531 let mut indicators = Vec::new();
532
533 let data = &encrypted_data.ciphertext;
534
535 // Calculate entropy
536 let entropy = self.calculate_entropy(data);
537
538 // Properly encrypted data should have high entropy
539 if entropy < 7.0 {
540 threat_level = ThreatLevel::High;
541 confidence = 0.9;
542 indicators.push(format!("Low entropy detected: {:.2}", entropy));
543 } else if entropy < 7.5 {
544 threat_level = ThreatLevel::Medium;
545 confidence = 0.7;
546 indicators.push(format!("Below expected entropy: {:.2}", entropy));
547 }
548
549 // Check for unusual size patterns
550 if data.len() < 100 {
551 indicators.push("Unusually small chunk size".to_string());
552 confidence = confidence.max(0.3);
553 } else if data.len() > 100 * 1024 * 1024 {
554 threat_level = std::cmp::max(threat_level, ThreatLevel::Medium);
555 confidence = confidence.max(0.6);
556 indicators.push("Unusually large chunk size".to_string());
557 }
558
559 // Check for pattern repetition
560 if self.detect_repetitive_patterns(data) {
561 threat_level = std::cmp::max(threat_level, ThreatLevel::Medium);
562 confidence = confidence.max(0.8);
563 indicators.push("Repetitive patterns detected".to_string());
564 }
565
566 Ok(AnalysisComponent {
567 component_type: AnalysisComponentType::StatisticalAnalysis,
568 threat_level,
569 confidence,
570 details: format!("Entropy: {:.2}, Size: {} bytes", entropy, data.len()),
571 indicators,
572 })
573 }
574
575 /// Analyze network context for threats
576 async fn analyze_network_context(&self, context: &AnalysisContext) -> Result<AnalysisComponent> {
577 let mut threat_level = ThreatLevel::Low;
578 let mut confidence: f64 = 0.0;
579 let mut indicators = Vec::new();
580
581 if let Some(peer_info) = &context.peer_info {
582 // Check peer reputation
583 if peer_info.peer_reputation < 0.3 {
584 threat_level = ThreatLevel::High;
585 confidence = 0.9;
586 indicators.push(format!("Low peer reputation: {:.2}", peer_info.peer_reputation));
587 } else if peer_info.peer_reputation < 0.6 {
588 threat_level = ThreatLevel::Medium;
589 confidence = 0.6;
590 indicators.push(format!("Moderate peer reputation: {:.2}", peer_info.peer_reputation));
591 }
592
593 // Check violation history
594 if peer_info.historical_violations > 5 {
595 threat_level = std::cmp::max(threat_level, ThreatLevel::Medium);
596 confidence = confidence.max(0.7);
597 indicators.push(format!("High violation count: {}", peer_info.historical_violations));
598 }
599 }
600
601 Ok(AnalysisComponent {
602 component_type: AnalysisComponentType::NetworkAnalysis,
603 threat_level,
604 confidence,
605 details: "Network context analysis".to_string(),
606 indicators,
607 })
608 }
609
610 /// Calculate entropy of data
611 fn calculate_entropy(&self, data: &[u8]) -> f64 {
612 let mut freq = [0u32; 256];
613 for &byte in data {
614 freq[byte as usize] += 1;
615 }
616
617 let len = data.len() as f64;
618 let mut entropy = 0.0;
619
620 for &count in &freq {
621 if count > 0 {
622 let p = count as f64 / len;
623 entropy -= p * p.log2();
624 }
625 }
626
627 entropy
628 }
629
630 /// Detect repetitive patterns in encrypted data
631 fn detect_repetitive_patterns(&self, data: &[u8]) -> bool {
632 if data.len() < 64 {
633 return false;
634 }
635
636 // Check for repeated blocks
637 let block_size = 16;
638 let mut block_counts = HashMap::new();
639
640 for chunk in data.chunks(block_size) {
641 if chunk.len() == block_size {
642 *block_counts.entry(chunk).or_insert(0) += 1;
643 }
644 }
645
646 // If any block appears more than 5% of the time, it's suspicious
647 let threshold = (data.len() / block_size) / 20; // 5%
648 block_counts.values().any(|&count| count > threshold.max(3))
649 }
650
651 /// Calculate overall threat level from components
652 fn calculate_overall_threat_level(&self, components: &[AnalysisComponent]) -> ThreatLevel {
653 let mut max_threat = ThreatLevel::Low;
654 let mut weighted_score = 0.0;
655 let mut total_weight = 0.0;
656
657 for component in components {
658 max_threat = max_threat.max(component.threat_level);
659
660 let weight = component.confidence;
661 let score = match component.threat_level {
662 ThreatLevel::Low => 0.0,
663 ThreatLevel::Medium => 1.0,
664 ThreatLevel::High => 2.0,
665 ThreatLevel::Critical => 3.0,
666 };
667
668 weighted_score += score * weight;
669 total_weight += weight;
670 }
671
672 let average_score = if total_weight > 0.0 {
673 weighted_score / total_weight
674 } else {
675 0.0
676 };
677
678 // Use the higher of max threat or weighted average
679 if average_score >= 2.5 || max_threat == ThreatLevel::Critical {
680 ThreatLevel::Critical
681 } else if average_score >= 1.5 || max_threat == ThreatLevel::High {
682 ThreatLevel::High
683 } else if average_score >= 0.5 || max_threat == ThreatLevel::Medium {
684 ThreatLevel::Medium
685 } else {
686 ThreatLevel::Low
687 }
688 }
689
690 /// Calculate confidence from components
691 fn calculate_confidence(&self, components: &[AnalysisComponent]) -> f64 {
692 if components.is_empty() {
693 return 0.0;
694 }
695
696 let avg_confidence: f64 = components.iter()
697 .map(|c| c.confidence)
698 .sum::<f64>() / components.len() as f64;
699
700 // Boost confidence if multiple components agree
701 let high_confidence_count = components.iter()
702 .filter(|c| c.confidence > 0.7 && c.threat_level != ThreatLevel::Low)
703 .count();
704
705 let boost = (high_confidence_count as f64 * 0.1).min(0.3);
706 (avg_confidence + boost).min(1.0)
707 }
708
709 /// Generate action recommendations
710 fn generate_recommendations(&self, components: &[AnalysisComponent]) -> Vec<RecommendedAction> {
711 let overall_threat = self.calculate_overall_threat_level(components);
712 let confidence = self.calculate_confidence(components);
713
714 let mut actions = Vec::new();
715
716 match overall_threat {
717 ThreatLevel::Low => {
718 actions.push(RecommendedAction::Allow);
719 },
720 ThreatLevel::Medium => {
721 actions.push(RecommendedAction::Monitor);
722 if confidence > 0.7 {
723 actions.push(RecommendedAction::EnhancedMonitoring);
724 }
725 },
726 ThreatLevel::High => {
727 actions.push(RecommendedAction::QuarantineChunk);
728 actions.push(RecommendedAction::EnhancedMonitoring);
729 if confidence > 0.8 {
730 actions.push(RecommendedAction::RateLimitPeer);
731 }
732 },
733 ThreatLevel::Critical => {
734 actions.push(RecommendedAction::QuarantineChunk);
735 actions.push(RecommendedAction::BlockPeer);
736 actions.push(RecommendedAction::AlertAdministrator);
737 if confidence > 0.9 {
738 actions.push(RecommendedAction::ImmediateDelete);
739 }
740 },
741 }
742
743 actions
744 }
745
746 /// Generate quarantine recommendation
747 fn generate_quarantine_recommendation(&self, components: &[AnalysisComponent]) -> QuarantineRecommendation {
748 let overall_threat = self.calculate_overall_threat_level(components);
749 let confidence = self.calculate_confidence(components);
750
751 match overall_threat {
752 ThreatLevel::Low => QuarantineRecommendation {
753 should_quarantine: false,
754 isolation_level: IsolationLevel::Standard,
755 reason: "No threat detected".to_string(),
756 duration: None,
757 monitoring_required: false,
758 },
759 ThreatLevel::Medium => QuarantineRecommendation {
760 should_quarantine: confidence > 0.6,
761 isolation_level: IsolationLevel::Enhanced,
762 reason: "Medium threat level detected".to_string(),
763 duration: Some(Duration::from_secs(3600)), // 1 hour
764 monitoring_required: true,
765 },
766 ThreatLevel::High => QuarantineRecommendation {
767 should_quarantine: true,
768 isolation_level: IsolationLevel::Quarantined,
769 reason: "High threat level detected".to_string(),
770 duration: Some(Duration::from_secs(86400)), // 24 hours
771 monitoring_required: true,
772 },
773 ThreatLevel::Critical => QuarantineRecommendation {
774 should_quarantine: true,
775 isolation_level: IsolationLevel::Quarantined,
776 reason: "Critical threat level detected".to_string(),
777 duration: None, // Indefinite
778 monitoring_required: true,
779 },
780 }
781 }
782
783 /// Analyze content using the existing analyze_chunk method
784 pub async fn analyze_content(
785 &self,
786 encrypted_data: &EncryptedData,
787 metadata: &HashMap<String, String>,
788 ) -> Result<ThreatAnalysisResult> {
789 // Create analysis context from metadata
790 let context = AnalysisContext {
791 chunk_id: None,
792 source: metadata.get("source").unwrap_or(&"unknown".to_string()).clone(),
793 peer_info: None,
794 upload_metadata: metadata.clone(),
795 temporal_context: TemporalContext {
796 upload_time: std::time::SystemTime::now()
797 .duration_since(std::time::UNIX_EPOCH)
798 .unwrap_or_default()
799 .as_secs(),
800 burst_indicator: false,
801 unusual_timing: false,
802 rate_limit_triggered: false,
803 },
804 };
805
806 // Forward to analyze_chunk with default priority
807 self.analyze_chunk(
808 uuid::Uuid::new_v4(),
809 encrypted_data.clone(),
810 context,
811 AnalysisPriority::Normal,
812 ).await
813 }
814
815 /// Get threat history for a chunk
816 pub async fn get_threat_history(&self, _chunk_id: Uuid) -> Vec<ThreatAnalysisResult> {
817 // TODO: Implement threat history tracking
818 vec![]
819 }
820
821 /// Update detector configuration
822 pub fn update_config(&mut self, _config: DetectionConfig) -> Result<()> {
823 // TODO: Implement configuration updates
824 Ok(())
825 }
826 }
827
828 // Implementation stubs for other components...
829 impl ThreatSignatureDatabase {
830 fn new() -> Self {
831 Self {
832 malicious_patterns: HashMap::new(),
833 suspicious_patterns: HashMap::new(),
834 behavioral_signatures: Vec::new(),
835 last_updated: SystemTime::now(),
836 }
837 }
838 }
839
840 impl BehavioralAnalyzer {
841 fn new() -> Self {
842 Self {
843 peer_patterns: Arc::new(RwLock::new(HashMap::new())),
844 global_stats: Arc::new(RwLock::new(GlobalUploadStats::default())),
845 temporal_analyzer: Arc::new(TemporalAnalyzer::new()),
846 }
847 }
848
849 async fn analyze_behavior(&self, _chunk_id: &Uuid, _context: &AnalysisContext) -> Result<AnalysisComponent> {
850 // Behavioral analysis implementation
851 Ok(AnalysisComponent {
852 component_type: AnalysisComponentType::BehavioralAnalysis,
853 threat_level: ThreatLevel::Low,
854 confidence: 0.5,
855 details: "Behavioral analysis completed".to_string(),
856 indicators: Vec::new(),
857 })
858 }
859 }
860
861 impl TemporalAnalyzer {
862 fn new() -> Self {
863 Self {
864 hourly_patterns: Arc::new(RwLock::new([0; 24])),
865 daily_patterns: Arc::new(RwLock::new([0; 7])),
866 anomaly_thresholds: TemporalThresholds {
867 hourly_deviation_threshold: 2.0,
868 burst_detection_threshold: 100,
869 unusual_timing_threshold: 0.1,
870 },
871 }
872 }
873
874 async fn analyze_temporal_patterns(&self, _context: &TemporalContext) -> Result<AnalysisComponent> {
875 // Temporal analysis implementation
876 Ok(AnalysisComponent {
877 component_type: AnalysisComponentType::TemporalAnalysis,
878 threat_level: ThreatLevel::Low,
879 confidence: 0.5,
880 details: "Temporal analysis completed".to_string(),
881 indicators: Vec::new(),
882 })
883 }
884
885
886 }
887
888 impl PatternMatcher {
889 fn new() -> Self {
890 Self {
891 matchers: Arc::new(RwLock::new(Vec::new())),
892 match_stats: Arc::new(RwLock::new(PatternMatchStats::default())),
893 }
894 }
895
896 async fn match_patterns(&self, _encrypted_data: &EncryptedData) -> Result<AnalysisComponent> {
897 // Pattern matching implementation
898 Ok(AnalysisComponent {
899 component_type: AnalysisComponentType::PatternRecognition,
900 threat_level: ThreatLevel::Low,
901 confidence: 0.5,
902 details: "Pattern matching completed".to_string(),
903 indicators: Vec::new(),
904 })
905 }
906
907 /// Get threat history for a chunk
908 pub async fn get_threat_history(&self, _chunk_id: Uuid) -> Vec<ThreatAnalysisResult> {
909 // TODO: Implement threat history tracking
910 vec![]
911 }
912
913 /// Update detector configuration
914 pub fn update_config(&mut self, _config: DetectionConfig) -> Result<()> {
915 // TODO: Implement configuration updates
916 Ok(())
917 }
918
919 }
920
921 impl QuarantineManager {
922 fn new() -> Self {
923 Self {
924 quarantined_chunks: Arc::new(RwLock::new(HashMap::new())),
925 policies: Arc::new(RwLock::new(Self::default_policies())),
926 stats: Arc::new(RwLock::new(QuarantineStats::default())),
927 }
928 }
929
930 async fn quarantine_chunk(
931 &self,
932 chunk_id: Uuid,
933 reason: String,
934 threat_level: ThreatLevel,
935 automated: bool,
936 ) -> Result<()> {
937 let quarantine_reason_copy = reason.clone();
938 let quarantined_chunk = QuarantinedChunk {
939 chunk_id,
940 quarantine_reason: reason,
941 quarantined_at: SystemTime::now(),
942 quarantine_duration: match threat_level {
943 ThreatLevel::Medium => Some(Duration::from_secs(3600)),
944 ThreatLevel::High => Some(Duration::from_secs(86400)),
945 ThreatLevel::Critical => None,
946 _ => Some(Duration::from_secs(1800)),
947 },
948 threat_level,
949 automated,
950 review_required: threat_level == ThreatLevel::Critical,
951 };
952
953 {
954 let mut chunks = self.quarantined_chunks.write().await;
955 chunks.insert(chunk_id, quarantined_chunk);
956 }
957
958 {
959 let mut stats = self.stats.write().await;
960 stats.total_quarantined += 1;
961 stats.currently_quarantined += 1;
962 if automated {
963 stats.automatic_quarantines += 1;
964 } else {
965 stats.manual_quarantines += 1;
966 }
967 }
968
969 info!("Quarantined chunk {} due to: {}", chunk_id, quarantine_reason_copy);
970 Ok(())
971 }
972
973 fn default_policies() -> Vec<QuarantinePolicy> {
974 vec![
975 QuarantinePolicy {
976 policy_id: "high_threat_auto".to_string(),
977 trigger_threat_level: ThreatLevel::High,
978 automatic_quarantine: true,
979 quarantine_duration: Some(Duration::from_secs(86400)),
980 require_manual_review: false,
981 delete_after_quarantine: false,
982 },
983 QuarantinePolicy {
984 policy_id: "critical_threat_auto".to_string(),
985 trigger_threat_level: ThreatLevel::Critical,
986 automatic_quarantine: true,
987 quarantine_duration: None,
988 require_manual_review: true,
989 delete_after_quarantine: false,
990 },
991 ]
992 }
993
994 /// Check if a chunk is quarantined
995 pub async fn is_quarantined(&self, chunk_id: Uuid) -> Result<bool> {
996 let chunks = self.quarantined_chunks.read().await;
997 Ok(chunks.contains_key(&chunk_id))
998 }
999
1000 /// Get quarantine status for a chunk
1001 pub async fn get_quarantine_status(&self, chunk_id: Uuid) -> Result<QuarantineStatus> {
1002 let chunks = self.quarantined_chunks.read().await;
1003 if let Some(quarantined_chunk) = chunks.get(&chunk_id) {
1004 Ok(QuarantineStatus {
1005 is_quarantined: true,
1006 quarantine_reason: quarantined_chunk.quarantine_reason.clone(),
1007 quarantined_at: quarantined_chunk.quarantined_at,
1008 threat_level: quarantined_chunk.threat_level,
1009 average_quarantine_duration_hours: 24.0,
1010 automatic_releases: 0,
1011 manual_reviews_required: if quarantined_chunk.threat_level == ThreatLevel::Critical { 1 } else { 0 },
1012 })
1013 } else {
1014 Err(anyhow::anyhow!("Chunk not found in quarantine: {}", chunk_id))
1015 }
1016 }
1017
1018 /// Make quarantine_chunk method public
1019 pub async fn quarantine_chunk(&mut self, chunk_id: Uuid, reason: String, threat_level: ThreatLevel, automated: bool) -> Result<()> {
1020 let quarantined_chunk = QuarantinedChunk {
1021 chunk_id,
1022 quarantine_reason: reason,
1023 quarantined_at: SystemTime::now(),
1024 quarantine_duration: match threat_level {
1025 ThreatLevel::Medium => Some(Duration::from_secs(3600)),
1026 ThreatLevel::High => Some(Duration::from_secs(86400)),
1027 ThreatLevel::Critical => None, // Manual review required
1028 _ => Some(Duration::from_secs(1800)),
1029 },
1030 threat_level,
1031 automated,
1032 review_required: threat_level == ThreatLevel::Critical,
1033 };
1034
1035 let mut chunks = self.quarantined_chunks.write().await;
1036 chunks.insert(chunk_id, quarantined_chunk);
1037 Ok(())
1038 }
1039 }
1040
1041 trait ThreatLevelExt {
1042 fn max(self, other: Self) -> Self;
1043 }
1044
1045 impl ThreatLevelExt for ThreatLevel {
1046 fn max(self, other: Self) -> Self {
1047 match (self, other) {
1048 (ThreatLevel::Critical, _) | (_, ThreatLevel::Critical) => ThreatLevel::Critical,
1049 (ThreatLevel::High, _) | (_, ThreatLevel::High) => ThreatLevel::High,
1050 (ThreatLevel::Medium, _) | (_, ThreatLevel::Medium) => ThreatLevel::Medium,
1051 _ => ThreatLevel::Low,
1052 }
1053 }
1054 }
1055
1056 #[cfg(test)]
1057 mod tests {
1058 use super::*;
1059
1060 #[tokio::test]
1061 async fn test_malicious_content_detection() {
1062 let detector = MaliciousContentDetector::new();
1063
1064 let encrypted_data = EncryptedData {
1065 segment_index: 0,
1066 ciphertext: vec![1, 2, 3, 4, 5],
1067 nonce: [0; 12],
1068 aad: vec![],
1069 key_path: vec![0, 1, 2],
1070 };
1071
1072 let context = AnalysisContext {
1073 source: "test".to_string(),
1074 peer_info: None,
1075 upload_metadata: HashMap::new(),
1076 temporal_context: TemporalContext {
1077 upload_time: 0,
1078 burst_indicator: false,
1079 unusual_timing: false,
1080 rate_limit_triggered: false,
1081 },
1082 };
1083
1084 let result = detector.analyze_chunk(
1085 Uuid::new_v4(),
1086 encrypted_data,
1087 context,
1088 AnalysisPriority::Normal,
1089 ).await.unwrap();
1090
1091 assert_eq!(result.overall_threat_level, ThreatLevel::High); // Low entropy should trigger high threat
1092 }
1093 }
1094
1095 /// Configuration for malicious content detection
1096 #[derive(Debug, Clone, Serialize, Deserialize)]
1097 pub struct DetectionConfig {
1098 /// Enable behavioral analysis
1099 pub enable_behavioral_analysis: bool,
1100 /// Enable pattern matching
1101 pub enable_pattern_matching: bool,
1102 /// Enable temporal analysis
1103 pub enable_temporal_analysis: bool,
1104 /// Maximum analysis time per chunk (seconds)
1105 pub max_analysis_time_seconds: u32,
1106 /// Threat signature database update interval (hours)
1107 pub signature_update_interval_hours: u32,
1108 }
1109
1110 impl Default for DetectionConfig {
1111 fn default() -> Self {
1112 Self {
1113 enable_behavioral_analysis: true,
1114 enable_pattern_matching: true,
1115 enable_temporal_analysis: true,
1116 max_analysis_time_seconds: 30,
1117 signature_update_interval_hours: 6,
1118 }
1119 }
1120 }
1121
1122 /// Threat indicator for security analysis
1123 #[derive(Debug, Clone, Serialize, Deserialize)]
1124 pub struct ThreatIndicator {
1125 pub indicator_type: ThreatIndicatorType,
1126 pub severity: ThreatSeverity,
1127 pub description: String,
1128 pub confidence_score: f64,
1129 pub detected_at: chrono::DateTime<chrono::Utc>,
1130 }
1131
1132 /// Types of threat indicators
1133 #[derive(Debug, Clone, Serialize, Deserialize)]
1134 pub enum ThreatIndicatorType {
1135 SuspiciousPattern,
1136 BehavioralAnomaly,
1137 KnownMalware,
1138 UnusualEntropy,
1139 SuspiciousMetadata,
1140 }
1141
1142 /// Severity levels for threats
1143 #[derive(Debug, Clone, Serialize, Deserialize)]
1144 pub enum ThreatSeverity {
1145 Low,
1146 Medium,
1147 High,
1148 Critical,
1149 }
1150
1151 /// Status information for a quarantined chunk
1152 #[derive(Debug, Clone, Serialize, Deserialize)]
1153 pub struct QuarantineStatus {
1154 pub is_quarantined: bool,
1155 pub quarantine_reason: String,
1156 pub quarantined_at: SystemTime,
1157 pub threat_level: ThreatLevel,
1158 pub average_quarantine_duration_hours: f64,
1159 pub automatic_releases: u32,
1160 pub manual_reviews_required: u32,
1161 }