/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.16.2/src/aead/quic.rs
Line | Count | Source |
1 | | // Copyright 2018 Brian Smith. |
2 | | // SPDX-License-Identifier: ISC |
3 | | // Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
4 | | // SPDX-License-Identifier: Apache-2.0 OR ISC |
5 | | |
6 | | //! QUIC Header Protection. |
7 | | //! |
8 | | //! See draft-ietf-quic-tls. |
9 | | |
10 | | use crate::cipher::aes::encrypt_block; |
11 | | use crate::cipher::block; |
12 | | use crate::cipher::chacha::encrypt_block_chacha20; |
13 | | use crate::cipher::key::SymmetricCipherKey; |
14 | | use crate::hkdf::KeyType; |
15 | | use crate::{derive_debug_via_id, error, hkdf}; |
16 | | |
17 | | /// A key for generating QUIC Header Protection masks. |
18 | | pub struct HeaderProtectionKey { |
19 | | inner: SymmetricCipherKey, |
20 | | algorithm: &'static Algorithm, |
21 | | } |
22 | | |
23 | | impl From<hkdf::Okm<'_, &'static Algorithm>> for HeaderProtectionKey { |
24 | 0 | fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self { |
25 | 0 | let mut key_bytes = [0; super::MAX_KEY_LEN]; |
26 | 0 | let algorithm = *okm.len(); |
27 | 0 | let key_bytes = &mut key_bytes[..algorithm.key_len()]; |
28 | 0 | okm.fill(key_bytes).unwrap(); |
29 | 0 | Self::new(algorithm, key_bytes).unwrap() |
30 | 0 | } |
31 | | } |
32 | | |
33 | | impl HeaderProtectionKey { |
34 | | /// Create a new header protection key. |
35 | | /// |
36 | | /// # Errors |
37 | | /// `error::Unspecified` when `key_bytes` length is not `algorithm.key_len` |
38 | 0 | pub fn new( |
39 | 0 | algorithm: &'static Algorithm, |
40 | 0 | key_bytes: &[u8], |
41 | 0 | ) -> Result<Self, error::Unspecified> { |
42 | | Ok(Self { |
43 | 0 | inner: (algorithm.init)(key_bytes)?, |
44 | 0 | algorithm, |
45 | | }) |
46 | 0 | } |
47 | | |
48 | | /// Generate a new QUIC Header Protection mask. |
49 | | /// |
50 | | /// # Errors |
51 | | /// `error::Unspecified` when `sample` length is not `self.algorithm().sample_len()`. |
52 | | #[inline] |
53 | 0 | pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5], error::Unspecified> { |
54 | 0 | let sample = <&[u8; SAMPLE_LEN]>::try_from(sample)?; |
55 | | |
56 | 0 | cipher_new_mask(&self.inner, *sample) |
57 | 0 | } |
58 | | |
59 | | /// The key's algorithm. |
60 | | #[inline] |
61 | | #[must_use] |
62 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
63 | 0 | self.algorithm |
64 | 0 | } |
65 | | } |
66 | | |
67 | | const SAMPLE_LEN: usize = super::TAG_LEN; |
68 | | |
69 | | /// QUIC sample for new key masks |
70 | | pub type Sample = [u8; SAMPLE_LEN]; |
71 | | |
72 | | /// A QUIC Header Protection Algorithm. |
73 | | pub struct Algorithm { |
74 | | init: fn(key: &[u8]) -> Result<SymmetricCipherKey, error::Unspecified>, |
75 | | |
76 | | key_len: usize, |
77 | | id: AlgorithmID, |
78 | | } |
79 | | |
80 | | impl KeyType for &'static Algorithm { |
81 | | #[inline] |
82 | 0 | fn len(&self) -> usize { |
83 | 0 | self.key_len() |
84 | 0 | } |
85 | | } |
86 | | |
87 | | impl Algorithm { |
88 | | /// The length of the key. |
89 | | #[inline] |
90 | | #[must_use] |
91 | 0 | pub fn key_len(&self) -> usize { |
92 | 0 | self.key_len |
93 | 0 | } |
94 | | |
95 | | /// The required sample length. |
96 | | #[inline] |
97 | | #[must_use] |
98 | 0 | pub fn sample_len(&self) -> usize { |
99 | 0 | SAMPLE_LEN |
100 | 0 | } |
101 | | } |
102 | | |
103 | | derive_debug_via_id!(Algorithm); |
104 | | |
105 | | #[derive(Debug, Eq, PartialEq)] |
106 | | #[allow(non_camel_case_types)] |
107 | | enum AlgorithmID { |
108 | | AES_128, |
109 | | AES_256, |
110 | | CHACHA20, |
111 | | } |
112 | | |
113 | | impl PartialEq for Algorithm { |
114 | | #[inline] |
115 | 0 | fn eq(&self, other: &Self) -> bool { |
116 | 0 | self.id == other.id |
117 | 0 | } |
118 | | } |
119 | | |
120 | | impl Eq for Algorithm {} |
121 | | |
122 | | /// AES-128. |
123 | | pub const AES_128: Algorithm = Algorithm { |
124 | | key_len: 16, |
125 | | init: SymmetricCipherKey::aes128, |
126 | | id: AlgorithmID::AES_128, |
127 | | }; |
128 | | |
129 | | /// AES-256. |
130 | | pub const AES_256: Algorithm = Algorithm { |
131 | | key_len: 32, |
132 | | init: SymmetricCipherKey::aes256, |
133 | | id: AlgorithmID::AES_256, |
134 | | }; |
135 | | |
136 | | /// `ChaCha20`. |
137 | | pub const CHACHA20: Algorithm = Algorithm { |
138 | | key_len: 32, |
139 | | init: SymmetricCipherKey::chacha20, |
140 | | id: AlgorithmID::CHACHA20, |
141 | | }; |
142 | | |
143 | | #[inline] |
144 | 0 | fn cipher_new_mask( |
145 | 0 | cipher_key: &SymmetricCipherKey, |
146 | 0 | sample: Sample, |
147 | 0 | ) -> Result<[u8; 5], error::Unspecified> { |
148 | 0 | let block = block::Block::from(sample); |
149 | | |
150 | 0 | let encrypted_block = match cipher_key { |
151 | 0 | SymmetricCipherKey::Aes128 { enc_key, .. } |
152 | 0 | | SymmetricCipherKey::Aes192 { enc_key, .. } |
153 | 0 | | SymmetricCipherKey::Aes256 { enc_key, .. } => encrypt_block(enc_key, block), |
154 | 0 | SymmetricCipherKey::ChaCha20 { raw_key } => { |
155 | 0 | let plaintext = block.as_ref(); |
156 | 0 | let counter_bytes: &[u8; 4] = plaintext[0..=3] |
157 | 0 | .try_into() |
158 | 0 | .map_err(|_| error::Unspecified)?; |
159 | 0 | let nonce: &[u8; 12] = plaintext[4..=15] |
160 | 0 | .try_into() |
161 | 0 | .map_err(|_| error::Unspecified)?; |
162 | 0 | let input = block::Block::zero(); |
163 | 0 | let counter = u32::from_ne_bytes(*counter_bytes).to_le(); |
164 | 0 | encrypt_block_chacha20(raw_key, input, nonce, counter)? |
165 | | } |
166 | | }; |
167 | | |
168 | 0 | let mut out: [u8; 5] = [0; 5]; |
169 | 0 | out.copy_from_slice(&encrypted_block.as_ref()[..5]); |
170 | 0 | Ok(out) |
171 | 0 | } |
172 | | |
173 | | #[cfg(test)] |
174 | | mod test { |
175 | | use crate::aead::quic::{Algorithm, HeaderProtectionKey}; |
176 | | use crate::test; |
177 | | |
178 | | #[test] |
179 | | fn test_types() { |
180 | | test::compile_time_assert_send::<Algorithm>(); |
181 | | test::compile_time_assert_sync::<Algorithm>(); |
182 | | |
183 | | test::compile_time_assert_send::<HeaderProtectionKey>(); |
184 | | test::compile_time_assert_sync::<HeaderProtectionKey>(); |
185 | | } |
186 | | } |