commonware_stream/public_key/mod.rs
1//! Communicate with an authenticated peer over an encrypted connection.
2//!
3//! This module provides a lightweight, self-contained transport layer for systems where peers
4//! already know one another's cryptographic identities (any [commonware_cryptography::Signer]).
5//! It offers mutual authentication and encrypted communication using a simplified handshake,
6//! eliminating the need for complex protocols like TLS or X.509 certificates. The implementation
7//! uses a fixed, non-negotiable cryptographic protocol to simplify implementation and reduce
8//! overhead, resulting in a minimal performance impact.
9//!
10//! # Design
11//!
12//! ## Handshake
13//!
14//! A three-message handshake is used to authenticate peers and establish a shared secret. The
15//! **dialer** initiates the connection, and the **listener** responds.
16//!
17//! The **dialer** initiates the connection to a known peer identity, while the **listener** accepts
18//! incoming connections. Much like a SYN / SYN-ACK / ACK handshake, the dialer and listener
19//! exchange messages in three rounds.
20//!
21//! The SYN-equivalent is a [handshake::Hello] message that contains:
22//! - The listener's expected public key (prevents wrong-target attacks)
23//! - The dialer's ephemeral public key (for Diffie-Hellman key exchange)
24//! - The current timestamp (prevents replay attacks)
25//! - The dialer's static public key and signature
26//!
27//! The ACK-equivalent is a [handshake::Confirmation] message that proves that each party can derive
28//! the correct shared secret.
29//!
30//! Thus:
31//! - Message 1 is a `Hello` message from the dialer to the listener
32//! - Message 2 is a `Hello` (with a continuation tag) and `Confirmation` message from the listener to the dialer
33//! - Message 3 is a `Confirmation` message from the dialer to the listener
34//!
35//! _The continuation tag binds the listener's [handshake::Hello] response to a particular dialer's
36//! [handshake::Hello] message, preventing exfiltration to a different session._
37//!
38//! ## Encryption
39//!
40//! All traffic is encrypted using ChaCha20-Poly1305. A shared secret is established using an
41//! ephemeral X25519 Diffie-Hellman key exchange. This secret, combined with the handshake
42//! transcript, is used to derive keys for both the handshake's key confirmation messages and
43//! the post-handshake data traffic. Binding the derived keys to the handshake transcript prevents
44//! man-in-the-middle and transcript substitution attacks.
45//!
46//! Each directional cipher uses a 12-byte nonce derived from a counter that is incremented for each
47//! message sent. This counter has sufficient cardinality for over 2.5 trillion years of continuous
48//! communication at a rate of 1 billion messages per second—sufficient for all practical use cases.
49//! This ensures that well-behaving peers can remain connected indefinitely as long as they both
50//! remain online (maximizing p2p network stability). In the unlikely case of counter overflow, the
51//! connection will be terminated and a new connection should be established. This method prevents
52//! nonce reuse (which would compromise message confidentiality) while saving bandwidth (as there is
53//! no need to transmit nonces explicitly).
54//!
55//! # Security
56//!
57//! ## Requirements
58//!
59//! - **Pre-Shared Namespace**: Peers must agree on a unique, application-specific namespace
60//! out-of-band to prevent cross-application replay attacks.
61//! - **Time Synchronization**: Peer clocks must be synchronized to within the `synchrony_bound`
62//! to correctly validate timestamps.
63//!
64//! ## Provided
65//!
66//! - **Mutual Authentication**: Both parties prove ownership of their static private keys through
67//! signatures.
68//! - **Forward Secrecy**: Ephemeral encryption keys ensure that any compromise of long-term static keys
69//! doesn't expose the contents of previous sessions.
70//! - **Session Uniqueness**: A listener's [handshake::Hello] is bound to the dialer's [handshake::Hello] message and
71//! [handshake::Confirmation]s are bound to the complete handshake transcript, preventing replay attacks and ensuring
72//! message integrity.
73//! - **Handshake Timeout**: A configurable deadline is enforced for handshake completion to protect
74//! against malicious peers that create connections but abandon handshakes.
75//!
76//! ## Not Provided
77//!
78//! - **Anonymity**: Peer identities are not hidden during handshakes from network observers (both active
79//! and passive).
80//! - **Padding**: Messages are encrypted as-is, allowing an attacker to perform traffic analysis.
81//! - **Future Secrecy**: If a peer's static private key is compromised, future sessions will be exposed.
82//! - **0-RTT**: The protocol does not support 0-RTT handshakes (resumed sessions).
83
84use chacha20poly1305::{
85 aead::{generic_array::typenum::Unsigned, AeadCore},
86 ChaCha20Poly1305,
87};
88use std::time::Duration;
89
90mod cipher;
91mod connection;
92use commonware_cryptography::Signer;
93pub use connection::{Connection, IncomingConnection, Receiver, Sender};
94pub mod handshake;
95mod nonce;
96pub mod x25519;
97
98// When encrypting data, an authentication tag is appended to the ciphertext.
99// This constant represents the size of the authentication tag in bytes.
100const AUTHENTICATION_TAG_LENGTH: usize = <ChaCha20Poly1305 as AeadCore>::TagSize::USIZE;
101
102/// Configuration for a connection.
103///
104/// # Warning
105///
106/// Synchronize this configuration across all peers.
107/// Mismatched configurations may cause dropped connections or parsing errors.
108#[derive(Clone)]
109pub struct Config<C: Signer> {
110 /// Cryptographic primitives for signing and verification.
111 pub crypto: C,
112
113 /// Unique prefix for all signed messages. Should be application-specific.
114 /// Prevents replay attacks across different applications using the same keys.
115 pub namespace: Vec<u8>,
116
117 /// Maximum message size (in bytes). Prevents memory exhaustion DoS attacks.
118 pub max_message_size: usize,
119
120 /// Maximum time drift allowed for future timestamps. Handles clock skew.
121 pub synchrony_bound: Duration,
122
123 /// Maximum age of handshake messages before rejection.
124 pub max_handshake_age: Duration,
125
126 /// Maximum time allowed for completing the handshake.
127 pub handshake_timeout: Duration,
128}