Mountain/IPC/Encryption/
SecureChannel.rs1use ring::{
36 aead::{self, AES_256_GCM, LessSafeKey, UnboundKey},
37 hmac,
38 rand::{SecureRandom, SystemRandom},
39};
40use serde::{Deserialize, Serialize};
41
42use super::super::Message::Types::TauriIPCMessage;
43use crate::dev_log;
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct EncryptedMessage {
71 pub nonce:Vec<u8>,
73
74 pub ciphertext:Vec<u8>,
76
77 pub hmac_tag:Vec<u8>,
79}
80
81impl EncryptedMessage {
82 pub fn new(nonce:Vec<u8>, ciphertext:Vec<u8>, hmac_tag:Vec<u8>) -> Self { Self { nonce, ciphertext, hmac_tag } }
84
85 pub fn is_valid(&self) -> bool {
87 self.nonce.len() == 12 && !self.ciphertext.is_empty()
89
90 && !self.hmac_tag.is_empty()
91 }
92}
93
94pub struct SecureMessageChannel {
158 encryption_key:LessSafeKey,
160
161 hmac_key:Vec<u8>,
163}
164
165impl SecureMessageChannel {
166 pub fn new() -> Result<Self, String> {
181 dev_log!("encryption", "[SecureMessageChannel] Creating new secure channel");
182
183 let rng = SystemRandom::new();
184
185 let mut encryption_key_bytes = vec![0u8; 32];
187
188 rng.fill(&mut encryption_key_bytes)
189 .map_err(|e| format!("Failed to generate encryption key: {}", e))?;
190
191 let unbound_key = UnboundKey::new(&AES_256_GCM, &encryption_key_bytes)
192 .map_err(|e| format!("Failed to create unbound key: {}", e))?;
193
194 let encryption_key = LessSafeKey::new(unbound_key);
195
196 let mut hmac_key = vec![0u8; 32];
198
199 rng.fill(&mut hmac_key)
200 .map_err(|e| format!("Failed to generate HMAC key: {}", e))?;
201
202 dev_log!("encryption", "[SecureMessageChannel] Secure channel created successfully");
203
204 Ok(Self { encryption_key, hmac_key })
205 }
206
207 pub fn encrypt_message(&self, message:&TauriIPCMessage) -> Result<EncryptedMessage, String> {
225 dev_log!(
226 "encryption",
227 "[SecureMessageChannel] Encrypting message on channel: {}",
228 message.channel
229 );
230
231 let serialized_message =
233 serde_json::to_vec(message).map_err(|e| format!("Failed to serialize message: {}", e))?;
234
235 let mut nonce = [0u8; 12];
237
238 SystemRandom::new()
239 .fill(&mut nonce)
240 .map_err(|e| format!("Failed to generate nonce: {}", e))?;
241
242 let mut in_out = serialized_message.clone();
244
245 self.encryption_key
246 .seal_in_place_append_tag(aead::Nonce::assume_unique_for_key(nonce), aead::Aad::empty(), &mut in_out)
247 .map_err(|e| format!("Encryption failed: {}", e))?;
248
249 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &self.hmac_key);
251
252 let hmac_tag = hmac::sign(&hmac_key, &in_out);
253
254 let encrypted_message =
255 EncryptedMessage { nonce:nonce.to_vec(), ciphertext:in_out, hmac_tag:hmac_tag.as_ref().to_vec() };
256
257 dev_log!(
258 "encryption",
259 "[SecureMessageChannel] Message encrypted: {} bytes -> {} bytes",
260 serialized_message.len(),
261 encrypted_message.ciphertext.len()
262 );
263
264 Ok(encrypted_message)
265 }
266
267 pub fn decrypt_message(&self, encrypted:&EncryptedMessage) -> Result<TauriIPCMessage, String> {
285 dev_log!("encryption", "[SecureMessageChannel] Decrypting message");
286
287 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &self.hmac_key);
289
290 hmac::verify(&hmac_key, &encrypted.ciphertext, &encrypted.hmac_tag)
291 .map_err(|_| "HMAC verification failed - message may be tampered".to_string())?;
292
293 let nonce_slice:&[u8] = &encrypted.nonce;
295
296 let nonce_array:[u8; 12] = nonce_slice
297 .try_into()
298 .map_err(|_| "Invalid nonce length - must be 12 bytes".to_string())?;
299
300 let nonce = aead::Nonce::assume_unique_for_key(nonce_array);
301
302 let mut in_out = encrypted.ciphertext.clone();
304
305 self.encryption_key
306 .open_in_place(nonce, aead::Aad::empty(), &mut in_out)
307 .map_err(|e| format!("Decryption failed: {}", e))?;
308
309 let plaintext_len = in_out.len() - AES_256_GCM.tag_len();
311
312 in_out.truncate(plaintext_len);
313
314 let message:TauriIPCMessage =
316 serde_json::from_slice(&in_out).map_err(|e| format!("Failed to deserialize message: {}", e))?;
317
318 dev_log!(
319 "encryption",
320 "[SecureMessageChannel] Message decrypted successfully on channel: {}",
321 message.channel
322 );
323
324 Ok(message)
325 }
326
327 pub fn rotate_keys(&mut self) -> Result<(), String> {
342 dev_log!("encryption", "[SecureMessageChannel] Rotating encryption keys");
343
344 *self = Self::new()?;
345
346 dev_log!("encryption", "[SecureMessageChannel] Keys rotated successfully");
347
348 Ok(())
349 }
350
351 pub fn hmac_tag_length(&self) -> usize {
353 32 }
355
356 pub fn nonce_length(&self) -> usize {
358 12 }
360
361 pub fn auth_tag_length(&self) -> usize { AES_256_GCM.tag_len() }
363
364 pub fn key_length(&self) -> usize {
366 32 }
368}
369
370#[cfg(test)]
371#[allow(unused_imports)]
372mod tests {
373
374 use super::*;
375
376 fn create_test_message() -> TauriIPCMessage {
377 TauriIPCMessage::new(
378 "test_channel".to_string(),
379 serde_json::json!({
380 "data": "sensitive information that should be encrypted",
381 "id": 12345
382 }),
383 Some("test_sender".to_string()),
384 )
385 }
386
387 #[test]
388 fn test_secure_channel_creation() {
389 let channel = SecureMessageChannel::new();
390
391 assert!(channel.is_ok());
392 }
393
394 #[test]
395 fn test_encrypt_and_decrypt() {
396 let channel = SecureMessageChannel::new().unwrap();
397
398 let original_message = create_test_message();
399
400 let encrypted = channel.encrypt_message(&original_message).unwrap();
402
403 assert!(encrypted.is_valid());
404
405 let decrypted = channel.decrypt_message(&encrypted).unwrap();
407
408 assert_eq!(decrypted.channel, original_message.channel);
410
411 assert_eq!(decrypted.data, original_message.data);
412
413 assert_eq!(decrypted.sender, original_message.sender);
414 }
415
416 #[test]
417 fn test_encryption_produces_different_outputs() {
418 let channel = SecureMessageChannel::new().unwrap();
419
420 let message = create_test_message();
421
422 let encrypted1 = channel.encrypt_message(&message).unwrap();
423
424 let encrypted2 = channel.encrypt_message(&message).unwrap();
425
426 assert_ne!(encrypted1.nonce, encrypted2.nonce);
428
429 assert_ne!(encrypted1.ciphertext, encrypted2.ciphertext);
430 }
431
432 #[test]
433 fn test_tampered_message_fails_hmac_verification() {
434 let channel = SecureMessageChannel::new().unwrap();
435
436 let message = create_test_message();
437
438 let mut encrypted = channel.encrypt_message(&message).unwrap();
439
440 if !encrypted.ciphertext.is_empty() {
442 encrypted.ciphertext[0] ^= 0xFF;
443 }
444
445 let result = channel.decrypt_message(&encrypted);
447
448 assert!(result.is_err());
449
450 assert!(result.unwrap_err().contains("HMAC verification failed"));
451 }
452
453 #[test]
454 fn test_invalid_nonce_length() {
455 let channel = SecureMessageChannel::new().unwrap();
456
457 let message = create_test_message();
458
459 let mut encrypted = channel.encrypt_message(&message).unwrap();
460
461 encrypted.nonce = vec![0u8; 16]; let result = channel.decrypt_message(&encrypted);
465
466 assert!(result.is_err());
467
468 assert!(result.unwrap_err().contains("Invalid nonce length"));
469 }
470
471 #[test]
472 fn test_message_channel_key_lengths() {
473 let channel = SecureMessageChannel::new().unwrap();
474
475 assert_eq!(channel.key_length(), 32);
476
477 assert_eq!(channel.nonce_length(), 12);
478
479 assert_eq!(channel.auth_tag_length(), 16); assert_eq!(channel.hmac_tag_length(), 32); }
483
484 #[test]
485 fn test_key_rotation() {
486 let mut channel = SecureMessageChannel::new().unwrap();
487
488 let message = create_test_message();
489
490 let encrypted1 = channel.encrypt_message(&message).unwrap();
492
493 let result = channel.rotate_keys();
495
496 assert!(result.is_ok());
497
498 let decrypted1 = channel.decrypt_message(&encrypted1).unwrap();
500
501 assert_eq!(decrypted1.channel, message.channel);
502
503 let encrypted2 = channel.encrypt_message(&message).unwrap();
505
506 let decrypted2 = channel.decrypt_message(&encrypted2).unwrap();
507
508 assert_eq!(decrypted2.channel, message.channel);
509
510 assert_ne!(encrypted1.nonce, encrypted2.nonce);
512 }
513
514 #[test]
515 fn test_empty_message() {
516 let channel = SecureMessageChannel::new().unwrap();
517
518 let message = TauriIPCMessage::new("test".to_string(), serde_json::json!(null), None);
519
520 let encrypted = channel.encrypt_message(&message).unwrap();
521
522 let decrypted = channel.decrypt_message(&encrypted).unwrap();
523
524 assert_eq!(decrypted.channel, "test");
525 }
526}