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 && !self.hmac_tag.is_empty()
90 }
91}
92
93pub struct SecureMessageChannel {
157 encryption_key:LessSafeKey,
159
160 hmac_key:Vec<u8>,
162}
163
164impl SecureMessageChannel {
165 pub fn new() -> Result<Self, String> {
180 dev_log!("encryption", "[SecureMessageChannel] Creating new secure channel");
181
182 let rng = SystemRandom::new();
183
184 let mut encryption_key_bytes = vec![0u8; 32];
186
187 rng.fill(&mut encryption_key_bytes)
188 .map_err(|e| format!("Failed to generate encryption key: {}", e))?;
189
190 let unbound_key = UnboundKey::new(&AES_256_GCM, &encryption_key_bytes)
191 .map_err(|e| format!("Failed to create unbound key: {}", e))?;
192
193 let encryption_key = LessSafeKey::new(unbound_key);
194
195 let mut hmac_key = vec![0u8; 32];
197
198 rng.fill(&mut hmac_key)
199 .map_err(|e| format!("Failed to generate HMAC key: {}", e))?;
200
201 dev_log!("encryption", "[SecureMessageChannel] Secure channel created successfully");
202
203 Ok(Self { encryption_key, hmac_key })
204 }
205
206 pub fn encrypt_message(&self, message:&TauriIPCMessage) -> Result<EncryptedMessage, String> {
224 dev_log!(
225 "encryption",
226 "[SecureMessageChannel] Encrypting message on channel: {}",
227 message.channel
228 );
229
230 let serialized_message =
232 serde_json::to_vec(message).map_err(|e| format!("Failed to serialize message: {}", e))?;
233
234 let mut nonce = [0u8; 12];
236
237 SystemRandom::new()
238 .fill(&mut nonce)
239 .map_err(|e| format!("Failed to generate nonce: {}", e))?;
240
241 let mut in_out = serialized_message.clone();
243
244 self.encryption_key
245 .seal_in_place_append_tag(aead::Nonce::assume_unique_for_key(nonce), aead::Aad::empty(), &mut in_out)
246 .map_err(|e| format!("Encryption failed: {}", e))?;
247
248 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &self.hmac_key);
250
251 let hmac_tag = hmac::sign(&hmac_key, &in_out);
252
253 let encrypted_message =
254 EncryptedMessage { nonce:nonce.to_vec(), ciphertext:in_out, hmac_tag:hmac_tag.as_ref().to_vec() };
255
256 dev_log!(
257 "encryption",
258 "[SecureMessageChannel] Message encrypted: {} bytes -> {} bytes",
259 serialized_message.len(),
260 encrypted_message.ciphertext.len()
261 );
262
263 Ok(encrypted_message)
264 }
265
266 pub fn decrypt_message(&self, encrypted:&EncryptedMessage) -> Result<TauriIPCMessage, String> {
284 dev_log!("encryption", "[SecureMessageChannel] Decrypting message");
285
286 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &self.hmac_key);
288
289 hmac::verify(&hmac_key, &encrypted.ciphertext, &encrypted.hmac_tag)
290 .map_err(|_| "HMAC verification failed - message may be tampered".to_string())?;
291
292 let nonce_slice:&[u8] = &encrypted.nonce;
294
295 let nonce_array:[u8; 12] = nonce_slice
296 .try_into()
297 .map_err(|_| "Invalid nonce length - must be 12 bytes".to_string())?;
298
299 let nonce = aead::Nonce::assume_unique_for_key(nonce_array);
300
301 let mut in_out = encrypted.ciphertext.clone();
303
304 self.encryption_key
305 .open_in_place(nonce, aead::Aad::empty(), &mut in_out)
306 .map_err(|e| format!("Decryption failed: {}", e))?;
307
308 let plaintext_len = in_out.len() - AES_256_GCM.tag_len();
310
311 in_out.truncate(plaintext_len);
312
313 let message:TauriIPCMessage =
315 serde_json::from_slice(&in_out).map_err(|e| format!("Failed to deserialize message: {}", e))?;
316
317 dev_log!(
318 "encryption",
319 "[SecureMessageChannel] Message decrypted successfully on channel: {}",
320 message.channel
321 );
322
323 Ok(message)
324 }
325
326 pub fn rotate_keys(&mut self) -> Result<(), String> {
341 dev_log!("encryption", "[SecureMessageChannel] Rotating encryption keys");
342
343 *self = Self::new()?;
344
345 dev_log!("encryption", "[SecureMessageChannel] Keys rotated successfully");
346
347 Ok(())
348 }
349
350 pub fn hmac_tag_length(&self) -> usize {
352 32 }
354
355 pub fn nonce_length(&self) -> usize {
357 12 }
359
360 pub fn auth_tag_length(&self) -> usize { AES_256_GCM.tag_len() }
362
363 pub fn key_length(&self) -> usize {
365 32 }
367}
368
369#[cfg(test)]
370#[allow(unused_imports)]
371mod tests {
372
373 use super::*;
374
375 fn create_test_message() -> TauriIPCMessage {
376 TauriIPCMessage::new(
377 "test_channel".to_string(),
378 serde_json::json!({
379 "data": "sensitive information that should be encrypted",
380 "id": 12345
381 }),
382 Some("test_sender".to_string()),
383 )
384 }
385
386 #[test]
387 fn test_secure_channel_creation() {
388 let channel = SecureMessageChannel::new();
389
390 assert!(channel.is_ok());
391 }
392
393 #[test]
394 fn test_encrypt_and_decrypt() {
395 let channel = SecureMessageChannel::new().unwrap();
396
397 let original_message = create_test_message();
398
399 let encrypted = channel.encrypt_message(&original_message).unwrap();
401
402 assert!(encrypted.is_valid());
403
404 let decrypted = channel.decrypt_message(&encrypted).unwrap();
406
407 assert_eq!(decrypted.channel, original_message.channel);
409
410 assert_eq!(decrypted.data, original_message.data);
411
412 assert_eq!(decrypted.sender, original_message.sender);
413 }
414
415 #[test]
416 fn test_encryption_produces_different_outputs() {
417 let channel = SecureMessageChannel::new().unwrap();
418
419 let message = create_test_message();
420
421 let encrypted1 = channel.encrypt_message(&message).unwrap();
422
423 let encrypted2 = channel.encrypt_message(&message).unwrap();
424
425 assert_ne!(encrypted1.nonce, encrypted2.nonce);
427
428 assert_ne!(encrypted1.ciphertext, encrypted2.ciphertext);
429 }
430
431 #[test]
432 fn test_tampered_message_fails_hmac_verification() {
433 let channel = SecureMessageChannel::new().unwrap();
434
435 let message = create_test_message();
436
437 let mut encrypted = channel.encrypt_message(&message).unwrap();
438
439 if !encrypted.ciphertext.is_empty() {
441 encrypted.ciphertext[0] ^= 0xFF;
442 }
443
444 let result = channel.decrypt_message(&encrypted);
446
447 assert!(result.is_err());
448
449 assert!(result.unwrap_err().contains("HMAC verification failed"));
450 }
451
452 #[test]
453 fn test_invalid_nonce_length() {
454 let channel = SecureMessageChannel::new().unwrap();
455
456 let message = create_test_message();
457
458 let mut encrypted = channel.encrypt_message(&message).unwrap();
459
460 encrypted.nonce = vec![0u8; 16]; let result = channel.decrypt_message(&encrypted);
464
465 assert!(result.is_err());
466
467 assert!(result.unwrap_err().contains("Invalid nonce length"));
468 }
469
470 #[test]
471 fn test_message_channel_key_lengths() {
472 let channel = SecureMessageChannel::new().unwrap();
473
474 assert_eq!(channel.key_length(), 32);
475
476 assert_eq!(channel.nonce_length(), 12);
477
478 assert_eq!(channel.auth_tag_length(), 16); assert_eq!(channel.hmac_tag_length(), 32); }
481
482 #[test]
483 fn test_key_rotation() {
484 let mut channel = SecureMessageChannel::new().unwrap();
485
486 let message = create_test_message();
487
488 let encrypted1 = channel.encrypt_message(&message).unwrap();
490
491 let result = channel.rotate_keys();
493
494 assert!(result.is_ok());
495
496 let decrypted1 = channel.decrypt_message(&encrypted1).unwrap();
498
499 assert_eq!(decrypted1.channel, message.channel);
500
501 let encrypted2 = channel.encrypt_message(&message).unwrap();
503
504 let decrypted2 = channel.decrypt_message(&encrypted2).unwrap();
505
506 assert_eq!(decrypted2.channel, message.channel);
507
508 assert_ne!(encrypted1.nonce, encrypted2.nonce);
510 }
511
512 #[test]
513 fn test_empty_message() {
514 let channel = SecureMessageChannel::new().unwrap();
515
516 let message = TauriIPCMessage::new("test".to_string(), serde_json::json!(null), None);
517
518 let encrypted = channel.encrypt_message(&message).unwrap();
519
520 let decrypted = channel.decrypt_message(&encrypted).unwrap();
521
522 assert_eq!(decrypted.channel, "test");
523 }
524}