nquic_packet (nquic v1.0.0)

View Source

QUIC packet parsing and encoding per RFC 9000 Section 17.

Handles long headers (Initial, Handshake, 0-RTT, Retry), short headers (1-RTT), and version negotiation packets. Provides the combined unmask-and-decrypt pipeline for received packets.

Summary

Functions

Map header bits to packet type atom for the given QUIC version.

Phase 2 of the receive pipeline: AEAD-decrypt and decode frames. Pair with unmask_header/6.

Encode a QUIC packet header to binary.

Encode a Version Negotiation packet with DCID/SCID swapped per RFC 9000 Section 17.2.1.

Check whether a QUIC version is supported.

Map packet type atom to header bits for the given QUIC version.

Parse a QUIC packet header from binary.

Parse a QUIC packet header with a known DCID length for short headers.

Parse a Retry packet's token payload into {RetryToken, IntegrityTag}. The raw token field from parse_header contains both the retry token and the 16-byte integrity tag appended at the end.

Return the list of supported QUIC versions (preferred first).

Remove header protection and decrypt a QUIC packet in one pass.

Phase 1 of the receive pipeline: strip header protection and recover the full packet number, returning the unmasked header alongside the recovered packet number, AAD, and ciphertext+tag. The caller is responsible for choosing AEAD keys (e.g. based on the unmasked short-header key_phase) and then calling decrypt_unmasked/5 to finish the AEAD step.

Types

header()

-type header() ::
          #long_header{type :: initial | handshake | rtt0 | retry | version_negotiation,
                       version :: 0..4294967295,
                       dcid :: nquic:connection_id(),
                       scid :: nquic:connection_id(),
                       token :: binary() | undefined,
                       payload_len :: non_neg_integer() | undefined,
                       packet_number :: nquic_packet_number:t() | undefined,
                       pn_len :: 1..4 | undefined} |
          #short_header{dcid :: nquic:connection_id(),
                        packet_number :: nquic_packet_number:t() | undefined,
                        key_phase :: boolean(),
                        spin :: 0..1,
                        pn_len :: 1..4 | undefined}.

space()

-type space() :: initial | handshake | application.

Functions

bits_to_packet_type/2

-spec bits_to_packet_type(0..3, non_neg_integer()) -> initial | rtt0 | handshake | retry.

Map header bits to packet type atom for the given QUIC version.

decrypt_unmasked(Cipher, Keys, PN, AAD, CT)

-spec decrypt_unmasked(aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                       map(),
                       non_neg_integer(),
                       binary(),
                       binary()) ->
                          {ok, [nquic_frame:t()]} | {error, term()}.

Phase 2 of the receive pipeline: AEAD-decrypt and decode frames. Pair with unmask_header/6.

encode_header/1

-spec encode_header(header()) -> binary().

Encode a QUIC packet header to binary.

encode_version_negotiation(DCID, SCID, SupportedVersions)

-spec encode_version_negotiation(nquic:connection_id(), nquic:connection_id(), [non_neg_integer()]) ->
                                    binary().

Encode a Version Negotiation packet with DCID/SCID swapped per RFC 9000 Section 17.2.1.

is_supported_version(Version)

-spec is_supported_version(non_neg_integer()) -> boolean().

Check whether a QUIC version is supported.

maybe_extract_key_phase/2

-spec maybe_extract_key_phase(header(), non_neg_integer()) -> header().

packet_type_bits/2

-spec packet_type_bits(atom(), non_neg_integer()) -> 0..3.

Map packet type atom to header bits for the given QUIC version.

parse_header(Bin)

-spec parse_header(binary()) -> {ok, header(), binary()} | {error, nquic_error:any_reason()}.

Parse a QUIC packet header from binary.

parse_header/2

-spec parse_header(binary(), non_neg_integer()) ->
                      {ok, header(), binary()} | {error, nquic_error:any_reason()}.

Parse a QUIC packet header with a known DCID length for short headers.

parse_retry/2

-spec parse_retry(binary(), binary()) ->
                     {ok, binary(), nquic:connection_id(), binary()} | {error, term()}.

Parse a Retry packet's token payload into {RetryToken, IntegrityTag}. The raw token field from parse_header contains both the retry token and the 16-byte integrity tag appended at the end.

supported_versions()

-spec supported_versions() -> [non_neg_integer()].

Return the list of supported QUIC versions (preferred first).

unmask_and_decrypt(Packet, Rest, Header, Cipher, Keys, LargestRecv)

-spec unmask_and_decrypt(binary(),
                         binary(),
                         header(),
                         aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                         map(),
                         non_neg_integer()) ->
                            {ok, header(), [nquic_frame:t()]} | {error, term()}.

Remove header protection and decrypt a QUIC packet in one pass.

unmask_header(Packet, Rest, Header, Cipher, Keys, LargestRecv)

-spec unmask_header(binary(),
                    binary(),
                    header(),
                    aes_128_gcm | aes_256_gcm | chacha20_poly1305,
                    map(),
                    non_neg_integer()) ->
                       {ok, header(), non_neg_integer(), binary(), binary()} | {error, term()}.

Phase 1 of the receive pipeline: strip header protection and recover the full packet number, returning the unmasked header alongside the recovered packet number, AAD, and ciphertext+tag. The caller is responsible for choosing AEAD keys (e.g. based on the unmasked short-header key_phase) and then calling decrypt_unmasked/5 to finish the AEAD step.