Skip to main content

pubky_messenger/
message.rs

1use anyhow::{anyhow, Result};
2use blake3::Hasher;
3use ed25519_dalek::Signature;
4use pkarr::{Keypair, PublicKey};
5use pubky_common::crypto::{decrypt, encrypt};
6use serde::{Deserialize, Serialize};
7use std::time::{SystemTime, UNIX_EPOCH};
8use uuid::Uuid;
9
10use crate::crypto::generate_shared_secret;
11
12/// A private message with encrypted sender and content
13#[derive(Serialize, Deserialize, Debug, Clone)]
14pub struct PrivateMessage {
15    pub timestamp: u64,
16    pub encrypted_sender: Vec<u8>,
17    pub encrypted_content: Vec<u8>,
18    pub signature_bytes: Vec<u8>,
19}
20
21impl PrivateMessage {
22    /// Create a new encrypted message
23    pub fn new(sender_keypair: &Keypair, recipient_pk: &PublicKey, content: &str) -> Result<Self> {
24        let content_bytes = content.as_bytes();
25        let timestamp = SystemTime::now()
26            .duration_since(UNIX_EPOCH)
27            .unwrap()
28            .as_secs();
29
30        // Create message digest for signing
31        let mut hasher = Hasher::new();
32        hasher.update(content_bytes);
33        hasher.update(sender_keypair.public_key().as_bytes());
34        hasher.update(&timestamp.to_be_bytes());
35        let message_digest = hasher.finalize();
36
37        // Sign the message
38        let signature = sender_keypair.sign(message_digest.as_bytes());
39        let signature_bytes = signature.to_bytes().to_vec();
40
41        // Generate encryption key from shared secret
42        let shared_secret = generate_shared_secret(sender_keypair, recipient_pk)?;
43        let shared_secret_bytes = hex::decode(&shared_secret)?;
44
45        let mut encryption_key = [0u8; 32];
46        encryption_key.copy_from_slice(&shared_secret_bytes);
47
48        // Encrypt content and sender
49        let encrypted_content = encrypt(content_bytes, &encryption_key);
50        let sender_string = sender_keypair.public_key().to_string();
51        let encrypted_sender = encrypt(sender_string.as_bytes(), &encryption_key);
52
53        Ok(Self {
54            timestamp,
55            encrypted_sender,
56            encrypted_content,
57            signature_bytes,
58        })
59    }
60
61    /// Decrypt the message content
62    pub fn decrypt_content(
63        &self,
64        receiver_keypair: &Keypair,
65        other_participant: &PublicKey,
66    ) -> Result<String> {
67        let shared_secret = generate_shared_secret(receiver_keypair, other_participant)?;
68        let shared_secret_bytes = hex::decode(&shared_secret)?;
69
70        let mut encryption_key = [0u8; 32];
71        encryption_key.copy_from_slice(&shared_secret_bytes);
72
73        let decrypted = decrypt(&self.encrypted_content, &encryption_key)?;
74        Ok(String::from_utf8(decrypted)?)
75    }
76
77    /// Decrypt the sender public key
78    pub fn decrypt_sender(
79        &self,
80        receiver_keypair: &Keypair,
81        other_participant: &PublicKey,
82    ) -> Result<String> {
83        let shared_secret = generate_shared_secret(receiver_keypair, other_participant)?;
84        let shared_secret_bytes = hex::decode(&shared_secret)?;
85
86        let mut encryption_key = [0u8; 32];
87        encryption_key.copy_from_slice(&shared_secret_bytes);
88
89        let decrypted = decrypt(&self.encrypted_sender, &encryption_key)?;
90        Ok(String::from_utf8(decrypted)?)
91    }
92
93    /// Verify the message signature
94    pub fn verify_signature(
95        &self,
96        decrypted_content: &str,
97        decrypted_sender: &str,
98    ) -> Result<bool> {
99        let sender_pk = PublicKey::try_from(decrypted_sender)?;
100
101        let mut hasher = Hasher::new();
102        hasher.update(decrypted_content.as_bytes());
103        hasher.update(sender_pk.as_bytes());
104        hasher.update(&self.timestamp.to_be_bytes());
105        let message_digest = hasher.finalize();
106
107        if self.signature_bytes.len() != 64 {
108            return Err(anyhow!("Invalid signature length"));
109        }
110
111        let mut sig_bytes = [0u8; 64];
112        sig_bytes.copy_from_slice(&self.signature_bytes);
113        let signature = Signature::from_bytes(&sig_bytes);
114
115        match sender_pk.verify(message_digest.as_bytes(), &signature) {
116            Ok(()) => Ok(true),
117            Err(_) => Ok(false),
118        }
119    }
120
121    /// Generate a unique message ID
122    pub fn generate_id() -> String {
123        Uuid::new_v4().to_string()
124    }
125}
126
127/// A decrypted message for application use
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct DecryptedMessage {
130    pub sender: String,
131    pub content: String,
132    pub timestamp: u64,
133    pub verified: bool,
134}