Expand description
SecureEnvelope — AEAD-wrapped session payloads (fn-129.T7).
Every body the daemon POSTs under a pairing session gets wrapped in this envelope. The envelope binds:
- Ciphertext + tag to a session-specific AEAD key derived from the
TransportKeyvia HKDF withENVELOPE_INFOdomain separation. - Request context (session id, path, monotonic counter) as AAD, in a length-prefixed layout that defeats AAD-confusion attacks.
§Committed design decisions
- Nonce scheme: deterministic counter XOR’d with a per-session 96-bit IV (RFC 8446 §5.3). Doubles as the monotonic-counter replay defense — one value, not two.
- AEAD primitive: ChaCha20-Poly1305 for the default build;
AES-256-GCM under
--features cnsa. Dispatched throughCryptoProvider::aead_{encrypt,decrypt}(fn-128.T2) so the swap is automatic. - AAD layout (length-prefixed):
u32_be(len(session_id)) || session_id || u32_be(len(path)) || path || u32_be(len(channel_binding)) || channel_binding || u32_be(counter). Naive concatenation is forbidden (USENIX’23 AEAD-confusion). - Channel binding (anti-relay): the session is pinned to the TLS
connection it runs on via the RFC 9266
tls-exporterkeying material (seecrate::channel_binding). The exporter is folded into BOTH the envelope key derivation (so two channels derive different keys) AND the AAD (so a cross-channel open is rejected explicitly). An envelope sealed on channel A therefore cannot be opened on channel B — a relayed proof is refused. This is the load-bearing negative property; without it the envelope is transport-agnostic and a captured proof replays. - Max messages per session: 1024. More than any pairing flow needs;
abort with
EnvelopeError::SessionExhaustedat the cap. - API is async to match
CryptoProvider’s async trait surface; this avoids a sync-over-async executor inside the crate.
§Typestate
Envelope<Sealed> (carries ciphertext) and Envelope<Open> (carries
plaintext) are separate types; seal and open can’t be swapped.
Structs§
- Envelope
- AEAD envelope. State parameter distinguishes sealed-for-transport from
opened-for-use. Never deriving
Clone/Copy— a sealed envelope is single-use (counter is one-shot). - Envelope
Session - Session-local envelope state. Holds the envelope key (HKDF-derived from
the
TransportKey), the per-session IV, the last-seen counter, and a message budget. Consumed via&mut selfso nonce reuse within a session is structurally prevented. - Open
- Phantom type: envelope has been opened (contains plaintext).
- Sealed
- Phantom type: envelope has been sealed (contains ciphertext).
Enums§
- Envelope
Error - Errors produced by envelope open/seal.
Constants§
- MAX_
MESSAGES_ PER_ SESSION - Hard cap on messages per envelope session. Well above any pairing flow’s natural message count.