# Forward Secrecy Forward secrecy (FS), also called perfect forward secrecy (PFS), is a property of a cryptographic protocol that guarantees: **if a long-term secret key is compromised, past session keys cannot be recovered.** In other words, an attacker who obtains today's long-term key cannot use it to decrypt messages recorded yesterday. quicprochat provides forward secrecy at two independent layers: the transport layer and the application layer. Even if one layer's FS mechanism is defeated, the other continues to protect message confidentiality. ## Transport Layer Forward Secrecy ### TLS 1.3 (QUIC) The QUIC transport (via `quinn 0.11` + `rustls 0.23`) uses TLS 1.3, which mandates ephemeral key exchange in every handshake. Unlike TLS 1.2, which allowed static RSA key exchange (no FS), TLS 1.3 exclusively uses ephemeral ECDHE (Elliptic Curve Diffie-Hellman Ephemeral). In each TLS 1.3 handshake: 1. Both client and server generate ephemeral ECDHE key pairs. 2. They exchange public keys and compute a shared secret via Diffie-Hellman. 3. Session keys are derived from the shared secret using HKDF. 4. The ephemeral private keys are discarded after key derivation. Because the ephemeral keys exist only for the duration of the handshake, compromising the server's long-term TLS certificate key (currently self-signed in quicprochat) does not reveal past session keys. ## Application Layer Forward Secrecy ### MLS Epoch Ratchet The MLS protocol (RFC 9420) provides forward secrecy at the application layer through its epoch ratchet mechanism. This is independent of the transport layer's FS and protects message content even if transport session keys are leaked. Each MLS group maintains a **ratchet tree** -- a binary tree where each leaf represents a group member and internal nodes hold derived key material. The tree defines a current **epoch**, which determines the encryption keys for all messages in that epoch. When the epoch advances (via a Commit message): 1. The ratchet tree is updated with new key material from the committing member. 2. New epoch keys are derived from the updated tree. 3. **Old epoch keys are deleted.** This deletion is the mechanism that provides forward secrecy: once old epoch keys are erased, messages encrypted under those keys cannot be decrypted, even if the current group state is compromised. In quicprochat, epoch advancement occurs when: - `add_member()` is called, which creates a Commit and calls `merge_pending_commit()`. - A received Commit is processed via `receive_message()`, which calls `merge_staged_commit()`. ```rust // Epoch advances here -- old keys deleted internally by openmls group.merge_pending_commit(&self.backend)?; // sender side group.merge_staged_commit(&self.backend, *staged)?; // receiver side ``` ### Single-Use KeyPackages MLS KeyPackages contain a single-use HPKE init public key. Each init key is used exactly once -- to encrypt the Welcome message that bootstraps a new member's group state. After the Welcome is processed, the init private key is consumed and deleted from the `DiskKeyStore`. This single-use design provides forward secrecy for the initial key exchange: - Even if a member's long-term Ed25519 identity key is later compromised, the attacker cannot reconstruct the HPKE init private key that was used to decrypt the Welcome. - The init key was ephemeral to the join operation and no longer exists. This property is critical because the Welcome message contains the full ratchet tree state, including the secrets needed to decrypt messages in the initial epoch. If the init key could be reused or recovered, an attacker could reconstruct the entire initial group state. See [Key Lifecycle and Zeroization](key-lifecycle.md) for the full lifecycle of HPKE init keys. ## Layered Forward Secrecy A distinctive property of quicprochat's design is that forward secrecy operates at two independent layers: ```text +------------------------------------------------------+ | Network Adversary (records ciphertext) | +------------------------------------------------------+ | v +------------------------------------------------------+ | TLS 1.3 (QUIC) | | Forward secrecy via ephemeral ECDHE | | Even if TLS cert is compromised, | | past transport sessions are protected. | +------------------------------------------------------+ | v +------------------------------------------------------+ | MLS (RFC 9420) | | Forward secrecy via epoch ratchet | | Even if current MLS state is compromised, | | past epochs are protected (keys deleted). | +------------------------------------------------------+ | v +------------------------------------------------------+ | Plaintext message content | +------------------------------------------------------+ ``` **Why this matters:** If the transport layer's forward secrecy is broken (e.g., an attacker obtains a TLS session key through a side channel), the MLS layer still protects message content independently. The attacker would see the MLS ciphertext but could not decrypt it without the MLS epoch keys. Conversely, if MLS epoch keys are somehow leaked, the transport layer prevents a network-level attacker from correlating them with specific network flows unless they also break the transport encryption. ## Comparison with Signal Signal's Double Ratchet protocol also provides forward secrecy, but the mechanisms differ: | Property | Signal Double Ratchet | MLS (quicprochat) | |----------|----------------------|---------------------| | Scope | Pairwise (1:1 sessions) | Group (n-party) | | Ratchet granularity | Per message (symmetric ratchet) + per DH round (DH ratchet) | Per epoch (Commit) | | FS granularity | Individual messages | All messages in an epoch | | Group support | Sender Keys (no per-message FS in groups) | Native group FS via ratchet tree | | Efficiency | O(1) per message | O(log n) per Commit, O(1) per message | Signal achieves finer-grained forward secrecy in 1:1 conversations (per message via the symmetric ratchet), but in group settings, Signal uses Sender Keys, which do **not** provide per-message forward secrecy. A compromised Sender Key reveals all past messages from that sender. MLS provides forward secrecy at the epoch level for the entire group. Within an epoch, all messages share the same key material. The trade-off is that FS granularity is coarser (per epoch rather than per message), but it applies uniformly to all group members. ## Practical Implications 1. **Epoch advancement frequency:** More frequent Commits provide more fine-grained forward secrecy. In the current implementation, epochs advance when members are added. Future milestones will add periodic Update proposals to advance epochs even without membership changes. 2. **Key deletion timing:** Forward secrecy depends on old keys being actually deleted from memory and disk. The `DiskKeyStore`'s flush-on-write behavior ensures that consumed HPKE init keys are removed from the persistent store. MLS epoch key deletion is handled internally by openmls. 3. **State file security:** The client state file contains the Ed25519 identity seed and potentially the DiskKeyStore contents. If this file is compromised, the attacker obtains the current identity key and any stored HPKE init keys (for pending Welcome messages). Past epoch keys are not in the state file (they have been deleted), so forward secrecy is preserved for past epochs. ## Related Pages - [Cryptography Overview](overview.md) -- algorithm inventory - [Key Lifecycle and Zeroization](key-lifecycle.md) -- when keys are created and destroyed - [Post-Compromise Security](post-compromise-security.md) -- the complementary property (protecting the future) - [Threat Model](threat-model.md) -- attacker models and what FS protects against - [Ed25519 Identity Keys](identity-keys.md) -- long-term key that FS protects against compromising