cookie/secure/key.rs
1use std::convert::TryFrom;
2
3const SIGNING_KEY_LEN: usize = 32;
4const ENCRYPTION_KEY_LEN: usize = 32;
5const COMBINED_KEY_LENGTH: usize = SIGNING_KEY_LEN + ENCRYPTION_KEY_LEN;
6
7// Statically ensure the numbers above are in-sync.
8#[cfg(feature = "signed")]
9const_assert!(crate::secure::signed::KEY_LEN == SIGNING_KEY_LEN);
10#[cfg(feature = "private")]
11const_assert!(crate::secure::private::KEY_LEN == ENCRYPTION_KEY_LEN);
12
13/// A cryptographic master key for use with `Signed` and/or `Private` jars.
14///
15/// This structure encapsulates secure, cryptographic keys for use with both
16/// [`PrivateJar`](crate::PrivateJar) and [`SignedJar`](crate::SignedJar). A
17/// single instance of a `Key` can be used for both a `PrivateJar` and a
18/// `SignedJar` simultaneously with no notable security implications.
19#[cfg_attr(all(nightly, doc), doc(cfg(any(feature = "private", feature = "signed"))))]
20#[derive(Clone)]
21pub struct Key([u8; COMBINED_KEY_LENGTH /* SIGNING | ENCRYPTION */]);
22
23impl PartialEq for Key {
24 fn eq(&self, other: &Self) -> bool {
25 use subtle::ConstantTimeEq;
26
27 self.0.ct_eq(&other.0).into()
28 }
29}
30
31impl std::fmt::Debug for Key {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.debug_struct("Key").finish()
34 }
35}
36
37impl Key {
38 // An empty key structure, to be filled.
39 const fn zero() -> Self {
40 Key([0; COMBINED_KEY_LENGTH])
41 }
42
43 /// Creates a new `Key` from a 512-bit cryptographically random string.
44 ///
45 /// The supplied key must be at least 512-bits (64 bytes). For security, the
46 /// master key _must_ be cryptographically random.
47 ///
48 /// # Panics
49 ///
50 /// Panics if `key` is less than 64 bytes in length.
51 ///
52 /// For a non-panicking version, use [`Key::try_from()`] or generate a key with
53 /// [`Key::generate()`] or [`Key::try_generate()`].
54 ///
55 /// # Example
56 ///
57 /// ```rust
58 /// use cookie::Key;
59 ///
60 /// # /*
61 /// let key = { /* a cryptographically random key >= 64 bytes */ };
62 /// # */
63 /// # let key: &Vec<u8> = &(0..64).collect();
64 ///
65 /// let key = Key::from(key);
66 /// ```
67 #[inline]
68 pub fn from(key: &[u8]) -> Key {
69 Key::try_from(key).unwrap()
70 }
71
72 /// Derives new signing/encryption keys from a master key.
73 ///
74 /// The master key must be at least 256-bits (32 bytes). For security, the
75 /// master key _must_ be cryptographically random. The keys are derived
76 /// deterministically from the master key.
77 ///
78 /// # Panics
79 ///
80 /// Panics if `key` is less than 32 bytes in length.
81 ///
82 /// # Example
83 ///
84 /// ```rust
85 /// use cookie::Key;
86 ///
87 /// # /*
88 /// let master_key = { /* a cryptographically random key >= 32 bytes */ };
89 /// # */
90 /// # let master_key: &Vec<u8> = &(0..32).collect();
91 ///
92 /// let key = Key::derive_from(master_key);
93 /// ```
94 #[cfg(feature = "key-expansion")]
95 #[cfg_attr(all(nightly, doc), doc(cfg(feature = "key-expansion")))]
96 pub fn derive_from(master_key: &[u8]) -> Self {
97 if master_key.len() < 32 {
98 panic!("bad master key length: expected >= 32 bytes, found {}", master_key.len());
99 }
100
101 // Expand the master key into two HKDF generated keys.
102 const KEYS_INFO: &[u8] = b"COOKIE;SIGNED:HMAC-SHA256;PRIVATE:AEAD-AES-256-GCM";
103 let mut both_keys = [0; COMBINED_KEY_LENGTH];
104 let hk = hkdf::Hkdf::<sha2::Sha256>::from_prk(master_key).expect("key length prechecked");
105 hk.expand(KEYS_INFO, &mut both_keys).expect("expand into keys");
106 Key::from(&both_keys)
107 }
108
109 /// Generates signing/encryption keys from a secure, random source. Keys are
110 /// generated nondeterministically.
111 ///
112 /// # Panics
113 ///
114 /// Panics if randomness cannot be retrieved from the operating system. See
115 /// [`Key::try_generate()`] for a non-panicking version.
116 ///
117 /// # Example
118 ///
119 /// ```rust
120 /// use cookie::Key;
121 ///
122 /// let key = Key::generate();
123 /// ```
124 pub fn generate() -> Key {
125 Self::try_generate().expect("failed to generate `Key` from randomness")
126 }
127
128 /// Attempts to generate signing/encryption keys from a secure, random
129 /// source. Keys are generated nondeterministically. If randomness cannot be
130 /// retrieved from the underlying operating system, returns `None`.
131 ///
132 /// # Example
133 ///
134 /// ```rust
135 /// use cookie::Key;
136 ///
137 /// let key = Key::try_generate();
138 /// ```
139 pub fn try_generate() -> Option<Key> {
140 use crate::secure::rand::RngCore;
141
142 let mut rng = crate::secure::rand::thread_rng();
143 let mut key = Key::zero();
144 rng.try_fill_bytes(&mut key.0).ok()?;
145 Some(key)
146 }
147
148 /// Returns the raw bytes of a key suitable for signing cookies. Guaranteed
149 /// to be at least 32 bytes.
150 ///
151 /// # Example
152 ///
153 /// ```rust
154 /// use cookie::Key;
155 ///
156 /// let key = Key::generate();
157 /// let signing_key = key.signing();
158 /// ```
159 pub fn signing(&self) -> &[u8] {
160 &self.0[..SIGNING_KEY_LEN]
161 }
162
163 /// Returns the raw bytes of a key suitable for encrypting cookies.
164 /// Guaranteed to be at least 32 bytes.
165 ///
166 /// # Example
167 ///
168 /// ```rust
169 /// use cookie::Key;
170 ///
171 /// let key = Key::generate();
172 /// let encryption_key = key.encryption();
173 /// ```
174 pub fn encryption(&self) -> &[u8] {
175 &self.0[SIGNING_KEY_LEN..]
176 }
177
178 /// Returns the raw bytes of the master key. Guaranteed to be at least 64
179 /// bytes.
180 ///
181 /// # Example
182 ///
183 /// ```rust
184 /// use cookie::Key;
185 ///
186 /// let key = Key::generate();
187 /// let master_key = key.master();
188 /// ```
189 pub fn master(&self) -> &[u8] {
190 &self.0
191 }
192}
193
194/// An error indicating an issue with generating or constructing a key.
195#[cfg_attr(all(nightly, doc), doc(cfg(any(feature = "private", feature = "signed"))))]
196#[derive(Debug)]
197#[non_exhaustive]
198pub enum KeyError {
199 /// Too few bytes (`.0`) were provided to generate a key.
200 ///
201 /// See [`Key::from()`] for minimum requirements.
202 TooShort(usize),
203}
204
205impl std::error::Error for KeyError { }
206
207impl std::fmt::Display for KeyError {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 match self {
210 KeyError::TooShort(n) => {
211 write!(f, "key material is too short: expected >= {} bytes, got {} bytes",
212 COMBINED_KEY_LENGTH, n)
213 }
214 }
215 }
216}
217
218impl TryFrom<&[u8]> for Key {
219 type Error = KeyError;
220
221 /// A fallible version of [`Key::from()`].
222 ///
223 /// Succeeds when [`Key::from()`] succeds and returns an error where
224 /// [`Key::from()`] panics, namely, if `key` is too short.
225 ///
226 /// # Example
227 ///
228 /// ```rust
229 /// # use std::convert::TryFrom;
230 /// use cookie::Key;
231 ///
232 /// # /*
233 /// let key = { /* a cryptographically random key >= 64 bytes */ };
234 /// # */
235 /// # let key: &Vec<u8> = &(0..64).collect();
236 /// # let key: &[u8] = &key[..];
237 /// assert!(Key::try_from(key).is_ok());
238 ///
239 /// // A key that's far too short to use.
240 /// let key = &[1, 2, 3, 4][..];
241 /// assert!(Key::try_from(key).is_err());
242 /// ```
243 fn try_from(key: &[u8]) -> Result<Self, Self::Error> {
244 if key.len() < COMBINED_KEY_LENGTH {
245 Err(KeyError::TooShort(key.len()))
246 } else {
247 let mut output = Key::zero();
248 output.0.copy_from_slice(&key[..COMBINED_KEY_LENGTH]);
249 Ok(output)
250 }
251 }
252}
253
254#[cfg(test)]
255mod test {
256 use super::Key;
257
258 #[test]
259 fn from_works() {
260 let key = Key::from(&(0..64).collect::<Vec<_>>());
261
262 let signing: Vec<u8> = (0..32).collect();
263 assert_eq!(key.signing(), &*signing);
264
265 let encryption: Vec<u8> = (32..64).collect();
266 assert_eq!(key.encryption(), &*encryption);
267 }
268
269 #[test]
270 fn try_from_works() {
271 use core::convert::TryInto;
272 let data = (0..64).collect::<Vec<_>>();
273 let key_res: Result<Key, _> = data[0..63].try_into();
274 assert!(key_res.is_err());
275
276 let key_res: Result<Key, _> = data.as_slice().try_into();
277 assert!(key_res.is_ok());
278 }
279
280 #[test]
281 #[cfg(feature = "key-expansion")]
282 fn deterministic_derive() {
283 let master_key: Vec<u8> = (0..32).collect();
284
285 let key_a = Key::derive_from(&master_key);
286 let key_b = Key::derive_from(&master_key);
287
288 assert_eq!(key_a.signing(), key_b.signing());
289 assert_eq!(key_a.encryption(), key_b.encryption());
290 assert_ne!(key_a.encryption(), key_a.signing());
291
292 let master_key_2: Vec<u8> = (32..64).collect();
293 let key_2 = Key::derive_from(&master_key_2);
294
295 assert_ne!(key_2.signing(), key_a.signing());
296 assert_ne!(key_2.encryption(), key_a.encryption());
297 }
298
299 #[test]
300 fn non_deterministic_generate() {
301 let key_a = Key::generate();
302 let key_b = Key::generate();
303
304 assert_ne!(key_a.signing(), key_b.signing());
305 assert_ne!(key_a.encryption(), key_b.encryption());
306 }
307
308 #[test]
309 fn debug_does_not_leak_key() {
310 let key = Key::generate();
311
312 assert_eq!(format!("{:?}", key), "Key");
313 }
314}