/rust/registry/src/index.crates.io-6f17d22bba15001f/ring-0.17.14/src/aead/quic.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2018 Brian Smith. |
2 | | // |
3 | | // Permission to use, copy, modify, and/or distribute this software for any |
4 | | // purpose with or without fee is hereby granted, provided that the above |
5 | | // copyright notice and this permission notice appear in all copies. |
6 | | // |
7 | | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | | |
15 | | //! QUIC Header Protection. |
16 | | //! |
17 | | //! See draft-ietf-quic-tls. |
18 | | |
19 | | use crate::{ |
20 | | aead::{aes, chacha}, |
21 | | cpu, error, hkdf, |
22 | | }; |
23 | | |
24 | | /// A key for generating QUIC Header Protection masks. |
25 | | pub struct HeaderProtectionKey { |
26 | | inner: KeyInner, |
27 | | algorithm: &'static Algorithm, |
28 | | } |
29 | | |
30 | | #[allow(clippy::large_enum_variant, variant_size_differences)] |
31 | | enum KeyInner { |
32 | | Aes(aes::Key), |
33 | | ChaCha20(chacha::Key), |
34 | | } |
35 | | |
36 | | impl From<hkdf::Okm<'_, &'static Algorithm>> for HeaderProtectionKey { |
37 | 0 | fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self { |
38 | 0 | let mut key_bytes = [0; super::MAX_KEY_LEN]; |
39 | 0 | let algorithm = *okm.len(); |
40 | 0 | let key_bytes = &mut key_bytes[..algorithm.key_len()]; |
41 | 0 | okm.fill(key_bytes).unwrap(); |
42 | 0 | Self::new(algorithm, key_bytes).unwrap() |
43 | 0 | } |
44 | | } |
45 | | |
46 | | impl HeaderProtectionKey { |
47 | | /// Create a new header protection key. |
48 | | /// |
49 | | /// `key_bytes` must be exactly `algorithm.key_len` bytes long. |
50 | 0 | pub fn new( |
51 | 0 | algorithm: &'static Algorithm, |
52 | 0 | key_bytes: &[u8], |
53 | 0 | ) -> Result<Self, error::Unspecified> { |
54 | 0 | Ok(Self { |
55 | 0 | inner: (algorithm.init)(key_bytes, cpu::features())?, |
56 | 0 | algorithm, |
57 | | }) |
58 | 0 | } |
59 | | |
60 | | /// Generate a new QUIC Header Protection mask. |
61 | | /// |
62 | | /// `sample` must be exactly `self.algorithm().sample_len()` bytes long. |
63 | 0 | pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5], error::Unspecified> { |
64 | 0 | let sample = <&[u8; SAMPLE_LEN]>::try_from(sample)?; |
65 | | |
66 | 0 | let out = (self.algorithm.new_mask)(&self.inner, *sample); |
67 | 0 | Ok(out) |
68 | 0 | } |
69 | | |
70 | | /// The key's algorithm. |
71 | | #[inline(always)] |
72 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
73 | 0 | self.algorithm |
74 | 0 | } |
75 | | } |
76 | | |
77 | | const SAMPLE_LEN: usize = super::TAG_LEN; |
78 | | |
79 | | /// QUIC sample for new key masks |
80 | | pub type Sample = [u8; SAMPLE_LEN]; |
81 | | |
82 | | /// A QUIC Header Protection Algorithm. |
83 | | pub struct Algorithm { |
84 | | init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>, |
85 | | |
86 | | new_mask: fn(key: &KeyInner, sample: Sample) -> [u8; 5], |
87 | | |
88 | | key_len: usize, |
89 | | id: AlgorithmID, |
90 | | } |
91 | | |
92 | | impl hkdf::KeyType for &'static Algorithm { |
93 | | #[inline] |
94 | 0 | fn len(&self) -> usize { |
95 | 0 | self.key_len() |
96 | 0 | } |
97 | | } |
98 | | |
99 | | impl Algorithm { |
100 | | /// The length of the key. |
101 | | #[inline(always)] |
102 | 0 | pub fn key_len(&self) -> usize { |
103 | 0 | self.key_len |
104 | 0 | } |
105 | | |
106 | | /// The required sample length. |
107 | | #[inline(always)] |
108 | 0 | pub fn sample_len(&self) -> usize { |
109 | 0 | SAMPLE_LEN |
110 | 0 | } |
111 | | } |
112 | | |
113 | | derive_debug_via_id!(Algorithm); |
114 | | |
115 | | #[derive(Debug, Eq, PartialEq)] |
116 | | enum AlgorithmID { |
117 | | AES_128, |
118 | | AES_256, |
119 | | CHACHA20, |
120 | | } |
121 | | |
122 | | impl PartialEq for Algorithm { |
123 | 0 | fn eq(&self, other: &Self) -> bool { |
124 | 0 | self.id == other.id |
125 | 0 | } |
126 | | } |
127 | | |
128 | | impl Eq for Algorithm {} |
129 | | |
130 | | /// AES-128. |
131 | | pub static AES_128: Algorithm = Algorithm { |
132 | | key_len: 16, |
133 | | init: aes_init_128, |
134 | | new_mask: aes_new_mask, |
135 | | id: AlgorithmID::AES_128, |
136 | | }; |
137 | | |
138 | | /// AES-256. |
139 | | pub static AES_256: Algorithm = Algorithm { |
140 | | key_len: 32, |
141 | | init: aes_init_256, |
142 | | new_mask: aes_new_mask, |
143 | | id: AlgorithmID::AES_256, |
144 | | }; |
145 | | |
146 | 0 | fn aes_init_128(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified> { |
147 | 0 | let key = key.try_into().map_err(|_| error::Unspecified)?; |
148 | 0 | let aes_key = aes::Key::new(aes::KeyBytes::AES_128(key), cpu_features)?; |
149 | 0 | Ok(KeyInner::Aes(aes_key)) |
150 | 0 | } |
151 | | |
152 | 0 | fn aes_init_256(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified> { |
153 | 0 | let key = key.try_into().map_err(|_| error::Unspecified)?; |
154 | 0 | let aes_key = aes::Key::new(aes::KeyBytes::AES_256(key), cpu_features)?; |
155 | 0 | Ok(KeyInner::Aes(aes_key)) |
156 | 0 | } |
157 | | |
158 | 0 | fn aes_new_mask(key: &KeyInner, sample: Sample) -> [u8; 5] { |
159 | 0 | let aes_key = match key { |
160 | 0 | KeyInner::Aes(key) => key, |
161 | 0 | _ => unreachable!(), |
162 | | }; |
163 | | |
164 | 0 | aes_key.new_mask(sample) |
165 | 0 | } |
166 | | |
167 | | /// ChaCha20. |
168 | | pub static CHACHA20: Algorithm = Algorithm { |
169 | | key_len: chacha::KEY_LEN, |
170 | | init: chacha20_init, |
171 | | new_mask: chacha20_new_mask, |
172 | | id: AlgorithmID::CHACHA20, |
173 | | }; |
174 | | |
175 | 0 | fn chacha20_init(key: &[u8], _cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified> { |
176 | 0 | let chacha20_key: [u8; chacha::KEY_LEN] = key.try_into()?; |
177 | 0 | Ok(KeyInner::ChaCha20(chacha::Key::new(chacha20_key))) |
178 | 0 | } |
179 | | |
180 | 0 | fn chacha20_new_mask(key: &KeyInner, sample: Sample) -> [u8; 5] { |
181 | 0 | let chacha20_key = match key { |
182 | 0 | KeyInner::ChaCha20(key) => key, |
183 | 0 | _ => unreachable!(), |
184 | | }; |
185 | | |
186 | 0 | chacha20_key.new_mask(sample) |
187 | 0 | } |