Start .NET rewrite with wire and media crypto conformance
This commit is contained in:
+13
-10
@@ -67,13 +67,15 @@ mandatory from the first build. This was chosen over DTLS after weighing two fin
|
||||
|
||||
### How it works
|
||||
|
||||
1. During the TLS 1.3 control handshake, both sides call the keying-material exporter with a
|
||||
fixed label (`"voicecat media v1"`) to derive independent **send/recv media keys** and a
|
||||
salt. No second handshake, no certificates on the UDP path — the UDP channel inherits the
|
||||
1. After the TLS 1.3 control handshake, both sides call the keying-material exporter with
|
||||
label `"voicecat media v1"` and a one-byte context: `0x00` for client→server,
|
||||
`0x01` for server→client. Each export yields a 32-byte directional media key.
|
||||
No second handshake, no certificates on the UDP path — the UDP channel inherits the
|
||||
authenticated, MITM-resistant TLS session's trust.
|
||||
2. Each UDP voice frame is sealed with **ChaCha20-Poly1305** (libsodium, ISC license).
|
||||
3. The readable routing field (`ssrc`) is passed as AEAD **associated data** so the relay can
|
||||
route without decrypting and an attacker cannot tamper with it undetected.
|
||||
3. The full 20-byte header is AEAD **associated data**. The server authenticates/decrypts
|
||||
inbound media and reseals for each recipient, replacing the sequence with that
|
||||
recipient's next send counter. It forwards the encoded Opus bytes without decoding audio.
|
||||
|
||||
This keeps the entire crypto surface on two permissive libraries (mbedTLS + libsodium), adds
|
||||
no handshake latency to voice startup, and is small enough to audit fully. It is abstracted
|
||||
@@ -84,11 +86,12 @@ the design depends on that.
|
||||
### Per-frame protections
|
||||
|
||||
- **AEAD** (ChaCha20-Poly1305) over each voice frame — confidentiality + integrity.
|
||||
- **Associated data:** the `ssrc` (and version/flags) are authenticated-but-visible so the
|
||||
relay routes without decrypting; everything else is encrypted.
|
||||
- **Nonce discipline:** `nonce = direction_bit ‖ ssrc ‖ monotonic_packet_counter`. The
|
||||
counter never repeats under one key; the session **rekeys** (re-derives via the exporter
|
||||
with a bumped epoch) well before counter exhaustion or on a time/byte budget.
|
||||
- **Associated data:** all 20 header bytes remain visible and authenticated; the Opus
|
||||
payload is encrypted and followed by a 16-byte tag.
|
||||
- **Nonce discipline:** `nonce = four_zero_bytes ‖ counter_u64_big_endian`. Counters are
|
||||
per directional session key, shared across its streams. Direction separation comes
|
||||
from exporter contexts, not nonce bits. Automatic epoch rekeying is not implemented;
|
||||
the .NET encryptor refuses counter exhaustion and requires a new session.
|
||||
- **Anti-replay:** a 64-bit sliding-window replay filter keyed on the packet counter (à la
|
||||
IPsec). The window is **advanced only after the AEAD tag verifies** (RFC 3711 §3.3 order:
|
||||
replay-check → authenticate → update). The counter is read from the unauthenticated
|
||||
|
||||
Reference in New Issue
Block a user