ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
Authenticated packet records and rotation

Migrated from docs/crypto-records.md into the rendered Doxygen topic set.

The low-level crypto_encrypt uses a random 16-byte sender prefix followed by a big-endian counter. Its counter, keys, rekey state, and accounting fields are mutable and have no internal lock, so an integrating transport must serialize access to a shared context, including rekey operations. The prefix and counter avoid reuse when used correctly; they do not by themselves prevent replay. crypto_decrypt authenticates the supplied nonce and ciphertext but does not remember received nonces or validate a sender prefix. Packet callers use the authenticated record layer below, which rejects replay.

TCP, WebSocket, WebRTC, native QUIC, and browser WebTransport use the same packet codec, authenticated record format, and rekey coordinator. Packet framing and CRC validation live in lib/network/packet; ACIP policy and envelope handling live in lib/network/acip. The record and rekey engine live in lib/crypto and have no transport dependencies. Each crypto_context_t owns one serialized session with bounded control output.

The shared record codec uses the ACR1 encrypted envelope. The outer ACIP ENCRYPTED payload begins with an eight-byte network-order key epoch, followed by the existing ACIP nonce and authenticated ciphertext. Its encrypted prefix is 24 bytes: ACR1, sender direction, traffic class, delivery mode, one reserved zero byte, a network-order 64-bit sequence, and the same 64-bit epoch. Reliable flows track their own monotonic receive sequence; media datagrams use separate 64-packet replay windows. Sequence and replay state span key changes.

The codec can prepare a next epoch only after the owner completes an authenticated DH exchange. It retains one previous receive context so delayed packets in other flows can still authenticate. The owner retires the previous key separately for each flow after an in-order retirement marker; late old- epoch datagrams on that flow are stale. A second transition is rejected until all three flows retire, bounding retained key material. Retired contexts and all codec-owned key copies are wiped.

Native connections and browser WASM use the same session coordinator. A session mutex serializes record and rotation state; transport callbacks run after releasing it. Native writers and browser timers drive rotation even on idle connections. Packet and time thresholds use the existing crypto configuration (default one million packets or one hour; explicit test environments use one thousand packets or thirty seconds).

Only the server initiates the ephemeral DH exchange. A client reaching its threshold sends an encrypted, empty CRYPTO_REKEY_NEEDED (1113) control message. REKEY_REQUEST (1201) and REKEY_RESPONSE (1202) carry the existing 32-byte X25519 public keys under the old epoch. The server commits the prepared key and sends REKEY_COMPLETE (1203), containing one zero byte, under the new epoch. The client can authenticate media using its prepared key before COMPLETE arrives.

Each side queues CRYPTO_EPOCH_MARKER (1112) reliably on all three flows before later application packets. Its payload is the current epoch as a network-order 64-bit integer. Markers retire old receive keys independently; only after all three retire does a side send CRYPTO_EPOCH_ACK (1114), with the same epoch payload, on control. Another exchange requires both local retirement and the peer ACK. Internal packets never reach application dispatch, and application callers cannot submit them as media or control.

The coordinator preserves the minimum crypto and request intervals. It retains at most one authenticated incoming request until the receive-side interval expires, accommodating changed network delay without bypassing rate limiting. An exchange, including flow retirement, has a thirty-second timeout. Invalid roles, epochs, messages, output queue failures, and timeouts fail the connection. The session bounds internal output to sixteen logical control messages. The writer seals and drains them before later application sends; browser timers stop before crypto cleanup. Cleanup aborts pending DH and wipes retained keys.