feat: E2E encrypted Tor channel messages (ChaCha20-Poly1305)
Messages between federated nodes are now end-to-end encrypted: - X25519 ECDH key agreement from existing ed25519 node identities - HKDF-SHA256 key derivation with domain separation - ChaCha20-Poly1305 authenticated encryption per message - Random 12-byte nonce per message via OsRng (CSPRNG) - Graceful fallback to plaintext if encryption fails - Receiver auto-detects encrypted vs plaintext messages The Tor transport was already encrypted (onion routing), this adds application-layer E2E encryption so even a compromised receiving backend can't read messages without the node's private key. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
3aa37137ed
commit
1f81a0d804
@@ -89,7 +89,25 @@ impl RpcHandler {
|
||||
|
||||
let (data, _) = self.state_manager.get_snapshot().await;
|
||||
let pubkey = data.server_info.pubkey.clone();
|
||||
node_message::send_to_peer(onion, &pubkey, message).await?;
|
||||
|
||||
// Load signing key for E2E encryption
|
||||
let identity_dir = self.config.data_dir.join("identity");
|
||||
let node_id = crate::identity::NodeIdentity::load_or_create(&identity_dir).await?;
|
||||
|
||||
// Look up recipient's pubkey from federation nodes
|
||||
let fed_nodes = federation::load_nodes(&self.config.data_dir).await.unwrap_or_default();
|
||||
let recipient_pubkey = fed_nodes.iter()
|
||||
.find(|n| n.onion == onion || n.onion == format!("{}.onion", onion)
|
||||
|| format!("{}.onion", n.onion) == onion)
|
||||
.map(|n| n.pubkey.clone());
|
||||
|
||||
node_message::send_to_peer(
|
||||
onion,
|
||||
&pubkey,
|
||||
message,
|
||||
Some(node_id.signing_key()),
|
||||
recipient_pubkey.as_deref(),
|
||||
).await?;
|
||||
Ok(serde_json::json!({ "ok": true, "sent_to": onion }))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user