quic_crypto (quic v1.3.1)

View Source

TLS 1.3 key schedule and cryptographic operations for QUIC.

This module implements the TLS 1.3 key schedule used by QUIC for deriving encryption keys at each handshake stage.

Key Schedule

TLS 1.3 uses a three-stage key schedule: 1. Early Secret (from PSK, or zeros for non-PSK) 2. Handshake Secret (from ECDHE shared secret) 3. Master Secret (for application data)

Traffic Secrets

From each secret, traffic secrets are derived for both client and server directions.

Summary

Functions

Map cipher suite to corresponding hash algorithm.

Compute the Finished verify_data. verify_data = HMAC(finished_key, Transcript-Hash(Handshake Context))

Compute the Finished verify_data with cipher-specific hash.

Compute PSK binder value for a pre_shared_key extension. RFC 8446 Section 4.2.11.2: binder_key = Derive-Secret(early_secret, "res binder" | "ext binder", "") binder = HMAC(binder_key, Transcript-Hash(Truncated ClientHello)) For resumption PSK, use "res binder". For external PSK, use "ext binder".

Compute PSK binder with cipher-specific hash.

Compute the integrity tag for a Retry packet. Used by servers to generate tags and by clients to verify.

Compute ECDHE shared secret. shared_secret = ECDH(our_private, their_public)

Derive client application traffic secret. client_application_traffic_secret_0 = Derive-Secret( master_secret, "c ap traffic", ClientHello...server Finished)

Derive client application traffic secret with cipher-specific hash.

Derive client early traffic secret. client_early_traffic_secret = Derive-Secret(early_secret, "c e traffic", ClientHello) This is used to encrypt 0-RTT data before the handshake completes.

Derive client early traffic secret with cipher-specific hash.

Derive client handshake traffic secret. client_handshake_traffic_secret = Derive-Secret( handshake_secret, "c hs traffic", ClientHello...ServerHello)

Derive client handshake traffic secret with cipher-specific hash.

Derive early exporter master secret. early_exporter_master_secret = Derive-Secret(early_secret, "e exp master", ClientHello)

Derive early secret without PSK (zeros). early_secret = HKDF-Extract(0, 0)

Derive early secret with PSK. early_secret = HKDF-Extract(0, PSK)

Derive early secret with cipher-specific hash.

Derive the finished key from a traffic secret. finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)

Derive the finished key with cipher-specific hash.

Derive handshake secret from early secret and ECDHE shared secret. handshake_secret = HKDF-Extract( Derive-Secret(early_secret, "derived", ""), shared_secret)

Derive handshake secret with cipher-specific hash.

Derive master secret from handshake secret. master_secret = HKDF-Extract( Derive-Secret(handshake_secret, "derived", ""), 0)

Derive master secret with cipher-specific hash.

Derive-Secret with raw messages (will be hashed). Derive-Secret(Secret, Label, Messages) = HKDF-Expand-Label(Secret, Label, Transcript-Hash(Messages), Hash.length)

Derive-Secret with specified hash algorithm.

Derive server application traffic secret. server_application_traffic_secret_0 = Derive-Secret( master_secret, "s ap traffic", ClientHello...server Finished)

Derive server application traffic secret with cipher-specific hash.

Derive server handshake traffic secret. server_handshake_traffic_secret = Derive-Secret( handshake_secret, "s hs traffic", ClientHello...ServerHello)

Derive server handshake traffic secret with cipher-specific hash.

Generate an ECDHE key pair for the specified curve. Returns {PublicKey, PrivateKey}

Compute transcript hash of handshake messages (default SHA-256).

Compute transcript hash with specified hash algorithm or cipher. Accepts both hash atoms (sha256, sha384) and cipher atoms (aes_128_gcm, aes_256_gcm).

Verify the integrity tag of a Retry packet. RFC 9001 Section 5.8: - Retry Pseudo-Packet = <ODCID length> <ODCID> <Retry packet without tag> - Tag = AES-128-GCM(Key, Nonce, AAD=Pseudo-Packet, "") Returns true if the tag is valid, false otherwise.

Functions

cipher_to_hash(_)

-spec cipher_to_hash(atom()) -> atom().

Map cipher suite to corresponding hash algorithm.

compute_finished_verify(FinishedKey, TranscriptHash)

-spec compute_finished_verify(binary(), binary()) -> binary().

Compute the Finished verify_data. verify_data = HMAC(finished_key, Transcript-Hash(Handshake Context))

compute_finished_verify(Cipher, FinishedKey, TranscriptHash)

-spec compute_finished_verify(atom(), binary(), binary()) -> binary().

Compute the Finished verify_data with cipher-specific hash.

compute_psk_binder(EarlySecret, TruncatedClientHelloHash, Type)

-spec compute_psk_binder(binary(), binary(), resumption | external) -> binary().

Compute PSK binder value for a pre_shared_key extension. RFC 8446 Section 4.2.11.2: binder_key = Derive-Secret(early_secret, "res binder" | "ext binder", "") binder = HMAC(binder_key, Transcript-Hash(Truncated ClientHello)) For resumption PSK, use "res binder". For external PSK, use "ext binder".

compute_psk_binder(Cipher, EarlySecret, TruncatedClientHelloHash, Type)

-spec compute_psk_binder(atom(), binary(), binary(), resumption | external) -> binary().

Compute PSK binder with cipher-specific hash.

compute_retry_integrity_tag(OriginalDCID, RetryPacketWithoutTag, Version)

-spec compute_retry_integrity_tag(binary(), binary(), non_neg_integer()) -> binary().

Compute the integrity tag for a Retry packet. Used by servers to generate tags and by clients to verify.

compute_shared_secret(Curve, OurPrivate, TheirPublic)

-spec compute_shared_secret(x25519 | x448 | secp256r1 | secp384r1, binary(), binary()) -> binary().

Compute ECDHE shared secret. shared_secret = ECDH(our_private, their_public)

derive_client_app_secret(MasterSecret, TranscriptHash)

-spec derive_client_app_secret(binary(), binary()) -> binary().

Derive client application traffic secret. client_application_traffic_secret_0 = Derive-Secret( master_secret, "c ap traffic", ClientHello...server Finished)

derive_client_app_secret(Cipher, MasterSecret, TranscriptHash)

-spec derive_client_app_secret(atom(), binary(), binary()) -> binary().

Derive client application traffic secret with cipher-specific hash.

derive_client_early_traffic_secret(EarlySecret, ClientHelloHash)

-spec derive_client_early_traffic_secret(binary(), binary()) -> binary().

Derive client early traffic secret. client_early_traffic_secret = Derive-Secret(early_secret, "c e traffic", ClientHello) This is used to encrypt 0-RTT data before the handshake completes.

derive_client_early_traffic_secret(Cipher, EarlySecret, ClientHelloHash)

-spec derive_client_early_traffic_secret(atom(), binary(), binary()) -> binary().

Derive client early traffic secret with cipher-specific hash.

derive_client_handshake_secret(HandshakeSecret, TranscriptHash)

-spec derive_client_handshake_secret(binary(), binary()) -> binary().

Derive client handshake traffic secret. client_handshake_traffic_secret = Derive-Secret( handshake_secret, "c hs traffic", ClientHello...ServerHello)

derive_client_handshake_secret(Cipher, HandshakeSecret, TranscriptHash)

-spec derive_client_handshake_secret(atom(), binary(), binary()) -> binary().

Derive client handshake traffic secret with cipher-specific hash.

derive_early_exporter_master_secret(EarlySecret, ClientHelloHash)

-spec derive_early_exporter_master_secret(binary(), binary()) -> binary().

Derive early exporter master secret. early_exporter_master_secret = Derive-Secret(early_secret, "e exp master", ClientHello)

derive_early_secret()

-spec derive_early_secret() -> binary().

Derive early secret without PSK (zeros). early_secret = HKDF-Extract(0, 0)

derive_early_secret(PSK)

-spec derive_early_secret(binary()) -> binary().

Derive early secret with PSK. early_secret = HKDF-Extract(0, PSK)

derive_early_secret(Cipher, PSK)

-spec derive_early_secret(atom(), binary()) -> binary().

Derive early secret with cipher-specific hash.

derive_finished_key(TrafficSecret)

-spec derive_finished_key(binary()) -> binary().

Derive the finished key from a traffic secret. finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)

derive_finished_key(Cipher, TrafficSecret)

-spec derive_finished_key(atom(), binary()) -> binary().

Derive the finished key with cipher-specific hash.

derive_handshake_secret(EarlySecret, SharedSecret)

-spec derive_handshake_secret(binary(), binary()) -> binary().

Derive handshake secret from early secret and ECDHE shared secret. handshake_secret = HKDF-Extract( Derive-Secret(early_secret, "derived", ""), shared_secret)

derive_handshake_secret(Cipher, EarlySecret, SharedSecret)

-spec derive_handshake_secret(atom(), binary(), binary()) -> binary().

Derive handshake secret with cipher-specific hash.

derive_master_secret(HandshakeSecret)

-spec derive_master_secret(binary()) -> binary().

Derive master secret from handshake secret. master_secret = HKDF-Extract( Derive-Secret(handshake_secret, "derived", ""), 0)

derive_master_secret(Cipher, HandshakeSecret)

-spec derive_master_secret(atom(), binary()) -> binary().

Derive master secret with cipher-specific hash.

derive_secret(Secret, Label, Messages)

-spec derive_secret(binary(), binary(), binary()) -> binary().

Derive-Secret with raw messages (will be hashed). Derive-Secret(Secret, Label, Messages) = HKDF-Expand-Label(Secret, Label, Transcript-Hash(Messages), Hash.length)

derive_secret(Hash, Secret, Label, Messages)

-spec derive_secret(atom(), binary(), binary(), binary()) -> binary().

Derive-Secret with specified hash algorithm.

derive_server_app_secret(MasterSecret, TranscriptHash)

-spec derive_server_app_secret(binary(), binary()) -> binary().

Derive server application traffic secret. server_application_traffic_secret_0 = Derive-Secret( master_secret, "s ap traffic", ClientHello...server Finished)

derive_server_app_secret(Cipher, MasterSecret, TranscriptHash)

-spec derive_server_app_secret(atom(), binary(), binary()) -> binary().

Derive server application traffic secret with cipher-specific hash.

derive_server_handshake_secret(HandshakeSecret, TranscriptHash)

-spec derive_server_handshake_secret(binary(), binary()) -> binary().

Derive server handshake traffic secret. server_handshake_traffic_secret = Derive-Secret( handshake_secret, "s hs traffic", ClientHello...ServerHello)

derive_server_handshake_secret(Cipher, HandshakeSecret, TranscriptHash)

-spec derive_server_handshake_secret(atom(), binary(), binary()) -> binary().

Derive server handshake traffic secret with cipher-specific hash.

generate_key_pair(Curve)

-spec generate_key_pair(x25519 | x448 | secp256r1 | secp384r1) -> {binary(), binary()}.

Generate an ECDHE key pair for the specified curve. Returns {PublicKey, PrivateKey}

hash_len(_)

transcript_hash(Messages)

-spec transcript_hash(binary()) -> binary().

Compute transcript hash of handshake messages (default SHA-256).

transcript_hash(HashOrCipher, Messages)

-spec transcript_hash(atom(), binary()) -> binary().

Compute transcript hash with specified hash algorithm or cipher. Accepts both hash atoms (sha256, sha384) and cipher atoms (aes_128_gcm, aes_256_gcm).

verify_retry_integrity_tag(OriginalDCID, RetryPacket, Version)

-spec verify_retry_integrity_tag(binary(), binary(), non_neg_integer()) -> boolean().

Verify the integrity tag of a Retry packet. RFC 9001 Section 5.8: - Retry Pseudo-Packet = <ODCID length> <ODCID> <Retry packet without tag> - Tag = AES-128-GCM(Key, Nonce, AAD=Pseudo-Packet, "") Returns true if the tag is valid, false otherwise.