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