Files
quicproquo/docs/src/cryptography/forward-secrecy.md
Chris Nennemann 853ca4fec0 chore: rename project quicnprotochat -> quicproquo (binaries: qpq)
Rename the entire workspace:
- Crate packages: quicnprotochat-{core,proto,server,client,gui,p2p,mobile} -> quicproquo-*
- Binary names: quicnprotochat -> qpq, quicnprotochat-server -> qpq-server,
  quicnprotochat-gui -> qpq-gui
- Default files: *-state.bin -> qpq-state.bin, *-server.toml -> qpq-server.toml,
  *.db -> qpq.db
- Environment variable prefix: QUICNPROTOCHAT_* -> QPQ_*
- App identifier: chat.quicnproto.gui -> chat.quicproquo.gui
- Proto package: quicnprotochat.bench -> quicproquo.bench
- All documentation, Docker, CI, and script references updated

HKDF domain-separation strings and P2P ALPN remain unchanged for
backward compatibility with existing encrypted state and wire protocol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:11:51 +01:00

181 lines
8.0 KiB
Markdown

# 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.
quicproquo 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 quicproquo) 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 quicproquo, 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 quicproquo'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 (quicproquo) |
|----------|----------------------|---------------------|
| 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