quic_aead (quic v1.3.1)
View SourceAEAD encryption/decryption for QUIC packet protection.
QUIC uses AEAD algorithms (AES-GCM, ChaCha20-Poly1305) to protect packet payloads. Header protection is applied to hide the packet number and certain header flags.
Packet Protection
The nonce for AEAD is computed by XORing the IV with the packet number (left-padded to 12 bytes).
Header Protection
A sample from the encrypted payload is used to generate a mask that protects the first header byte and packet number bytes.
Summary
Functions
Compute the nonce for AEAD by XORing IV with packet number. RFC 9001 Section 5.3: The 64 bits of the reconstructed QUIC packet number in network byte order are left-padded with zeros to the size of the IV.
Decrypt a QUIC packet payload using AEAD.
Decrypt with explicit cipher type. Useful for ChaCha20-Poly1305 which also uses 32-byte keys.
Stage 2: Decrypt short packet payload after key selection. Called after unprotect_short_header with the correct keys based on key_phase.
Encrypt a QUIC packet payload using AEAD.
Encrypt with explicit cipher type. Useful for ChaCha20-Poly1305 which also uses 32-byte keys.
Apply header protection to a QUIC packet.
Protect a long header (Initial/Handshake/0-RTT) packet. Performs encryption and header protection in a single call.
Protect a short header (1-RTT) packet. Performs encryption and header protection in a single call.
Remove header protection from a QUIC packet.
Unprotect and decrypt a long header (Initial/Handshake/0-RTT) packet.
Stage 1: Unprotect short header to recover key_phase and PN info. Uses HP key (same regardless of key phase) to unprotect header.
Unprotect and decrypt a short header (1-RTT) packet.
Types
Functions
-spec compute_nonce(binary(), non_neg_integer()) -> binary().
Compute the nonce for AEAD by XORing IV with packet number. RFC 9001 Section 5.3: The 64 bits of the reconstructed QUIC packet number in network byte order are left-padded with zeros to the size of the IV.
-spec decrypt(binary(), binary(), non_neg_integer(), binary(), binary()) -> {ok, binary()} | {error, bad_tag}.
Decrypt a QUIC packet payload using AEAD.
Returns: {ok, Plaintext} | {error, bad_tag}
-spec decrypt(binary(), binary(), non_neg_integer(), binary(), binary(), cipher()) -> {ok, binary()} | {error, bad_tag}.
Decrypt with explicit cipher type. Useful for ChaCha20-Poly1305 which also uses 32-byte keys.
-spec decrypt_short_payload(cipher(), binary(), binary(), binary(), 1..4, non_neg_integer(), binary(), non_neg_integer() | undefined) -> {ok, non_neg_integer(), binary()} | {error, term()}.
Stage 2: Decrypt short packet payload after key selection. Called after unprotect_short_header with the correct keys based on key_phase.
Cipher: AEAD cipher type Key: AEAD key (selected based on key_phase from stage 1) IV: AEAD IV (selected based on key_phase from stage 1) UnprotectedHeader: From stage 1 (used as AAD) PNLen: From stage 1 TruncatedPN: From stage 1 EncryptedPayload: PN bytes + ciphertext + tag LargestRecv: Largest received packet number for PN reconstruction
Returns: {ok, PN, Plaintext} | {error, term()}
Encrypt a QUIC packet payload using AEAD.
Key: AEAD key IV: AEAD initialization vector PN: Packet number (used with IV to create nonce) AAD: Additional authenticated data (unprotected header) Plaintext: Payload to encrypt
Returns: Ciphertext with authentication tag appended
Encrypt with explicit cipher type. Useful for ChaCha20-Poly1305 which also uses 32-byte keys.
-spec protect_header(binary(), binary(), binary(), non_neg_integer()) -> binary() | {error, payload_too_short}.
Apply header protection to a QUIC packet.
HP: Header protection key Header: The packet header (first byte + rest + PN) EncryptedPayload: The AEAD-encrypted payload (ciphertext + tag) PNOffset: Offset of packet number in the header
The sample is taken starting 4 bytes after the start of the Packet Number. Since PN is at the end of Header, and ciphertext comes after PN: sample_offset = 4 - PNLen (where PNLen is encoded in the first byte)
Returns: Protected header (first byte and PN bytes masked), or {error, payload_too_short} if payload is too small for sampling.
-spec protect_long_packet(cipher(), binary(), binary(), binary(), non_neg_integer(), binary(), iodata()) -> binary().
Protect a long header (Initial/Handshake/0-RTT) packet. Performs encryption and header protection in a single call.
Cipher: AEAD cipher type Key: AEAD key IV: AEAD initialization vector HP: Header protection key PN: Packet number HeaderPrefix: Long header up to (but not including) the packet number Plaintext: Payload to encrypt
Returns: Complete protected packet binary
-spec protect_short_packet(cipher(), binary(), binary(), binary(), non_neg_integer(), byte(), binary(), iodata()) -> binary().
Protect a short header (1-RTT) packet. Performs encryption and header protection in a single call.
Cipher: AEAD cipher type Key: AEAD key IV: AEAD initialization vector HP: Header protection key PN: Packet number FirstByte: First byte of header (includes spin bit, key phase, etc.) DCID: Destination Connection ID Plaintext: Payload to encrypt
Returns: Complete protected packet binary
-spec unprotect_header(binary(), binary(), binary(), non_neg_integer()) -> {binary(), pos_integer()} | {error, payload_too_short}.
Remove header protection from a QUIC packet.
HP: Header protection key ProtectedHeader: The protected header bytes (up to but not including PN) EncryptedPayload: PN bytes + ciphertext + tag PNOffset: Offset of packet number in the full header (= byte_size(ProtectedHeader))
The sample is taken at position 4 from the start of PN. Since EncryptedPayload starts with PN, sample is at position 4.
Returns: {UnprotectedHeader, PNLength} or {error, payload_too_short}
-spec unprotect_long_packet(cipher(), binary(), binary(), binary(), binary(), binary(), non_neg_integer() | undefined) -> {ok, non_neg_integer(), binary(), binary()} | {error, term()}.
Unprotect and decrypt a long header (Initial/Handshake/0-RTT) packet.
Cipher: AEAD cipher type Key: AEAD key IV: AEAD initialization vector HP: Header protection key Header: Protected header up to (but not including) the PN EncryptedPayload: PN bytes + ciphertext + tag LargestRecv: Largest received packet number for PN reconstruction
Returns: {ok, PN, UnprotectedHeader, Plaintext} | {error, term()}
-spec unprotect_short_header(binary(), binary(), binary(), non_neg_integer()) -> {ok, 0 | 1, 1..4, non_neg_integer(), binary()} | {error, term()}.
Stage 1: Unprotect short header to recover key_phase and PN info. Uses HP key (same regardless of key phase) to unprotect header.
HP: Header protection key Header: Protected header (first byte + DCID) EncryptedPayload: PN bytes + ciphertext + tag PNOffset: Offset to packet number in header (= byte_size(Header))
Returns: {ok, KeyPhase, PNLen, TruncatedPN, UnprotectedHeader} | {error, term()}
-spec unprotect_short_packet(cipher(), binary(), binary(), binary(), binary(), binary(), non_neg_integer() | undefined) -> {ok, non_neg_integer(), binary(), binary()} | {error, term()}.
Unprotect and decrypt a short header (1-RTT) packet.
Cipher: AEAD cipher type Key: AEAD key IV: AEAD initialization vector HP: Header protection key Header: Protected header (first byte + DCID, without PN) EncryptedPayload: PN bytes + ciphertext + tag LargestRecv: Largest received packet number for PN reconstruction
Returns: {ok, PN, UnprotectedHeader, Plaintext} | {error, term()}