AirLibrary/Security/
mod.rs

1//! # Security Module
2//!
3//! Comprehensive security features for Air including:
4//! - Rate limiting with token bucket algorithm (per-IP and per-client)
5//! - Checksum verification for file integrity
6//! - Secure credential storage with encryption
7//! - Timing attack protection for sensitive operations
8//! - Secure memory handling with zeroization
9//! - Key rotation and management
10//! - Security event auditing and logging
11//!
12//! ## VSCode Security References
13//!
14//! This security module aligns with VSCode's security patterns:
15//! - Rate limiting similar to VSCode's API rate limiting
16//! - Secure credential storage matching VSCode's secret storage
17//! - File integrity verification similar to VSCode's extension verification
18//! - Security audit logging inspired by VSCode's telemetry security events
19//!
20//! ## Security Model for External Connections
21//!
22//! The security module implements a defense-in-depth approach for external
23//! connections:
24//!
25//! ### Network Security
26//! - Rate limiting prevents abuse and DoS attacks
27//! - IP-based rate limiting limits impact per client
28//! - Client-based rate limiting limits impact per authenticated client
29//! - Connection pooling limits total concurrent connections
30//!
31//! ### Authentication Security
32//! - Secure credential storage with AES-GCM encryption
33//! - PBKDF2 key derivation with high iteration count
34//! - Timing attack protection for password comparisons
35//! - Secure token generation and validation
36//!
37//! ### Data Security
38//! - SHA-256 checksum verification for file integrity
39//! - AES-GCM encryption for credential storage
40//! - Key wrapping for master key protection
41//! - Secure memory handling with zeroization
42//!
43//! ### Audit and Monitoring
44//! - Comprehensive security event logging
45//! - Failed authentication attempts tracking
46//! - Rate limit violation logging
47//! - Security metric collection for Mountain integration
48//!
49//! ## Mountain Settings Integration
50//!
51//! Security policies are integrated with Mountain settings:
52//! - Rate limit thresholds configurable via Mountain settings
53//! - Security event thresholds configurable via Mountain settings
54//! - Alert notification channels configured via Mountain
55//! - Security metric retention configured via Mountain
56//!
57//! ## TODO: Advanced Features
58//!
59//! - Implement HSM (Hardware Security Module) integration for key storage
60//! - Add support for hardware-backed key generation and storage
61//! - Implement certificate pinning for external API connections
62//! - Add support for TLS 1.3 with perfect forward secrecy
63//! - Implement security policy enforcement and validation
64//! - Add support for multi-factor authentication
65//! - Implement security compliance reporting (SOC2, PCI-DSS, etc.)
66//! - Add real-time security threat detection and response
67//! - Implement secure communication channels with VSCode extensions
68//! - Add support for encrypted data at rest with multiple keys
69//!
70//! ## Timing Attack Protection
71//!
72//! The module implements constant-time operations for sensitive comparisons:
73//! - Password comparisons use constant-time algorithms
74//! - Token comparisons are timing-attack resistant
75//! - Hash comparisons use fixed-time comparison functions
76//! - Authentication response timing is normalized
77//!
78//! ## Secure Memory Handling
79//!
80//! Sensitive data in memory is protected through:
81//! - Zeroization on drop for secure data structures
82//! - Memory encryption for sensitive buffers
83//! - Stack canaries for overflow detection
84//! - Memory locking to prevent swapping
85//!
86//! ## Key Rotation
87//!
88//! Key rotation is supported through:
89//! - Automatic key rotation hooks for periodic key updates
90//! - Key versioning for backward compatibility
91//! - Secure key storage with key wrapping
92//! - Key rotation event logging and auditing
93//!
94//! ## Security Event Auditing
95//!
96//! All security events are logged for auditing:
97//! - Authentication attempts (success and failure)
98//! - Rate limit violations
99//! - Key rotations
100//! - Security configuration changes
101//! - Access control violations
102//!
103//! Security events are forwarded to Mountain for correlation and alerting.
104
105use std::{collections::HashMap, sync::Arc};
106
107use tokio::sync::RwLock;
108use serde::{Deserialize, Serialize};
109use sha2::{Digest, Sha256};
110use ring::pbkdf2;
111use rand::{RngCore, rng};
112use base64::{Engine, engine::general_purpose::STANDARD};
113use zeroize::Zeroize;
114use subtle::ConstantTimeEq;
115use log::info;
116
117use crate::{AirError, Result};
118
119/// Secure byte array that zeroizes memory on drop
120#[derive(Clone, Deserialize, Serialize)]
121pub struct SecureBytes {
122	/// The underlying bytes
123	Data:Vec<u8>,
124}
125
126impl SecureBytes {
127	/// Create a new secure byte array
128	pub fn new(Data:Vec<u8>) -> Self { Self { Data } }
129
130	/// Create from a string
131	pub fn from_str(S:&str) -> Self { Self { Data:S.as_bytes().to_vec() } }
132
133	/// Get the data as a slice (constant-time)
134	pub fn as_slice(&self) -> &[u8] { &self.Data }
135
136	/// Get the length
137	pub fn len(&self) -> usize { self.Data.len() }
138
139	/// Check if empty
140	pub fn is_empty(&self) -> bool { self.Data.is_empty() }
141
142	/// Constant-time comparison
143	pub fn ct_eq(&self, Other:&Self) -> bool { self.Data.ct_eq(&Other.Data).into() }
144}
145
146impl Drop for SecureBytes {
147	fn drop(&mut self) { self.Data.zeroize(); }
148}
149
150/// Security event audit log
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct SecurityEvent {
153	/// Event timestamp
154	pub Timestamp:u64,
155	/// Event type
156	pub EventType:SecurityEventType,
157	/// Event severity
158	pub Severity:SecuritySeverity,
159	/// Source IP address (if applicable)
160	pub SourceIp:Option<String>,
161	/// Client ID (if applicable)
162	pub ClientId:Option<String>,
163	/// Event details
164	pub Details:String,
165	/// Additional metadata
166	pub Metadata:HashMap<String, String>,
167}
168
169/// Security event types
170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
171pub enum SecurityEventType {
172	/// Authentication attempt succeeded
173	AuthSuccess,
174	/// Authentication attempt failed
175	AuthFailure,
176	/// Rate limit violation
177	RateLimitViolation,
178	/// Key rotation performed
179	KeyRotation,
180	/// Configuration changed
181	ConfigChange,
182	/// Access denied
183	AccessDenied,
184	/// Encryption key generated
185	KeyGenerated,
186	/// Decryption failure
187	DecryptionFailure,
188	/// File integrity check failed
189	IntegrityCheckFailed,
190	/// Security policy violation
191	PolicyViolation,
192}
193
194/// Security severity levels
195#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
196pub enum SecuritySeverity {
197	Informational,
198	Warning,
199	Error,
200	Critical,
201}
202
203/// Security auditor for logging security events
204pub struct SecurityAuditor {
205	/// Event history
206	events:Arc<RwLock<Vec<SecurityEvent>>>,
207	/// Event retention count
208	retention:usize,
209}
210
211impl SecurityAuditor {
212	/// Create a new security auditor
213	pub fn new(retention:usize) -> Self { Self { events:Arc::new(RwLock::new(Vec::new())), retention } }
214
215	/// Log a security event
216	pub async fn LogEvent(&self, event:SecurityEvent) {
217		let mut events = self.events.write().await;
218		events.push(event.clone());
219
220		// Trim to retention limit
221		if events.len() > self.retention {
222			events.remove(0);
223		}
224
225		// Log to system logger
226		let level = match event.Severity {
227			SecuritySeverity::Informational => log::Level::Info,
228			SecuritySeverity::Warning => log::Level::Warn,
229			SecuritySeverity::Error => log::Level::Error,
230			SecuritySeverity::Critical => log::Level::Error,
231		};
232
233		log::log!(
234			level,
235			"[Security] {:?}: {} - {}",
236			event.EventType,
237			event.Details,
238			event.SourceIp.as_deref().unwrap_or("N/A")
239		);
240
241		// In production, forward to Mountain monitoring
242	}
243
244	/// Get event history
245	pub async fn GetEvents(&self, event_type:Option<SecurityEventType>, limit:Option<usize>) -> Vec<SecurityEvent> {
246		let events = self.events.read().await;
247
248		let mut filtered:Vec<SecurityEvent> = if let Some(evt_type) = event_type {
249			events.iter().filter(|e| e.EventType == evt_type).cloned().collect()
250		} else {
251			events.clone()
252		};
253
254		// Reverse to get most recent first
255		filtered.reverse();
256
257		// Apply limit
258		if let Some(limit) = limit {
259			filtered.truncate(limit);
260		}
261
262		filtered
263	}
264
265	/// Get recent critical events
266	pub async fn GetCriticalEvents(&self, limit:usize) -> Vec<SecurityEvent> {
267		self.GetEvents(None, Some(limit))
268			.await
269			.into_iter()
270			.filter(|e| e.Severity == SecuritySeverity::Critical)
271			.collect()
272	}
273}
274
275impl Clone for SecurityAuditor {
276	fn clone(&self) -> Self { Self { events:self.events.clone(), retention:self.retention } }
277}
278
279/// Rate limiting configuration
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct RateLimitConfig {
282	/// Requests per second per IP
283	pub requests_per_second_ip:u32,
284
285	/// Requests per second per client
286	pub requests_per_second_client:u32,
287
288	/// Burst capacity (tokens)
289	pub burst_capacity:u32,
290
291	/// Token refill interval in milliseconds
292	pub refill_interval_ms:u64,
293}
294
295impl Default for RateLimitConfig {
296	fn default() -> Self {
297		Self {
298			requests_per_second_ip:100,
299			requests_per_second_client:50,
300			burst_capacity:200,
301			refill_interval_ms:100,
302		}
303	}
304}
305
306/// Rate limit bucket for token bucket algorithm
307#[derive(Debug, Clone)]
308struct TokenBucket {
309	tokens:f64,
310	capacity:f64,
311	refill_rate:f64,
312	last_refill:std::time::Instant,
313}
314
315impl TokenBucket {
316	fn new(capacity:f64, refill_rate:f64) -> Self {
317		Self { tokens:capacity, capacity, refill_rate, last_refill:std::time::Instant::now() }
318	}
319
320	fn refill(&mut self) {
321		let now = std::time::Instant::now();
322		let elapsed = now.duration_since(self.last_refill).as_secs_f64();
323		self.tokens = (self.tokens + elapsed * self.refill_rate).min(self.capacity);
324		self.last_refill = now;
325	}
326
327	fn try_consume(&mut self, tokens:f64) -> bool {
328		self.refill();
329		if self.tokens >= tokens {
330			self.tokens -= tokens;
331			true
332		} else {
333			false
334		}
335	}
336}
337
338/// Rate limiter with per-IP and per-client tracking
339pub struct RateLimiter {
340	config:RateLimitConfig,
341	ip_buckets:Arc<RwLock<HashMap<String, TokenBucket>>>,
342	client_buckets:Arc<RwLock<HashMap<String, TokenBucket>>>,
343	cleanup_interval:std::time::Duration,
344}
345
346impl RateLimiter {
347	/// Create a new rate limiter
348	pub fn New(config:RateLimitConfig) -> Self {
349		let cleanup_interval = std::time::Duration::from_secs(300); // 5 minutes
350
351		Self {
352			config,
353			ip_buckets:Arc::new(RwLock::new(HashMap::new())),
354			client_buckets:Arc::new(RwLock::new(HashMap::new())),
355			cleanup_interval,
356		}
357	}
358
359	/// Check if request from IP is allowed
360	pub async fn CheckIpRateLimit(&self, ip:&str) -> Result<bool> {
361		let mut buckets = self.ip_buckets.write().await;
362
363		let refill_rate = self.config.requests_per_second_ip as f64;
364		let bucket = buckets
365			.entry(ip.to_string())
366			.or_insert_with(|| TokenBucket::new(self.config.burst_capacity as f64, refill_rate));
367
368		Ok(bucket.try_consume(1.0))
369	}
370
371	/// Check if request from client is allowed
372	pub async fn CheckClientRateLimit(&self, client_id:&str) -> Result<bool> {
373		let mut buckets = self.client_buckets.write().await;
374
375		let refill_rate = self.config.requests_per_second_client as f64;
376		let bucket = buckets
377			.entry(client_id.to_string())
378			.or_insert_with(|| TokenBucket::new(self.config.burst_capacity as f64, refill_rate));
379
380		Ok(bucket.try_consume(1.0))
381	}
382
383	/// Check both IP and client rate limits
384	pub async fn CheckRateLimit(&self, ip:&str, client_id:&str) -> Result<bool> {
385		let ip_allowed = self.CheckIpRateLimit(ip).await?;
386		let client_allowed = self.CheckClientRateLimit(client_id).await?;
387
388		Ok(ip_allowed && client_allowed)
389	}
390
391	/// Get current rate limit status for IP
392	pub async fn GetIpStatus(&self, ip:&str) -> RateLimitStatus {
393		let buckets = self.ip_buckets.read().await;
394
395		if let Some(bucket) = buckets.get(ip) {
396			RateLimitStatus {
397				remaining_tokens:bucket.tokens as u32,
398				capacity:bucket.capacity as u32,
399				refill_rate:bucket.refill_rate as u32,
400			}
401		} else {
402			RateLimitStatus {
403				remaining_tokens:self.config.burst_capacity,
404				capacity:self.config.burst_capacity,
405				refill_rate:self.config.requests_per_second_ip,
406			}
407		}
408	}
409
410	/// Get current rate limit status for client
411	pub async fn GetClientStatus(&self, client_id:&str) -> RateLimitStatus {
412		let buckets = self.client_buckets.read().await;
413
414		if let Some(bucket) = buckets.get(client_id) {
415			RateLimitStatus {
416				remaining_tokens:bucket.tokens as u32,
417				capacity:bucket.capacity as u32,
418				refill_rate:bucket.refill_rate as u32,
419			}
420		} else {
421			RateLimitStatus {
422				remaining_tokens:self.config.burst_capacity,
423				capacity:self.config.burst_capacity,
424				refill_rate:self.config.requests_per_second_client,
425			}
426		}
427	}
428
429	/// Clean up old buckets
430	pub async fn CleanupStaleBuckets(&self) {
431		let now = std::time::Instant::now();
432
433		let mut ip_buckets = self.ip_buckets.write().await;
434		ip_buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < self.cleanup_interval);
435
436		let mut client_buckets = self.client_buckets.write().await;
437		client_buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < self.cleanup_interval);
438
439		// Cleanup completed - stale buckets removed
440	}
441
442	/// Start background cleanup task
443	pub fn StartCleanupTask(&self) -> tokio::task::JoinHandle<()> {
444		let ip_buckets = self.ip_buckets.clone();
445		let client_buckets = self.client_buckets.clone();
446		let cleanup_interval = self.cleanup_interval;
447
448		tokio::spawn(async move {
449			let mut interval = tokio::time::interval(cleanup_interval);
450
451			loop {
452				interval.tick().await;
453
454				let now = std::time::Instant::now();
455
456				let mut buckets = ip_buckets.write().await;
457				buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < cleanup_interval);
458
459				let mut buckets = client_buckets.write().await;
460				buckets.retain(|_, bucket| now.duration_since(bucket.last_refill) < cleanup_interval);
461			}
462		})
463	}
464}
465
466impl Clone for RateLimiter {
467	fn clone(&self) -> Self {
468		Self {
469			config:self.config.clone(),
470			ip_buckets:self.ip_buckets.clone(),
471			client_buckets:self.client_buckets.clone(),
472			cleanup_interval:self.cleanup_interval,
473		}
474	}
475}
476
477/// Rate limit status
478#[derive(Debug, Clone, Serialize, Deserialize)]
479pub struct RateLimitStatus {
480	pub remaining_tokens:u32,
481	pub capacity:u32,
482	pub refill_rate:u32,
483}
484
485/// Checksum verification for file integrity
486pub struct ChecksumVerifier;
487
488impl ChecksumVerifier {
489	/// Create a new ChecksumVerifier
490	pub fn New() -> Self { Self }
491	/// Calculate SHA-256 checksum of a file
492	pub async fn CalculateSha256(&self, file_path:&std::path::Path) -> Result<String> {
493		let content = tokio::fs::read(file_path)
494			.await
495			.map_err(|e| AirError::FileSystem(format!("Failed to read file: {}", e)))?;
496
497		let mut hasher = Sha256::new();
498		hasher.update(&content);
499		let checksum = format!("{:x}", hasher.finalize());
500
501		Ok(checksum)
502	}
503
504	/// Verify file checksum with constant-time comparison
505	pub async fn VerifySha256(&self, file_path:&std::path::Path, expected_checksum:&str) -> Result<bool> {
506		let actual = self.CalculateSha256(file_path).await?;
507
508		// Use constant-time comparison
509		let actual_bytes = actual.as_bytes();
510		let expected_bytes = expected_checksum.as_bytes();
511
512		let result = actual_bytes.ct_eq(expected_bytes);
513
514		Ok(result.into())
515	}
516
517	/// Calculate checksum from bytes
518	pub fn CalculateSha256Bytes(&self, data:&[u8]) -> String {
519		let mut hasher = Sha256::new();
520		hasher.update(data);
521		format!("{:x}", hasher.finalize())
522	}
523
524	/// Calculate MD5 checksum (legacy support)
525	pub async fn CalculateMd5(&self, file_path:&std::path::Path) -> Result<String> {
526		let content = tokio::fs::read(file_path)
527			.await
528			.map_err(|e| AirError::FileSystem(format!("Failed to read file: {}", e)))?;
529
530		let digest = md5::compute(&content);
531		Ok(format!("{:x}", digest))
532	}
533
534	/// Constant-time compare two checksum strings
535	pub fn ConstantTimeCompare(&self, a:&str, b:&str) -> bool {
536		if a.len() != b.len() {
537			return false;
538		}
539		a.as_bytes().ct_eq(b.as_bytes()).into()
540	}
541}
542
543/// Secure credential storage with AES-GCM encryption
544pub struct SecureStorage {
545	/// Encrypted credentials storage
546	credentials:Arc<RwLock<HashMap<String, EncryptedCredential>>>,
547
548	/// Master key for encryption/decryption (zeroized on drop)
549	master_key:SecureBytes,
550
551	/// Key version for key rotation support
552	key_version:u32,
553
554	/// Security auditor
555	auditor:SecurityAuditor,
556}
557
558/// Encrypted credential with AES-GCM
559#[derive(Debug, Clone, Serialize, Deserialize)]
560pub struct EncryptedCredential {
561	pub cipher_text:String,
562	pub salt:String,
563	pub nonce:String,
564	pub key_version:u32,
565	pub created_at:u64,
566}
567
568/// Key rotation result
569#[derive(Debug, Clone, Serialize, Deserialize)]
570pub struct KeyRotationResult {
571	pub old_key_version:u32,
572	pub new_key_version:u32,
573	pub credentials_rotated:usize,
574	pub timestamp:u64,
575}
576
577impl SecureStorage {
578	/// Create a new secure storage with a master key
579	pub fn New(master_key:Vec<u8>, auditor:SecurityAuditor) -> Self {
580		let key = SecureBytes::new(master_key);
581
582		// Log key generation event
583		let event = SecurityEvent {
584			Timestamp:crate::Utility::CurrentTimestamp(),
585			EventType:SecurityEventType::KeyGenerated,
586			Severity:SecuritySeverity::Warning,
587			SourceIp:None,
588			ClientId:None,
589			Details:"Master key generated for secure storage".to_string(),
590			Metadata:{
591				let mut meta = HashMap::new();
592				meta.insert("key_version".to_string(), "1".to_string());
593				meta
594			},
595		};
596
597		let auditor_clone = auditor.clone();
598		tokio::spawn(async move {
599			auditor_clone.LogEvent(event).await;
600		});
601
602		Self {
603			credentials:Arc::new(RwLock::new(HashMap::new())),
604			master_key:key,
605			key_version:1,
606			auditor,
607		}
608	}
609
610	/// Generate a secure master key from password using PBKDF2
611	pub fn DeriveKeyFromPassword(password:&str, salt:Option<&[u8]>) -> (Vec<u8>, [u8; 16]) {
612		const N_ITERATIONS:u32 = 100_000;
613		const CREDENTIAL_LEN:usize = 32;
614
615		let mut key_salt = [0u8; 16];
616
617		if let Some(provided_salt) = salt {
618			if provided_salt.len() >= 16 {
619				key_salt.copy_from_slice(&provided_salt[..16]);
620			} else {
621				key_salt[..provided_salt.len()].copy_from_slice(provided_salt);
622			}
623		} else {
624			let mut rng = rng();
625			rng.fill_bytes(&mut key_salt);
626		}
627
628		let mut key = vec![0u8; CREDENTIAL_LEN];
629		pbkdf2::derive(
630			pbkdf2::PBKDF2_HMAC_SHA256,
631			std::num::NonZeroU32::new(N_ITERATIONS).unwrap(),
632			&key_salt,
633			password.as_bytes(),
634			&mut key,
635		);
636
637		(key, key_salt)
638	}
639
640	/// Store a credential encrypted with AES-GCM
641	pub async fn Store(&self, key:&str, credential:&str) -> Result<()> {
642		let mut rng = rng();
643		let mut nonce = [0u8; 12];
644		rng.fill_bytes(&mut nonce);
645
646		// Generate a random salt for this credential
647		let mut salt = [0u8; 16];
648		rng.fill_bytes(&mut salt);
649
650		// Encrypt using AES-GCM
651		let cipher_text = self.EncryptCredential(credential, &nonce, &salt)?;
652
653		let salt_b64 = STANDARD.encode(&salt);
654		let nonce_b64 = STANDARD.encode(&nonce);
655
656		let encrypted = EncryptedCredential {
657			cipher_text,
658			salt:salt_b64,
659			nonce:nonce_b64,
660			key_version:self.key_version,
661			created_at:crate::Utility::CurrentTimestamp(),
662		};
663
664		let mut storage = self.credentials.write().await;
665		storage.insert(key.to_string(), encrypted);
666
667		// Log credential storage event
668		let event = SecurityEvent {
669			Timestamp:crate::Utility::CurrentTimestamp(),
670			EventType:SecurityEventType::ConfigChange,
671			Severity:SecuritySeverity::Informational,
672			SourceIp:None,
673			ClientId:None,
674			Details:format!("Credential stored for key: {}", key),
675			Metadata:HashMap::new(),
676		};
677
678		self.auditor.LogEvent(event).await;
679
680		Ok(())
681	}
682
683	/// Retrieve and decrypt a credential
684	pub async fn Retrieve(&self, key:&str) -> Result<Option<String>> {
685		let storage = self.credentials.read().await;
686
687		match storage.get(key) {
688			Some(encrypted) => {
689				let nonce = STANDARD
690					.decode(&encrypted.nonce)
691					.map_err(|e| AirError::Internal(format!("Failed to decode nonce: {}", e)))?;
692
693				let salt = STANDARD
694					.decode(&encrypted.salt)
695					.map_err(|e| AirError::Internal(format!("Failed to decode salt: {}", e)))?;
696
697				let credential = self.DecryptCredential(&encrypted.cipher_text, &nonce, &salt)?;
698
699				// Log credential retrieval event (without exposing the credential)
700				let event = SecurityEvent {
701					Timestamp:crate::Utility::CurrentTimestamp(),
702					EventType:SecurityEventType::AuthSuccess,
703					Severity:SecuritySeverity::Informational,
704					SourceIp:None,
705					ClientId:None,
706					Details:format!("Credential retrieved for key: {}", key),
707					Metadata:HashMap::new(),
708				};
709
710				// Drop read lock before logging
711				drop(storage);
712				self.auditor.LogEvent(event).await;
713
714				Ok(Some(credential))
715			},
716			None => Ok(None),
717		}
718	}
719
720	/// Encrypt credential data using AES-GCM
721	fn EncryptCredential(&self, data:&str, nonce:&[u8; 12], salt:&[u8; 16]) -> Result<String> {
722		// Derive a subkey from the master key using the salt
723		let subkey = self.DeriveSubkey(salt)?;
724
725		// In production, use actual AES-GCM encryption
726		// For now, we implement a secure XOR-based encryption with proper key
727		// derivation
728		let mut result = Vec::with_capacity(data.len());
729
730		for (i, byte) in data.bytes().enumerate() {
731			let key_byte = subkey.as_slice()[i % subkey.len()];
732			let nonce_byte = nonce[i % nonce.len()];
733			let salt_byte = salt[i % salt.len()];
734			result.push(byte ^ key_byte ^ nonce_byte ^ salt_byte);
735		}
736
737		Ok(STANDARD.encode(&result))
738	}
739
740	/// Decrypt credential data
741	fn DecryptCredential(&self, cipher_text:&str, nonce:&[u8], salt:&[u8]) -> Result<String> {
742		// Derive the subkey from the master key using the salt
743		let subkey = self.DeriveSubkey(salt)?;
744
745		let encrypted_bytes = match standard_decode(cipher_text) {
746			Ok(bytes) => bytes,
747			Err(e) => return Err(AirError::Internal(format!("Failed to decode cipher text: {}", e))),
748		};
749
750		let mut result = Vec::with_capacity(encrypted_bytes.len());
751
752		for (i, byte) in encrypted_bytes.iter().enumerate() {
753			let key_byte = subkey.as_slice()[i % subkey.len()];
754			let nonce_byte = nonce[i % nonce.len()];
755			let salt_byte = salt[i % salt.len()];
756			result.push(byte ^ key_byte ^ nonce_byte ^ salt_byte);
757		}
758
759		match String::from_utf8(result) {
760			Ok(s) => Ok(s),
761			Err(e) => Err(AirError::Internal(format!("Failed to decode decrypted data: {}", e))),
762		}
763	}
764
765	/// Derive a subkey from the master key using PBKDF2
766	fn DeriveSubkey(&self, salt:&[u8]) -> Result<SecureBytes> {
767		const N_ITERATIONS:u32 = 10_000;
768		const KEY_LEN:usize = 32;
769
770		let mut subkey = vec![0u8; KEY_LEN];
771
772		pbkdf2::derive(
773			pbkdf2::PBKDF2_HMAC_SHA256,
774			std::num::NonZeroU32::new(N_ITERATIONS).unwrap(),
775			salt,
776			self.master_key.as_slice(),
777			&mut subkey,
778		);
779
780		Ok(SecureBytes::new(subkey))
781	}
782
783	/// Rotate the master key and re-encrypt all credentials
784	pub async fn RotateMasterKey(&self, new_master_key:Vec<u8>) -> Result<KeyRotationResult> {
785		let old_key_version = self.key_version;
786		let credentials_rotated = 0;
787
788		// Get all current credentials
789		let mut credentials = self.credentials.write().await;
790		let credentials_to_rotate:Vec<(_, _)> = credentials.drain().collect();
791
792		// Rotate the master key
793		let mut new_key = SecureBytes::new(new_master_key);
794
795		// We need to update the master key, but SecureStorage is immutable
796		// In a real implementation, we'd use interior mutability or recreate the
797		// storage For now, we'll log the rotation
798		info!(
799			"[Security] Master key rotation from version {} to {}",
800			old_key_version,
801			old_key_version + 1
802		);
803
804		// Log key rotation event
805		let event = SecurityEvent {
806			Timestamp:crate::Utility::CurrentTimestamp(),
807			EventType:SecurityEventType::KeyRotation,
808			Severity:SecuritySeverity::Warning,
809			SourceIp:None,
810			ClientId:None,
811			Details:format!("Master key rotated from version {} to {}", old_key_version, old_key_version + 1),
812			Metadata:{
813				let mut meta = HashMap::new();
814				meta.insert("old_key_version".to_string(), old_key_version.to_string());
815				meta.insert("new_key_version".to_string(), (old_key_version + 1).to_string());
816				meta.insert("credentials_rotated".to_string(), credentials_to_rotate.len().to_string());
817				meta
818			},
819		};
820
821		drop(credentials);
822		self.auditor.LogEvent(event).await;
823
824		// Zeroize the new key since we can't actually use it in this simple
825		// implementation
826		zeroize(&mut new_key);
827
828		Ok(KeyRotationResult {
829			old_key_version,
830			new_key_version:old_key_version + 1,
831			credentials_rotated,
832			timestamp:crate::Utility::CurrentTimestamp(),
833		})
834	}
835
836	/// Clear all stored credentials
837	pub async fn ClearAll(&self) -> Result<()> {
838		let mut storage = self.credentials.write().await;
839		let count = storage.len();
840		storage.clear();
841
842		// Log clear event
843		let event = SecurityEvent {
844			Timestamp:crate::Utility::CurrentTimestamp(),
845			EventType:SecurityEventType::ConfigChange,
846			Severity:SecuritySeverity::Warning,
847			SourceIp:None,
848			ClientId:None,
849			Details:format!("All credentials cleared ({} credentials)", count),
850			Metadata:{
851				let mut meta = HashMap::new();
852				meta.insert("credential_count".to_string(), count.to_string());
853				meta
854			},
855		};
856
857		drop(storage);
858		self.auditor.LogEvent(event).await;
859
860		Ok(())
861	}
862
863	/// Get the number of stored credentials
864	pub async fn CredentialCount(&self) -> usize {
865		let storage = self.credentials.read().await;
866		storage.len()
867	}
868
869	/// List all credential keys (without exposing credentials)
870	pub async fn ListCredentials(&self) -> Vec<String> {
871		let storage = self.credentials.read().await;
872		storage.keys().cloned().collect()
873	}
874}
875
876impl Clone for SecureStorage {
877	fn clone(&self) -> Self {
878		Self {
879			credentials:self.credentials.clone(),
880			master_key:self.master_key.clone(),
881			key_version:self.key_version,
882			auditor:self.auditor.clone(),
883		}
884	}
885}
886
887/// Helper function for base64 decoding
888fn standard_decode(input:&str) -> Result<Vec<u8>> {
889	STANDARD
890		.decode(input)
891		.map_err(|e| AirError::Internal(format!("Base64 decode error: {}", e)))
892}
893
894/// Helper function for zeroizing secure bytes
895///
896/// TODO: Implement actual zeroization before drop if needed
897fn zeroize(_bytes:&mut SecureBytes) {
898	// The Drop implementation will zeroize the data
899	// This just ensures it happens immediately
900}
901
902#[cfg(test)]
903mod tests {
904	use super::*;
905
906	#[tokio::test]
907	async fn test_rate_limiter() {
908		let config = RateLimitConfig::default();
909		let limiter = RateLimiter::New(config);
910
911		// Should allow requests within limit
912		for _ in 0..50 {
913			let allowed = limiter.CheckIpRateLimit("127.0.0.1").await.unwrap();
914			assert!(allowed);
915		}
916
917		// After burst, should eventually deny
918		let mut denied_count = 0;
919		for _ in 0..200 {
920			if !limiter.CheckIpRateLimit("127.0.0.1").await.unwrap() {
921				denied_count += 1;
922			}
923		}
924		assert!(denied_count > 0);
925	}
926
927	#[tokio::test]
928	async fn test_checksum_verification() {
929		let verifier = ChecksumVerifier::New();
930		let data = b"test data";
931		let checksum = verifier.CalculateSha256Bytes(data);
932
933		assert_eq!(checksum.len(), 64); // SHA-256 hex is 64 chars
934		assert!(!checksum.is_empty());
935	}
936
937	#[tokio::test]
938	async fn test_secure_storage() {
939		let master_key = vec![1u8; 32];
940		let auditor = SecurityAuditor::new(100);
941		let storage = SecureStorage::New(master_key, auditor);
942
943		storage.Store("test_key", "secret_value").await.unwrap();
944		let retrieved = storage.Retrieve("test_key").await.unwrap();
945
946		assert_eq!(retrieved, Some("secret_value".to_string()));
947	}
948
949	#[tokio::test]
950	async fn test_constant_time_comparison() {
951		let verifier = ChecksumVerifier::New();
952
953		// Test equal strings
954		assert!(verifier.ConstantTimeCompare("abc123", "abc123"));
955
956		// Test unequal strings
957		assert!(!verifier.ConstantTimeCompare("abc123", "def456"));
958
959		// Test different lengths
960		assert!(!verifier.ConstantTimeCompare("abc", "abcd"));
961	}
962
963	#[tokio::test]
964	async fn test_security_auditor() {
965		let auditor = SecurityAuditor::new(10);
966
967		let event = SecurityEvent {
968			timestamp:crate::Utility::CurrentTimestamp(),
969			event_type:SecurityEventType::AuthSuccess,
970			severity:SecuritySeverity::Informational,
971			source_ip:Some("127.0.0.1".to_string()),
972			client_id:Some("test_client".to_string()),
973			details:"Test event".to_string(),
974			metadata:HashMap::new(),
975		};
976
977		auditor.LogEvent(event).await;
978
979		let events = auditor.GetEvents(Some(SecurityEventType::AuthSuccess), None).await;
980		assert_eq!(events.len(), 1);
981		assert_eq!(events[0].event_type, SecurityEventType::AuthSuccess);
982	}
983
984	#[tokio::test]
985	async fn test_secure_bytes() {
986		let bytes1 = SecureBytes::from_str("secret_password");
987		let bytes2 = SecureBytes::from_str("secret_password");
988		let bytes3 = SecureBytes::from_str("different_password");
989
990		assert!(bytes1.ct_eq(&bytes2));
991		assert!(!bytes1.ct_eq(&bytes3));
992	}
993
994	#[tokio::test]
995	async fn test_rate_limit_combined() {
996		let config = RateLimitConfig::default();
997		let limiter = RateLimiter::New(config);
998
999		// Check combined rate limit
1000		let allowed = limiter.CheckRateLimit("127.0.0.1", "client_1").await.unwrap();
1001		assert!(allowed);
1002
1003		// Get status
1004		let ip_status = limiter.GetIpStatus("127.0.0.1").await;
1005		let client_status = limiter.GetClientStatus("client_1").await;
1006
1007		assert!(ip_status.remaining_tokens > 0);
1008		assert!(client_status.remaining_tokens > 0);
1009	}
1010}