Skip to main content

Mountain/IPC/Enhanced/SecureMessageChannel/
EncryptionKey.rs

1#![allow(non_snake_case)]
2
3//! Wrapper around `ring::aead::LessSafeKey` plus metadata -
4//! creation timestamp, random key id, and a usage counter the
5//! channel bumps on each encrypt. Private constructors are
6//! exposed via `pub(super)` so the channel can manage rotation
7//! while keeping callers out of the raw key material.
8
9use std::time::{Duration, SystemTime};
10
11use ring::{
12	aead::{AES_256_GCM, LessSafeKey, UnboundKey},
13	rand::{SecureRandom, SystemRandom},
14};
15
16#[derive(Debug, Clone)]
17pub struct Struct {
18	pub(super) key:LessSafeKey,
19
20	pub(super) created_at:SystemTime,
21
22	pub(super) key_id:String,
23
24	pub(super) usage_count:usize,
25}
26
27impl Struct {
28	pub(super) fn new(key_bytes:&[u8]) -> Result<Self, String> {
29		let unbound_key =
30			UnboundKey::new(&AES_256_GCM, key_bytes).map_err(|e| format!("Failed to create unbound key: {}", e))?;
31
32		Ok(Self {
33			key:LessSafeKey::new(unbound_key),
34			created_at:SystemTime::now(),
35			key_id:Self::generate_key_id(),
36			usage_count:0,
37		})
38	}
39
40	fn generate_key_id() -> String {
41		let rng = SystemRandom::new();
42
43		let mut id_bytes = [0u8; 8];
44
45		rng.fill(&mut id_bytes).unwrap();
46
47		hex::encode(id_bytes)
48	}
49
50	pub(super) fn is_expired(&self, rotation_interval:Duration) -> bool {
51		self.created_at.elapsed().unwrap_or_default() > rotation_interval
52	}
53
54	pub(super) fn increment_usage(&mut self) { self.usage_count += 1; }
55}