1#![allow(clippy::duplicate_mod)]
2
3use alloc::boxed::Box;
4
5use super::ring_like::aead;
6use crate::crypto::cipher::{AeadKey, Iv, Nonce};
7use crate::error::Error;
8use crate::quic;
9
10pub(crate) struct HeaderProtectionKey(aead::quic::HeaderProtectionKey);
11
12impl HeaderProtectionKey {
13 pub(crate) fn new(key: AeadKey, alg: &'static aead::quic::Algorithm) -> Self {
14 Self(aead::quic::HeaderProtectionKey::new(alg, key.as_ref()).unwrap())
15 }
16
17 fn xor_in_place(
18 &self,
19 sample: &[u8],
20 first: &mut u8,
21 packet_number: &mut [u8],
22 masked: bool,
23 ) -> Result<(), Error> {
24 let mask = self
28 .0
29 .new_mask(sample)
30 .map_err(|_| Error::General("sample of invalid length".into()))?;
31
32 let (first_mask, pn_mask) = mask.split_first().unwrap();
35
36 if packet_number.len() > pn_mask.len() {
39 return Err(Error::General("packet number too long".into()));
40 }
41
42 const LONG_HEADER_FORM: u8 = 0x80;
46 let bits = match *first & LONG_HEADER_FORM == LONG_HEADER_FORM {
47 true => 0x0f, false => 0x1f, };
50
51 let first_plain = match masked {
52 true => *first ^ (first_mask & bits),
54 false => *first,
56 };
57 let pn_len = (first_plain & 0x03) as usize + 1;
58
59 *first ^= first_mask & bits;
60 for (dst, m) in packet_number
61 .iter_mut()
62 .zip(pn_mask)
63 .take(pn_len)
64 {
65 *dst ^= m;
66 }
67
68 Ok(())
69 }
70}
71
72impl quic::HeaderProtectionKey for HeaderProtectionKey {
73 fn encrypt_in_place(
74 &self,
75 sample: &[u8],
76 first: &mut u8,
77 packet_number: &mut [u8],
78 ) -> Result<(), Error> {
79 self.xor_in_place(sample, first, packet_number, false)
80 }
81
82 fn decrypt_in_place(
83 &self,
84 sample: &[u8],
85 first: &mut u8,
86 packet_number: &mut [u8],
87 ) -> Result<(), Error> {
88 self.xor_in_place(sample, first, packet_number, true)
89 }
90
91 #[inline]
92 fn sample_len(&self) -> usize {
93 self.0.algorithm().sample_len()
94 }
95}
96
97pub(crate) struct PacketKey {
98 key: aead::LessSafeKey,
100 iv: Iv,
102 confidentiality_limit: u64,
104 integrity_limit: u64,
106}
107
108impl PacketKey {
109 pub(crate) fn new(
110 key: AeadKey,
111 iv: Iv,
112 confidentiality_limit: u64,
113 integrity_limit: u64,
114 aead_algorithm: &'static aead::Algorithm,
115 ) -> Self {
116 Self {
117 key: aead::LessSafeKey::new(
118 aead::UnboundKey::new(aead_algorithm, key.as_ref()).unwrap(),
119 ),
120 iv,
121 confidentiality_limit,
122 integrity_limit,
123 }
124 }
125}
126
127impl quic::PacketKey for PacketKey {
128 fn encrypt_in_place(
129 &self,
130 packet_number: u64,
131 header: &[u8],
132 payload: &mut [u8],
133 ) -> Result<quic::Tag, Error> {
134 let aad = aead::Aad::from(header);
135 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, packet_number).0);
136 let tag = self
137 .key
138 .seal_in_place_separate_tag(nonce, aad, payload)
139 .map_err(|_| Error::EncryptError)?;
140 Ok(quic::Tag::from(tag.as_ref()))
141 }
142
143 fn decrypt_in_place<'a>(
151 &self,
152 packet_number: u64,
153 header: &[u8],
154 payload: &'a mut [u8],
155 ) -> Result<&'a [u8], Error> {
156 let payload_len = payload.len();
157 let aad = aead::Aad::from(header);
158 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, packet_number).0);
159 self.key
160 .open_in_place(nonce, aad, payload)
161 .map_err(|_| Error::DecryptError)?;
162
163 let plain_len = payload_len - self.key.algorithm().tag_len();
164 Ok(&payload[..plain_len])
165 }
166
167 #[inline]
169 fn tag_len(&self) -> usize {
170 self.key.algorithm().tag_len()
171 }
172
173 fn confidentiality_limit(&self) -> u64 {
175 self.confidentiality_limit
176 }
177
178 fn integrity_limit(&self) -> u64 {
180 self.integrity_limit
181 }
182}
183
184pub(crate) struct KeyBuilder {
185 pub(crate) packet_alg: &'static aead::Algorithm,
186 pub(crate) header_alg: &'static aead::quic::Algorithm,
187 pub(crate) confidentiality_limit: u64,
188 pub(crate) integrity_limit: u64,
189}
190
191impl quic::Algorithm for KeyBuilder {
192 fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn quic::PacketKey> {
193 Box::new(PacketKey::new(
194 key,
195 iv,
196 self.confidentiality_limit,
197 self.integrity_limit,
198 self.packet_alg,
199 ))
200 }
201
202 fn header_protection_key(&self, key: AeadKey) -> Box<dyn quic::HeaderProtectionKey> {
203 Box::new(HeaderProtectionKey::new(key, self.header_alg))
204 }
205
206 fn aead_key_len(&self) -> usize {
207 self.packet_alg.key_len()
208 }
209
210 fn fips(&self) -> bool {
211 super::fips()
212 }
213}
214
215#[cfg(test)]
216#[macro_rules_attribute::apply(test_for_each_provider)]
217mod tests {
218 use std::dbg;
219
220 use super::provider::tls13::{
221 TLS13_AES_128_GCM_SHA256_INTERNAL, TLS13_CHACHA20_POLY1305_SHA256_INTERNAL,
222 };
223 use crate::common_state::Side;
224 use crate::crypto::tls13::OkmBlock;
225 use crate::quic::*;
226
227 fn test_short_packet(version: Version, expected: &[u8]) {
228 const PN: u64 = 654360564;
229 const SECRET: &[u8] = &[
230 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42, 0x27, 0x48, 0xad,
231 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0, 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3,
232 0x0f, 0x21, 0x63, 0x2b,
233 ];
234
235 let secret = OkmBlock::new(SECRET);
236 let builder = KeyBuilder::new(
237 &secret,
238 version,
239 TLS13_CHACHA20_POLY1305_SHA256_INTERNAL
240 .quic
241 .unwrap(),
242 TLS13_CHACHA20_POLY1305_SHA256_INTERNAL.hkdf_provider,
243 );
244 let packet = builder.packet_key();
245 let hpk = builder.header_protection_key();
246
247 const PLAIN: &[u8] = &[0x42, 0x00, 0xbf, 0xf4, 0x01];
248
249 let mut buf = PLAIN.to_vec();
250 let (header, payload) = buf.split_at_mut(4);
251 let tag = packet
252 .encrypt_in_place(PN, header, payload)
253 .unwrap();
254 buf.extend(tag.as_ref());
255
256 let pn_offset = 1;
257 let (header, sample) = buf.split_at_mut(pn_offset + 4);
258 let (first, rest) = header.split_at_mut(1);
259 let sample = &sample[..hpk.sample_len()];
260 hpk.encrypt_in_place(sample, &mut first[0], dbg!(rest))
261 .unwrap();
262
263 assert_eq!(&buf, expected);
264
265 let (header, sample) = buf.split_at_mut(pn_offset + 4);
266 let (first, rest) = header.split_at_mut(1);
267 let sample = &sample[..hpk.sample_len()];
268 hpk.decrypt_in_place(sample, &mut first[0], rest)
269 .unwrap();
270
271 let (header, payload_tag) = buf.split_at_mut(4);
272 let plain = packet
273 .decrypt_in_place(PN, header, payload_tag)
274 .unwrap();
275
276 assert_eq!(plain, &PLAIN[4..]);
277 }
278
279 #[test]
280 fn short_packet_header_protection() {
281 test_short_packet(
283 Version::V1,
284 &[
285 0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6, 0x90, 0x80, 0x57,
286 0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb,
287 ],
288 );
289 }
290
291 #[test]
292 fn key_update_test_vector() {
293 fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool {
294 x.as_ref() == y.as_ref()
295 }
296
297 let mut secrets = Secrets::new(
298 OkmBlock::new(
300 &[
301 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
302 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
303 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
304 ][..],
305 ),
306 OkmBlock::new(
307 &[
308 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
309 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
310 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
311 ][..],
312 ),
313 TLS13_AES_128_GCM_SHA256_INTERNAL,
314 TLS13_AES_128_GCM_SHA256_INTERNAL
315 .quic
316 .unwrap(),
317 Side::Client,
318 Version::V1,
319 );
320 secrets.update();
321
322 assert!(equal_okm(
323 &secrets.client,
324 &OkmBlock::new(
325 &[
326 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
327 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
328 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
329 ][..]
330 )
331 ));
332 assert!(equal_okm(
333 &secrets.server,
334 &OkmBlock::new(
335 &[
336 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
337 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
338 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
339 ][..]
340 )
341 ));
342 }
343
344 #[test]
345 fn short_packet_header_protection_v2() {
346 test_short_packet(
348 Version::V2,
349 &[
350 0x55, 0x58, 0xb1, 0xc6, 0x0a, 0xe7, 0xb6, 0xb9, 0x32, 0xbc, 0x27, 0xd7, 0x86, 0xf4,
351 0xbc, 0x2b, 0xb2, 0x0f, 0x21, 0x62, 0xba,
352 ],
353 );
354 }
355
356 #[test]
357 fn initial_test_vector_v2() {
358 let icid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
360 let server = Keys::initial(
361 Version::V2,
362 TLS13_AES_128_GCM_SHA256_INTERNAL,
363 TLS13_AES_128_GCM_SHA256_INTERNAL
364 .quic
365 .unwrap(),
366 &icid,
367 Side::Server,
368 );
369 let mut server_payload = [
370 0x02, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x5a, 0x02, 0x00, 0x00, 0x56, 0x03,
371 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1, 0x63, 0x2e, 0x96, 0x67, 0x78,
372 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf, 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43,
373 0x0b, 0x9a, 0x04, 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00,
374 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69, 0x0b, 0x84, 0xd0,
375 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68, 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83,
376 0x4d, 0x53, 0x11, 0xbc, 0xf3, 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03,
377 0x04,
378 ];
379 let mut server_header = [
380 0xd1, 0x6b, 0x33, 0x43, 0xcf, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62,
381 0xb5, 0x00, 0x40, 0x75, 0x00, 0x01,
382 ];
383 let tag = server
384 .local
385 .packet
386 .encrypt_in_place(1, &server_header, &mut server_payload)
387 .unwrap();
388 let (first, rest) = server_header.split_at_mut(1);
389 let rest_len = rest.len();
390 server
391 .local
392 .header
393 .encrypt_in_place(
394 &server_payload[2..18],
395 &mut first[0],
396 &mut rest[rest_len - 2..],
397 )
398 .unwrap();
399 let mut server_packet = server_header.to_vec();
400 server_packet.extend(server_payload);
401 server_packet.extend(tag.as_ref());
402 let expected_server_packet = [
403 0xdc, 0x6b, 0x33, 0x43, 0xcf, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62,
404 0xb5, 0x00, 0x40, 0x75, 0xd9, 0x2f, 0xaa, 0xf1, 0x6f, 0x05, 0xd8, 0xa4, 0x39, 0x8c,
405 0x47, 0x08, 0x96, 0x98, 0xba, 0xee, 0xa2, 0x6b, 0x91, 0xeb, 0x76, 0x1d, 0x9b, 0x89,
406 0x23, 0x7b, 0xbf, 0x87, 0x26, 0x30, 0x17, 0x91, 0x53, 0x58, 0x23, 0x00, 0x35, 0xf7,
407 0xfd, 0x39, 0x45, 0xd8, 0x89, 0x65, 0xcf, 0x17, 0xf9, 0xaf, 0x6e, 0x16, 0x88, 0x6c,
408 0x61, 0xbf, 0xc7, 0x03, 0x10, 0x6f, 0xba, 0xf3, 0xcb, 0x4c, 0xfa, 0x52, 0x38, 0x2d,
409 0xd1, 0x6a, 0x39, 0x3e, 0x42, 0x75, 0x75, 0x07, 0x69, 0x80, 0x75, 0xb2, 0xc9, 0x84,
410 0xc7, 0x07, 0xf0, 0xa0, 0x81, 0x2d, 0x8c, 0xd5, 0xa6, 0x88, 0x1e, 0xaf, 0x21, 0xce,
411 0xda, 0x98, 0xf4, 0xbd, 0x23, 0xf6, 0xfe, 0x1a, 0x3e, 0x2c, 0x43, 0xed, 0xd9, 0xce,
412 0x7c, 0xa8, 0x4b, 0xed, 0x85, 0x21, 0xe2, 0xe1, 0x40,
413 ];
414 assert_eq!(server_packet[..], expected_server_packet[..]);
415 }
416}