1use super::key_exchange::KeyExchange;
4use super::types::*;
5use crate::identity::FourWordAddress;
6use crate::messaging::user_handle::UserHandle;
7use anyhow::Result;
8use blake3::Hasher;
9use chacha20poly1305::{
10 ChaCha20Poly1305, Nonce,
11 aead::{Aead, AeadCore, KeyInit, OsRng},
12};
13use std::collections::HashMap;
14use std::sync::Arc;
15use tokio::sync::RwLock;
16
17pub struct SecureMessaging {
19 identity: FourWordAddress,
21 pub key_exchange: KeyExchange,
23 session_keys: Arc<RwLock<HashMap<FourWordAddress, SessionKey>>>,
25 device_keys: Arc<RwLock<HashMap<DeviceId, DeviceKey>>>,
27}
28
29impl SecureMessaging {
30 pub fn new(identity: FourWordAddress) -> Result<Self> {
32 let key_exchange = KeyExchange::new(identity.clone())?;
33
34 Ok(Self {
35 identity,
36 key_exchange,
37 session_keys: Arc::new(RwLock::new(HashMap::new())),
38 device_keys: Arc::new(RwLock::new(HashMap::new())),
39 })
40 }
41
42 pub async fn encrypt_message(&self, message: &RichMessage) -> Result<EncryptedMessage> {
44 let session_key = if let Ok(key) = self
50 .key_exchange
51 .get_session_key(&message.channel_id.0.to_string().into())
52 .await
53 {
54 key
55 } else {
56 let mut hasher = Hasher::new();
58 hasher.update(self.identity.to_string().as_bytes());
59 hasher.update(message.channel_id.0.as_bytes());
60 let key_material = hasher.finalize();
61 key_material.as_bytes()[..32].to_vec()
62 };
63
64 let cipher = ChaCha20Poly1305::new_from_slice(&session_key)?;
66 let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
67
68 let plaintext = serde_json::to_vec(message)?;
70
71 let ciphertext = cipher
72 .encrypt(&nonce, plaintext.as_ref())
73 .map_err(|e| anyhow::anyhow!("Encryption failed: {}", e))?;
74
75 Ok(EncryptedMessage {
76 id: message.id,
77 channel_id: message.channel_id,
78 sender: self.identity.clone(),
79 ciphertext,
80 nonce: nonce.to_vec(),
81 key_id: self.identity.to_string(),
82 })
83 }
84
85 pub async fn decrypt_message(&self, encrypted: EncryptedMessage) -> Result<RichMessage> {
87 let session_key = self.get_or_create_session_key(&encrypted.sender).await?;
89
90 let cipher = ChaCha20Poly1305::new_from_slice(&session_key.key)?;
92 let nonce = Nonce::from_slice(&encrypted.nonce);
93
94 let plaintext = cipher
95 .decrypt(nonce, encrypted.ciphertext.as_ref())
96 .map_err(|e| anyhow::anyhow!("Decryption failed: {}", e))?;
97
98 let message: RichMessage = serde_json::from_slice(&plaintext)?;
100
101 Ok(message)
102 }
103
104 pub fn sign_message(&self, message: &RichMessage) -> Vec<u8> {
106 let mut hasher = Hasher::new();
108 hasher.update(&serde_json::to_vec(message).unwrap_or_default());
109 let hash = hasher.finalize();
110
111 hash.as_bytes().to_vec()
114 }
115
116 pub fn verify_message(&self, message: &RichMessage) -> bool {
118 let mut hasher = Hasher::new();
120 hasher.update(&serde_json::to_vec(message).unwrap_or_default());
121 let hash = hasher.finalize();
122
123 message.signature.signature == hash.as_bytes().to_vec()
126 }
127
128 pub async fn establish_session(&self, peer: &FourWordAddress) -> Result<SessionKey> {
130 let mut hasher = Hasher::new();
135 hasher.update(self.identity.to_string().as_bytes());
136 hasher.update(peer.to_string().as_bytes());
137 let key_material = hasher.finalize();
138
139 let session_key = SessionKey {
140 peer: peer.clone(),
141 key: key_material.as_bytes()[..32].to_vec(),
142 established_at: chrono::Utc::now(),
143 expires_at: chrono::Utc::now() + chrono::Duration::hours(24),
144 };
145
146 let mut keys = self.session_keys.write().await;
148 keys.insert(peer.clone(), session_key.clone());
149
150 Ok(session_key)
151 }
152
153 pub async fn rotate_session_keys(&self) -> Result<()> {
155 let mut keys = self.session_keys.write().await;
156 let now = chrono::Utc::now();
157
158 keys.retain(|_, key| key.expires_at > now);
160
161 let rotation_threshold = now - chrono::Duration::hours(12);
163 for (peer, key) in keys.iter_mut() {
164 if key.established_at < rotation_threshold {
165 let new_key = self.establish_session(peer).await?;
167 *key = new_key;
168 }
169 }
170
171 Ok(())
172 }
173
174 pub async fn register_device(&self, device_id: DeviceId) -> Result<DeviceKey> {
176 let mut hasher = Hasher::new();
178 hasher.update(self.identity.to_string().as_bytes());
179 hasher.update(device_id.0.as_bytes());
180 let key_material = hasher.finalize();
181
182 let device_key = DeviceKey {
183 device_id: device_id.clone(),
184 public_key: key_material.as_bytes().to_vec(),
185 private_key: vec![0; 32], created_at: chrono::Utc::now(),
187 };
188
189 let mut keys = self.device_keys.write().await;
191 keys.insert(device_id, device_key.clone());
192
193 Ok(device_key)
194 }
195
196 pub async fn encrypt_for_devices(
198 &self,
199 message: &RichMessage,
200 devices: Vec<DeviceId>,
201 ) -> Result<Vec<EncryptedMessage>> {
202 let mut encrypted_messages = Vec::new();
203
204 for device_id in devices {
205 let keys = self.device_keys.read().await;
207 if let Some(device_key) = keys.get(&device_id) {
208 let encrypted = self
210 .encrypt_with_key(message, &device_key.public_key)
211 .await?;
212 encrypted_messages.push(encrypted);
213 }
214 }
215
216 Ok(encrypted_messages)
217 }
218
219 pub async fn create_ephemeral_session(
221 &self,
222 peer: &FourWordAddress,
223 ) -> Result<EphemeralSession> {
224 let mut hasher = Hasher::new();
227 hasher.update(&chrono::Utc::now().timestamp().to_le_bytes());
228 hasher.update(peer.to_string().as_bytes());
229 let key_material = hasher.finalize();
230
231 Ok(EphemeralSession {
232 peer: peer.clone(),
233 ephemeral_public: key_material.as_bytes()[..32].to_vec(),
234 ephemeral_private: key_material.as_bytes().get(32..64).unwrap_or(&[]).to_vec(),
235 created_at: chrono::Utc::now(),
236 message_count: 0,
237 })
238 }
239
240 async fn get_or_create_session_key(&self, peer: &FourWordAddress) -> Result<SessionKey> {
242 let keys = self.session_keys.read().await;
243
244 if let Some(key) = keys.get(peer)
245 && key.expires_at > chrono::Utc::now()
246 {
247 return Ok(key.clone());
248 }
249 drop(keys);
250
251 self.establish_session(peer).await
253 }
254
255 async fn encrypt_with_key(
257 &self,
258 message: &RichMessage,
259 key: &[u8],
260 ) -> Result<EncryptedMessage> {
261 let cipher = ChaCha20Poly1305::new_from_slice(&key[..32])?;
262 let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
263
264 let plaintext = serde_json::to_vec(message)?;
265 let ciphertext = cipher
266 .encrypt(&nonce, plaintext.as_ref())
267 .map_err(|e| anyhow::anyhow!("Encryption failed: {}", e))?;
268
269 Ok(EncryptedMessage {
270 id: message.id,
271 channel_id: message.channel_id,
272 sender: self.identity.clone(),
273 ciphertext,
274 nonce: nonce.to_vec(),
275 key_id: self.identity.to_string(),
276 })
277 }
278}
279
280#[derive(Debug, Clone)]
282pub struct SessionKey {
283 pub peer: FourWordAddress,
284 pub key: Vec<u8>,
285 pub established_at: chrono::DateTime<chrono::Utc>,
286 pub expires_at: chrono::DateTime<chrono::Utc>,
287}
288
289#[derive(Debug, Clone)]
291pub struct DeviceKey {
292 pub device_id: DeviceId,
293 pub public_key: Vec<u8>,
294 pub private_key: Vec<u8>,
295 pub created_at: chrono::DateTime<chrono::Utc>,
296}
297
298#[derive(Debug, Clone)]
300pub struct EphemeralSession {
301 pub peer: FourWordAddress,
302 pub ephemeral_public: Vec<u8>,
303 pub ephemeral_private: Vec<u8>,
304 pub created_at: chrono::DateTime<chrono::Utc>,
305 pub message_count: u32,
306}
307
308pub struct KeyRatchet {
310 current_key: Vec<u8>,
311 generation: u32,
312}
313
314impl KeyRatchet {
315 pub fn new(initial_key: Vec<u8>) -> Self {
317 Self {
318 current_key: initial_key,
319 generation: 0,
320 }
321 }
322
323 pub fn ratchet(&mut self) -> Vec<u8> {
325 let mut hasher = Hasher::new();
326 hasher.update(&self.current_key);
327 hasher.update(&self.generation.to_le_bytes());
328 let new_key = hasher.finalize();
329
330 self.current_key = new_key.as_bytes().to_vec();
331 self.generation += 1;
332
333 self.current_key.clone()
334 }
335}
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340
341 #[tokio::test]
342 async fn test_message_encryption() {
343 let identity = FourWordAddress::from("alice-bob-charlie-david");
344 let secure = SecureMessaging::new(identity.clone()).unwrap();
345
346 let message = RichMessage::new(
347 UserHandle::from(identity.to_string()),
348 ChannelId::new(),
349 MessageContent::Text("Secret message".to_string()),
350 );
351
352 let encrypted = secure.encrypt_message(&message).await.unwrap();
353 assert!(!encrypted.ciphertext.is_empty());
354 assert_eq!(encrypted.id, message.id);
355 }
356
357 #[test]
358 fn test_message_signing() {
359 let identity = FourWordAddress::from("alice-bob-charlie-david");
360 let secure = SecureMessaging::new(identity.clone()).unwrap();
361
362 let message = RichMessage::new(
363 UserHandle::from(identity.to_string()),
364 ChannelId::new(),
365 MessageContent::Text("Sign me".to_string()),
366 );
367
368 let signature = secure.sign_message(&message);
369 assert!(!signature.is_empty());
370 assert_eq!(signature.len(), 32); }
372
373 #[test]
374 fn test_key_ratchet() {
375 let initial_key = vec![0u8; 32];
376 let mut ratchet = KeyRatchet::new(initial_key.clone());
377
378 let key1 = ratchet.ratchet();
379 let key2 = ratchet.ratchet();
380
381 assert_ne!(key1, initial_key);
382 assert_ne!(key2, key1);
383 assert_eq!(ratchet.generation, 2);
384 }
385}