21const uint8_t INITIAL_SALT[20] = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
22 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
25const uint8_t RETRY_KEY[16] = {0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a,
26 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e};
27const uint8_t RETRY_NONCE[12] = {0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb};
30void build_nonce(
const uint8_t iv[12], uint64_t full_pn, uint8_t nonce[12])
32 memcpy(nonce, iv, 12);
33 for (
int i = 0; i < 8; i++)
34 nonce[11 - i] ^= (uint8_t)(full_pn >> (8 * i));
38void quic_keys_from_secret(
const uint8_t secret[QUIC_HKDF_HASH_LEN], QuicPacketKeys *out)
42 quic_hkdf_expand_label(secret,
"quic key", out->key,
sizeof(out->key));
43 quic_hkdf_expand_label(secret,
"quic iv", out->iv,
sizeof(out->iv));
44 quic_hkdf_expand_label(secret,
"quic hp", out->hp,
sizeof(out->hp));
47void quic_derive_initial_secrets(
const uint8_t *dcid,
size_t dcid_len, QuicInitialSecrets *out)
49 uint8_t initial_secret[QUIC_HKDF_HASH_LEN];
50 quic_hkdf_extract(INITIAL_SALT,
sizeof(INITIAL_SALT), dcid, dcid_len, initial_secret);
52 uint8_t client_secret[QUIC_HKDF_HASH_LEN];
53 uint8_t server_secret[QUIC_HKDF_HASH_LEN];
54 quic_hkdf_expand_label(initial_secret,
"client in", client_secret,
sizeof(client_secret));
55 quic_hkdf_expand_label(initial_secret,
"server in", server_secret,
sizeof(server_secret));
57 quic_keys_from_secret(client_secret, &out->client);
58 quic_keys_from_secret(server_secret, &out->server);
61size_t quic_packet_protect(uint8_t *pkt,
size_t cap,
size_t pn_offset, uint8_t pn_len, uint64_t full_pn,
62 size_t payload_len,
const QuicPacketKeys *keys,
bool is_long)
64 if (pn_len < 1 || pn_len > 4)
66 size_t hdr_len = pn_offset + pn_len;
67 size_t total = hdr_len + payload_len + QUIC_AEAD_TAG_LEN;
73 build_nonce(keys->iv, full_pn, nonce);
74 quic_aes128_gcm_seal(keys->key, nonce, pkt, hdr_len, pkt + hdr_len, payload_len, pkt + hdr_len);
79 quic_aes128_init(&hp, keys->hp);
81 quic_aes128_encrypt_block(&hp, pkt + pn_offset + 4, mask);
82 quic_aes128_wipe(&hp);
84 pkt[0] ^= mask[0] & (is_long ? 0x0f : 0x1f);
85 for (uint8_t i = 0; i < pn_len; i++)
86 pkt[pn_offset + i] ^= mask[1 + i];
91size_t quic_packet_unprotect(uint8_t *pkt,
size_t pn_offset,
size_t length, uint64_t largest_pn,
92 const QuicPacketKeys *keys,
bool is_long, uint8_t *out, uint64_t *out_pn)
96 if (length < 4 + QUIC_AEAD_TAG_LEN)
100 quic_aes128_init(&hp, keys->hp);
102 quic_aes128_encrypt_block(&hp, pkt + pn_offset + 4, mask);
103 quic_aes128_wipe(&hp);
105 pkt[0] ^= mask[0] & (is_long ? 0x0f : 0x1f);
106 uint8_t pn_len = (uint8_t)((pkt[0] & 0x03) + 1);
108 uint64_t truncated_pn = 0;
109 for (uint8_t i = 0; i < pn_len; i++)
111 pkt[pn_offset + i] ^= mask[1 + i];
112 truncated_pn = (truncated_pn << 8) | pkt[pn_offset + i];
114 uint64_t full_pn = quic_pn_decode(largest_pn, truncated_pn, (uint8_t)(pn_len * 8));
118 size_t hdr_len = pn_offset + pn_len;
119 size_t ct_len = length - pn_len;
121 build_nonce(keys->iv, full_pn, nonce);
122 if (!quic_aes128_gcm_open(keys->key, nonce, pkt, hdr_len, pkt + hdr_len, ct_len, out))
125 return ct_len - QUIC_AEAD_TAG_LEN;
128void quic_retry_integrity_tag(
const uint8_t *odcid,
size_t odcid_len,
const uint8_t *retry,
size_t retry_len,
133 uint8_t aad[1 + QUIC_MAX_CID_LEN + 256];
135 aad[p++] = (uint8_t)odcid_len;
136 if (odcid_len > QUIC_MAX_CID_LEN || 1 + odcid_len + retry_len >
sizeof(aad))
141 memcpy(aad + p, odcid, odcid_len);
143 memcpy(aad + p, retry, retry_len);
147 quic_aes128_gcm_seal(RETRY_KEY, RETRY_NONCE, aad, p,
nullptr, 0, tag);
AES-128 block cipher and AEAD_AES_128_GCM (RFC 5116 / NIST SP 800-38D).
QUIC packet protection: Initial secrets, AEAD payload protection, header protection,...
HKDF-SHA256 (RFC 5869) and TLS 1.3 HKDF-Expand-Label (RFC 8446 sec 7.1).
QUIC packet headers and packet-number coding (RFC 9000 sec 17).