/ docs / transport-security.md
transport-security.md
  1  # Ekko Transport Security Documentation
  2  
  3  **Version**: 1.0
  4  **Date**: March 2026
  5  **Classification**: Technical Reference
  6  
  7  ---
  8  
  9  ## Table of Contents
 10  
 11  1. [Overview](#1-overview)
 12  2. [Core Cryptographic Primitives](#2-core-cryptographic-primitives)
 13  3. [Message Encryption Pipeline](#3-message-encryption-pipeline)
 14  4. [BLE (Bluetooth Low Energy)](#4-ble-bluetooth-low-energy)
 15  5. [DHT (Distributed Hash Table)](#5-dht-distributed-hash-table)
 16  6. [Tor P2P (Onion-Routed Peer-to-Peer)](#6-tor-p2p-onion-routed-peer-to-peer)
 17  7. [iroh (QUIC-Based P2P)](#7-iroh-quic-based-p2p)
 18  8. [BLE Gossip (Proximity Relay)](#8-ble-gossip-proximity-relay)
 19  9. [Comparative Security Matrix](#9-comparative-security-matrix)
 20  10. [Attack Surface Analysis](#10-attack-surface-analysis)
 21  
 22  ---
 23  
 24  ## 1. Overview
 25  
 26  Ekko is a censorship-resistant messaging application that delivers messages through multiple independent transport channels. All transports share a common application-level encryption layer built on modern cryptographic primitives. Each transport adds its own transport-level security properties.
 27  
 28  **Transport Priority:**
 29  - Text messages: BLE → iroh → Tor P2P → DHT
 30  - File attachments: BLE → iroh → Tor P2P → DHT (chunked)
 31  
 32  **Key Principle:** Messages are encrypted once at the application layer before being handed to any transport. Transport-level encryption (where present) provides defense-in-depth but is not relied upon for confidentiality.
 33  
 34  ---
 35  
 36  ## 2. Core Cryptographic Primitives
 37  
 38  All cryptographic operations are implemented in Rust using audited crates. No custom cryptography is used.
 39  
 40  ### Key Types
 41  
 42  | Key | Algorithm | Size | Lifetime | Purpose |
 43  |-----|-----------|------|----------|---------|
 44  | Identity | Ed25519 | 32-byte secret, 32-byte public | Device lifetime | Signing, authentication |
 45  | Exchange | X25519 | 32-byte secret, 32-byte public | Device lifetime | Static key agreement |
 46  | Ephemeral | X25519 | 32-byte secret, 32-byte public | Single message | Forward secrecy |
 47  
 48  ### Algorithms
 49  
 50  | Function | Algorithm | Parameters |
 51  |----------|-----------|------------|
 52  | Authenticated encryption | ChaCha20-Poly1305 | 256-bit key, 96-bit nonce, 128-bit tag |
 53  | Key agreement | X25519 ECDH | 32-byte shared secret output |
 54  | Key derivation | HKDF-SHA256 (RFC 5869) | Domain prefix: `DeadDrop-v1-` |
 55  | Signatures | Ed25519 | 64-byte deterministic signatures |
 56  | Fingerprints | BLAKE2b-256 | 32 bytes (128 bits displayed to user) |
 57  | Memory cleanup | Zeroize | All secret key types implement `ZeroizeOnDrop` |
 58  
 59  ### Crate Dependencies
 60  
 61  | Crate | Version | Purpose |
 62  |-------|---------|---------|
 63  | `x25519-dalek` | — | X25519 key agreement |
 64  | `ed25519-dalek` | — | Ed25519 signatures |
 65  | `chacha20poly1305` | — | AEAD encryption |
 66  | `hkdf` + `sha2` | — | Key derivation |
 67  | `snow` | — | Noise protocol framework |
 68  | `rand` | — | OS-level CSPRNG |
 69  | `zeroize` | — | Secure memory cleanup |
 70  
 71  ---
 72  
 73  ## 3. Message Encryption Pipeline
 74  
 75  Every message, regardless of transport, passes through the same encryption pipeline.
 76  
 77  ### Encryption (Sender)
 78  
 79  ```
 80  PlaintextMessage {content_type, content, filename, metadata}
 81 82 83  Generate message_id: 16 random bytes (CSPRNG)
 84 85 86  Generate ephemeral X25519 key pair
 87 88 89  ECDH: shared_secret = DH(ephemeral_secret, recipient_exchange_public)
 90      │  (32-byte X25519 shared secret)
 91 92  HKDF-SHA256(secret=shared_secret, salt=message_id, info="DeadDrop-v1-message-key")
 93      │  (32-byte encryption key)
 94 95  ChaCha20-Poly1305.encrypt(key, nonce=random_12_bytes, plaintext, aad=message_id)
 96      │  (ciphertext + 16-byte authentication tag)
 97 98  Ed25519.sign(identity_secret, message_id ∥ ciphertext)
 99      │  (64-byte signature)
100101  EncryptedMessage {
102      message_id:       [u8; 16]   — Random, used as HKDF salt
103      ephemeral_public: [u8; 32]   — For recipient ECDH recovery
104      nonce:            [u8; 12]   — Random, for ChaCha20
105      ciphertext:       Vec<u8>    — Encrypted content + Poly1305 tag
106      timestamp:        i64        — Unix seconds
107      signature:        [u8; 64]   — Ed25519 over message_id ∥ ciphertext
108  }
109  ```
110  
111  ### Decryption (Recipient)
112  
113  ```
114  EncryptedMessage
115116117  Ed25519.verify(sender_identity_public, message_id ∥ ciphertext, signature)
118      │  (reject if invalid)
119120  ECDH: shared_secret = DH(recipient_exchange_secret, ephemeral_public)
121      │  (same 32-byte shared secret as sender computed)
122123  HKDF-SHA256(secret=shared_secret, salt=message_id, info="DeadDrop-v1-message-key")
124      │  (same 32-byte encryption key)
125126  ChaCha20-Poly1305.decrypt(key, nonce, ciphertext, aad=message_id)
127      │  (reject if tag verification fails)
128129  PlaintextMessage
130  ```
131  
132  ### Forward Secrecy Guarantee
133  
134  Each message generates a fresh ephemeral X25519 key pair. The ephemeral secret is consumed by Rust's ownership system after the DH operation and then zeroized. It is never written to disk or transmitted.
135  
136  **Consequence:** If the recipient's long-term exchange key is compromised after messages have been decrypted, past ciphertexts cannot be recovered — the ephemeral secrets no longer exist.
137  
138  **Limitation:** There is no Double Ratchet or evolving session state. Each message is encrypted independently. If the recipient's exchange key is compromised *before* they decrypt a message still in transit, that message can be decrypted by the attacker.
139  
140  ### Non-Repudiation
141  
142  The sender's Ed25519 signature on every message provides non-repudiation — a recipient can cryptographically prove who sent a message. This is a deliberate design choice; deniable authentication is not a goal.
143  
144  ---
145  
146  ## 4. BLE (Bluetooth Low Energy)
147  
148  ### Architecture
149  
150  BLE transport provides direct device-to-device messaging with no network infrastructure. Devices discover each other via BLE advertising, establish a Noise-encrypted channel, and exchange queued messages bidirectionally.
151  
152  ### Third-Party Services
153  
154  **None.** BLE operates entirely peer-to-peer with no internet connectivity required.
155  
156  ### Encryption Layers
157  
158  | Layer | Protocol | Purpose |
159  |-------|----------|---------|
160  | Transport | Noise_XX_25519_ChaChaPoly_SHA256 | Session encryption, mutual authentication |
161  | Application | ChaCha20-Poly1305 + Ed25519 | Per-message encryption (§3) |
162  
163  ### Noise XX Handshake
164  
165  The BLE transport uses the Noise Protocol Framework with the XX pattern, providing mutual authentication with encrypted static key transmission.
166  
167  ```
168  Initiator (Alice)                         Responder (Bob)
169      │                                         │
170      │  → e                                    │  Message 1: Alice's ephemeral public key
171      │     (32 bytes, unencrypted)             │
172      │                                         │
173      │  ← e, ee, s, es                         │  Message 2: Bob's ephemeral key +
174      │     (80 bytes, partially encrypted)     │  Bob's static key (encrypted with DH(e,e))
175      │                                         │
176      │  → s, se                                │  Message 3: Alice's static key
177      │     (48 bytes, encrypted)               │  (encrypted with established keys)
178      │                                         │
179      │  ═══ Symmetric transport keys ═══       │
180      │  (separate keys per direction)          │
181  ```
182  
183  **After handshake completion:**
184  - Both parties have verified each other's static X25519 keys
185  - Two independent symmetric keys are established (one per direction)
186  - A nonce counter is maintained per direction (never reused)
187  - All subsequent data is encrypted with ChaCha20-Poly1305
188  
189  ### Message Exchange Protocol
190  
191  After the Noise handshake, an application-level exchange protocol runs over the encrypted channel:
192  
193  1. **MsgCount**: Both peers announce how many queued messages they have
194  2. **MsgData**: Each message (already encrypted per §3) is transmitted with index tracking
195  3. **MsgAck/MsgNack**: Per-message acknowledgment/rejection
196  4. **ExchangeComplete**: Both peers signal completion
197  
198  ### Forward Secrecy
199  
200  BLE provides forward secrecy at two levels:
201  
202  1. **Session level** (Noise XX): Each BLE session generates fresh ephemeral keys. Compromise of static keys does not reveal past session keys.
203  2. **Message level** (§3): Each message within a session uses independent ephemeral ECDH, providing per-message forward secrecy even within a single BLE session.
204  
205  ### Dual-Initiation Collision
206  
207  When both devices simultaneously initiate a BLE connection:
208  - Active sessions in `exchanging`, `gossiping`, or `complete` states ignore incoming handshake messages
209  - If both are at message 1, ephemeral keys are compared — the smaller key's device becomes the responder
210  - Prevents session reset during active data transfer
211  
212  ### Security Risks
213  
214  | Risk | Severity | Notes |
215  |------|----------|-------|
216  | BLE range limitation | Low | ~10m range limits interception to physical proximity |
217  | BLE advertising metadata | Low | Rotating IDs derived via HKDF prevent tracking; rotated periodically |
218  | Relay attack (MITM) | Low | Noise XX provides mutual authentication; MITM requires real-time key substitution |
219  | Jamming/DoS | Medium | Radio-level jamming can prevent BLE communication; no mitigation possible |
220  
221  ---
222  
223  ## 5. DHT (Distributed Hash Table)
224  
225  ### Architecture
226  
227  Messages are encrypted, published to the public BitTorrent Mainline DHT as BEP44 mutable items, and fetched by recipients who poll their designated slots.
228  
229  ### Third-Party Services
230  
231  | Service | Operator | Role |
232  |---------|----------|------|
233  | Mainline DHT bootstrap nodes | BitTorrent Inc, µTorrent, Transmission, libtorrent, CMU | Initial DHT network entry |
234  | Mainline DHT nodes | Thousands of public nodes | Store and relay BEP44 mutable items |
235  
236  **Default bootstrap nodes:**
237  - `router.bittorrent.com:6881`
238  - `router.utorrent.com:6881`
239  - `dht.transmissionbt.com:6881`
240  - `dht.libtorrent.org:25401`
241  - `node.sp.cs.cmu.edu:6881`
242  
243  **No Ekko-specific infrastructure is required.** The DHT is the same public network used by BitTorrent clients worldwide.
244  
245  ### Encryption Layers
246  
247  | Layer | Protocol | Purpose |
248  |-------|----------|---------|
249  | DHT integrity | BEP44 Ed25519 signatures | Prevents unauthorized slot modification |
250  | Application | ChaCha20-Poly1305 + Ed25519 | Per-message encryption (§3) |
251  
252  **Note:** The DHT itself provides no confidentiality. BEP44 values are stored in plaintext on DHT nodes. All confidentiality comes from the application-level encryption.
253  
254  ### DHT Key Derivation
255  
256  Recipients are addressed by their X25519 exchange public key. A BEP44 signing key is derived deterministically:
257  
258  ```
259  ed25519_seed = SHA-512("deaddrop/dht/ed25519/v1" ∥ x25519_exchange_public)[0..32]
260  signing_key  = Ed25519.from_seed(ed25519_seed)
261  public_key   = signing_key.verifying_key()
262  ```
263  
264  **Slot addressing:**
265  - Salt: `"deaddrop/v1/slot/{N}"` where N = 0..100
266  - Sequence number: current Unix timestamp (prevents rollback)
267  - Value: bencoded list of `DhtStoredMessage` entries, optionally zstd-compressed
268  
269  ### Publish/Fetch Flow
270  
271  **Publishing (sender):**
272  1. Messages are encrypted per §3 and wrapped in `DhtStoredMessage { message_id, sender_key, payload, timestamp, expires_at }`
273  2. Messages distributed across recipient's slots (20–100 slots, expandable to 500 via continuation chaining)
274  3. Each slot is published as a BEP44 mutable item with Ed25519 signature and current timestamp as sequence number
275  4. Retry: 3 attempts with exponential backoff (1s, 2s, 4s)
276  
277  **Fetching (recipient):**
278  1. Recipient polls slots 0–100 concurrently every 30 seconds (first 3 minutes) then every 5 minutes
279  2. Continuation markers chain to additional slot ranges (100–199, 200–299, etc.)
280  3. Messages exceeding 950-byte slot limit are split into chunks with reassembly metadata
281  4. Each fetched message is decrypted per §3 and stored locally
282  
283  ### Forward Secrecy
284  
285  Per-message forward secrecy is provided by the application-level encryption (§3). Each message uses an independent ephemeral ECDH key agreement.
286  
287  **DHT-specific limitation:** Messages persist on DHT nodes for up to 48 hours (configurable TTL). If a recipient's exchange key is compromised during this window, unread messages on the DHT can be decrypted.
288  
289  ### Security Risks
290  
291  | Risk | Severity | Notes |
292  |------|----------|-------|
293  | Slot enumeration | Medium | Observers can correlate slots 0–100 to a single recipient by access patterns |
294  | Volume analysis | Medium | Number of occupied slots reveals approximate message count |
295  | IP address exposure | Medium | DHT participation reveals the device's IP address to DHT peers |
296  | Timing correlation | Medium | Publish/fetch timing can correlate sender and recipient |
297  | No confidentiality at rest on DHT | Low | Mitigated by application-level encryption; DHT nodes see only ciphertext |
298  | Stale message replay | Low | TTL (48h), message ID deduplication, and BEP44 sequence numbers prevent replay |
299  | Slot value rollback | Low | BEP44 sequence numbers prevent injection of older values |
300  
301  ---
302  
303  ## 6. Tor P2P (Onion-Routed Peer-to-Peer)
304  
305  ### Architecture
306  
307  Devices create Tor v3 onion services (.onion hidden services) and establish direct WebSocket connections through the Tor network. Peer discovery uses DHT-based rendezvous — each device publishes its .onion address to the DHT.
308  
309  ### Third-Party Services
310  
311  | Service | Operator | Role |
312  |---------|----------|------|
313  | Tor network | The Tor Project (volunteer-operated) | Onion routing, circuit building |
314  | Tor directory authorities | The Tor Project | Network consensus |
315  | Mainline DHT | Public | .onion address rendezvous |
316  
317  **No exit nodes are used.** All connections are .onion-to-.onion (hidden service to hidden service), remaining entirely within the Tor network.
318  
319  ### Encryption Layers
320  
321  | Layer | Protocol | Purpose |
322  |-------|----------|---------|
323  | Network | Tor v3 onion routing | Anonymity, 3-hop circuit encryption |
324  | Transport | WebSocket over TCP | Message framing |
325  | Application | ChaCha20-Poly1305 + Ed25519 | Per-message encryption (§3) |
326  
327  ### Connection Protocol
328  
329  **WebSocket Handshake over Tor:**
330  
331  ```
332  Initiator (Client)                    Responder (Server)
333      │                                     │
334      │  SOCKS5 tunnel via localhost:9050    │
335      │  ─────────────────────────────────► │  Tor routes to .onion:80
336      │                                     │
337      │  WebSocket upgrade (HTTP 101)       │
338      │  ◄────────────────────────────────► │
339      │                                     │
340      │  Send 32-byte Ed25519 identity key  │
341      │  ─────────────────────────────────► │  Server stores peer identity
342      │                                     │
343      │  Receive 32-byte identity key       │  Server sends own identity
344      │  ◄───────────────────────────────── │
345      │                                     │  Server verifies peer is known contact
346      │  Receive 32-byte nonce challenge    │
347      │  ◄───────────────────────────────── │
348      │                                     │
349      │  Echo nonce back                    │
350      │  ─────────────────────────────────► │
351      │                                     │
352      │  Receive "OK"                       │  Authentication complete
353      │  ◄───────────────────────────────── │
354      │                                     │
355      │  ═══ Encrypted messages (§3) ═══   │
356      │  ◄────────────────────────────────► │
357  ```
358  
359  ### Rendezvous Mechanism
360  
361  Peer .onion addresses are discovered via DHT:
362  
363  - **Salt:** `"deaddrop/v1/rendezvous"`
364  - **Value:** bencoded `{ "a": "<56-char-onion-address>", "t": <unix_timestamp> }`
365  - **Freshness:** Entries older than 1 hour are rejected
366  - **Caching:** Discovered addresses cached in `contacts.onion_address` column for instant reconnect
367  
368  **Polling:** Fast poll every 30 seconds for first 3 minutes, then every 5 minutes.
369  
370  ### Forward Secrecy
371  
372  Per-message forward secrecy is provided by the application-level encryption (§3).
373  
374  Additionally, Tor provides circuit-level forward secrecy — each Tor circuit uses ephemeral Diffie-Hellman key agreement at each hop.
375  
376  ### Platform Implementation
377  
378  | Platform | Tor Framework | Hidden Service | SOCKS5 |
379  |----------|--------------|----------------|--------|
380  | iOS | `Tor.framework` (CocoaPods) | `ADD_ONION` via control port | Port 9050 |
381  | macOS | `Tor.framework` (CocoaPods) | `ADD_ONION` via control port | Port 9050 |
382  | Android | `tor_hidden_service` Flutter package | Automatic | Port 9050 |
383  
384  **Persistent onion keys:** The Ed25519 private key from `ADD_ONION NEW` is saved to `.onion_key` and reused on subsequent launches for stable .onion addresses.
385  
386  ### Security Risks
387  
388  | Risk | Severity | Notes |
389  |------|----------|-------|
390  | DHT rendezvous metadata | Medium | DHT queries for .onion addresses are not anonymous; DHT peers see the lookup |
391  | Timing correlation | Medium | Message timing patterns visible to ISP-level observers watching both endpoints |
392  | Message size analysis | Low | No padding; file transfer sizes are observable |
393  | Tor circuit compromise | Low | Requires control of guard + rendezvous point; v3 onion services have improved guard rotation |
394  | Stale .onion address | Low | 1-hour TTL + SOCKS5 status=4 (connection refused) indicates peer offline |
395  | Onion key storage | Low | Stored unencrypted in app sandbox; OS sandboxing provides protection |
396  | Identity key exchange in cleartext over WebSocket | Low | Mitigated by Tor circuit encryption; identity keys are public information |
397  
398  ---
399  
400  ## 7. iroh (QUIC-Based P2P)
401  
402  ### Architecture
403  
404  iroh is a QUIC-based P2P library from n0.computer providing NAT traversal via relay servers and optional UDP hole-punching for direct connections. Ekko uses iroh with a custom ALPN protocol (`deaddrop/msg/v1`) for push-based message delivery.
405  
406  ### Third-Party Services
407  
408  | Service | Operator | Role |
409  |---------|----------|------|
410  | n0.computer relay servers | n0 Inc | QUIC relay for NAT traversal |
411  | Mainline DHT | Public | EndpointId rendezvous |
412  
413  **Relay bypass:** If UDP hole-punching succeeds, the relay is not used. The relay is a fallback for devices behind restrictive NATs.
414  
415  ### Encryption Layers
416  
417  | Layer | Protocol | Purpose |
418  |-------|----------|---------|
419  | Transport | QUIC (TLS 1.3, ChaCha20-Poly1305) | Transport confidentiality via iroh |
420  | Application | ChaCha20-Poly1305 + Ed25519 | Per-message encryption (§3) |
421  
422  **Double encryption:** Messages are encrypted at the application layer (§3) before being transmitted over QUIC, which adds its own TLS 1.3 encryption. Even if the QUIC layer is compromised, messages remain protected.
423  
424  ### EndpointId and Peer Discovery
425  
426  Each device has a persistent 32-byte EndpointId derived from a locally-stored secret key:
427  
428  ```
429  secret_key: 32 random bytes (generated once, stored at {storage_dir}/iroh_secret_key)
430  EndpointId = iroh::Endpoint.id() (derived from secret_key)
431  ```
432  
433  **DHT rendezvous:**
434  - **Salt:** `"deaddrop/v1/iroh-rendezvous"` (distinct from Tor rendezvous)
435  - **Value:** `"endpoint_id|relay_url"` (pipe-separated)
436  - **Caching:** `contacts.iroh_endpoint_id` column + in-memory `IROH_RELAY_CACHE`
437  
438  ### Message Flow
439  
440  **Sending:**
441  ```
442  1. Encrypt message per §3 → EncryptedMessage
443  2. bincode::serialize(EncryptedMessage) → payload bytes
444  3. Look up recipient's EndpointId + relay URL
445  4. Open unidirectional QUIC stream: endpoint.connect(addr, "deaddrop/msg/v1")
446  5. Write: [4-byte big-endian length] + [payload]
447  6. Close stream
448  ```
449  
450  **Receiving:**
451  ```
452  1. endpoint.accept() → incoming QUIC connection
453  2. Read 4-byte length, then payload
454  3. Map sender EndpointId → ContactId via cached mapping
455  4. Look up sender's Ed25519 identity key
456  5. Decrypt per §3
457  6. Store in database
458  ```
459  
460  ### Forward Secrecy
461  
462  Per-message forward secrecy is provided by the application-level encryption (§3).
463  
464  QUIC/TLS 1.3 provides additional transport-level forward secrecy with ephemeral ECDH per connection.
465  
466  ### What the Relay Server Can See
467  
468  | Data | Visible to Relay? |
469  |------|-------------------|
470  | Message content | No (double-encrypted) |
471  | Message metadata (timestamps, sizes) | Yes |
472  | Connection patterns (who contacts whom) | Yes (EndpointIds) |
473  | IP addresses of both peers | Yes |
474  | Message frequency | Yes |
475  
476  ### Security Risks
477  
478  | Risk | Severity | Notes |
479  |------|----------|-------|
480  | Relay metadata visibility | Medium | n0 relay sees connection patterns and IP addresses |
481  | IP address exposure | Medium | Both peers' IPs visible to relay; no anonymity |
482  | DHT endpoint visibility | Low | Published EndpointIds are publicly queryable |
483  | Message size analysis | Low | Packet sizes visible to relay and network observers |
484  | Timing analysis | Low | Message frequency visible; can enable traffic analysis |
485  | Endpoint impersonation | Low | Ed25519 signature verification prevents message forgery |
486  | Nonce reuse | Very Low | Random 96-bit nonces; collision probability negligible |
487  
488  ---
489  
490  ## 8. BLE Gossip (Proximity Relay)
491  
492  ### Architecture
493  
494  BLE Gossip extends the BLE transport to relay messages between devices that don't share contacts. After a standard BLE exchange completes, devices enter a gossip phase where they exchange forwarded messages for third-party recipients using the existing Noise-encrypted channel.
495  
496  ### Third-Party Services
497  
498  **None.** Operates entirely over BLE with no network connectivity.
499  
500  ### Encryption
501  
502  Gossip messages maintain their original application-level encryption (§3). The gossip relay cannot read forwarded messages because they are encrypted for a specific recipient's exchange key.
503  
504  **Transport encryption:** The gossip protocol reuses the Noise transport established during the initial BLE handshake, so forwarded messages are double-encrypted (Noise session + application-level).
505  
506  ### Security Properties
507  
508  - **Forwarding store limits:** 50MB maximum, 48-hour TTL
509  - **Probabilistic acceptance:** Messages accepted based on bloom filter digests
510  - **No metadata leakage to relay:** Relay device sees encrypted blobs; cannot determine sender, recipient, or content
511  - **Chunking:** Gossip digests are chunked with 4-byte length prefix + 500-byte data chunks for BLE ATT size limits
512  
513  ---
514  
515  ## 9. Comparative Security Matrix
516  
517  | Property | BLE | DHT | Tor P2P | iroh |
518  |----------|-----|-----|---------|------|
519  | **Confidentiality** | ChaCha20-Poly1305 (2 layers) | ChaCha20-Poly1305 | ChaCha20-Poly1305 + Tor circuits | ChaCha20-Poly1305 (2 layers) |
520  | **Authenticity** | Ed25519 + Noise XX | Ed25519 + BEP44 signatures | Ed25519 + identity key exchange | Ed25519 + QUIC TLS |
521  | **Forward secrecy** | Per-session (Noise) + per-message (ECDH) | Per-message (ECDH) | Per-message (ECDH) + per-circuit (Tor) | Per-message (ECDH) + per-connection (TLS 1.3) |
522  | **Anonymity** | Physical proximity required | IP visible to DHT peers | Strong (.onion-to-.onion) | IP visible to relay |
523  | **Third-party dependency** | None | Public DHT nodes | Tor network | n0.computer relay |
524  | **Offline capability** | Yes (direct) | No (needs internet) | No (needs Tor circuit) | No (needs internet) |
525  | **Replay protection** | Nonce counter + message ID | Message ID + BEP44 seq + TTL | Message ID + replay cache | Message ID |
526  | **Mutual authentication** | Noise XX static keys | N/A (async) | Identity key exchange | QUIC + identity key mapping |
527  | **Max message size** | ~500 bytes per BLE packet (chunked) | ~950 bytes per slot (chunked) | Unlimited (WebSocket) | 100 MB |
528  
529  ---
530  
531  ## 10. Attack Surface Analysis
532  
533  ### Scenario 1: Compromised Recipient Exchange Key
534  
535  **Impact:** Attacker can decrypt any message encrypted to this key that they can intercept.
536  
537  | Transport | Risk | Details |
538  |-----------|------|---------|
539  | BLE | Low | Requires physical proximity to intercept |
540  | DHT | High | Messages persist on public DHT for 48 hours; attacker can fetch and decrypt |
541  | Tor P2P | Medium | Must intercept in real-time (no persistence); Tor anonymity makes interception difficult |
542  | iroh | Medium | Must intercept in real-time via relay or network position |
543  
544  **Mitigation:** Forward secrecy protects messages that have already been decrypted and whose ephemeral keys are gone. Only messages currently in transit or stored on the DHT are at risk.
545  
546  ### Scenario 2: Compromised Sender Identity Key
547  
548  **Impact:** Attacker can forge messages appearing to come from the compromised sender.
549  
550  **All transports:** Cannot decrypt past messages (identity keys are for signing, not encryption). Can impersonate sender going forward until key is revoked/rotated.
551  
552  ### Scenario 3: Global Passive Adversary (Network Observer)
553  
554  | Transport | Observable | Not Observable |
555  |-----------|-----------|---------------|
556  | BLE | Radio signals within ~10m | Content (encrypted) |
557  | DHT | IP addresses, slot access patterns, timing | Message content, sender identity |
558  | Tor P2P | Tor circuit existence (not endpoints) | .onion addresses, message content, peer identities |
559  | iroh | IP addresses, relay connections, timing | Message content (double-encrypted) |
560  
561  ### Scenario 4: Compromised Relay/Infrastructure
562  
563  | Infrastructure | Attacker Capability |
564  |---------------|---------------------|
565  | DHT nodes | Store/serve ciphertext; cannot decrypt. Can refuse to store (DoS). |
566  | Tor relays | Route encrypted circuits; cannot decrypt. Guard node knows client IP. |
567  | n0 relay | See connection metadata and encrypted QUIC packets; cannot decrypt application-layer encryption. |
568  | BLE | N/A — no infrastructure |
569  
570  ### Scenario 5: Nonce Reuse
571  
572  ChaCha20-Poly1305 is catastrophically broken by nonce reuse with the same key. The system mitigates this through:
573  
574  1. **Random 96-bit nonces** generated per message via OS CSPRNG
575  2. **Unique encryption keys** per message (HKDF with message_id salt ensures different key even if nonce collides)
576  3. **Noise transport** uses counter-based nonces (guaranteed unique within session)
577  
578  **Residual risk:** Negligible. Birthday bound for 96-bit random nonces is 2^48 messages per key, and keys are never reused across messages.
579  
580  ---
581  
582  *This document describes the cryptographic architecture as implemented. No system is perfectly secure — security depends on correct implementation, secure key management, and operational practices. Regular security audits of the Rust cryptographic core are recommended.*