cookie_hashed_domain/secure/key.rs
1const SIGNING_KEY_LEN: usize = 32;
2const ENCRYPTION_KEY_LEN: usize = 32;
3const COMBINED_KEY_LENGTH: usize = SIGNING_KEY_LEN + ENCRYPTION_KEY_LEN;
4
5// Statically ensure the numbers above are in-sync.
6#[cfg(feature = "signed")]
7const_assert!(crate::secure::signed::KEY_LEN == SIGNING_KEY_LEN);
8#[cfg(feature = "private")]
9const_assert!(crate::secure::private::KEY_LEN == ENCRYPTION_KEY_LEN);
10
11/// A cryptographic master key for use with `Signed` and/or `Private` jars.
12///
13/// This structure encapsulates secure, cryptographic keys for use with both
14/// [`PrivateJar`](crate::PrivateJar) and [`SignedJar`](crate::SignedJar). A
15/// single instance of a `Key` can be used for both a `PrivateJar` and a
16/// `SignedJar` simultaneously with no notable security implications.
17#[cfg_attr(all(nightly, doc), doc(cfg(any(feature = "private", feature = "signed"))))]
18#[derive(Clone)]
19pub struct Key([u8; COMBINED_KEY_LENGTH /* SIGNING | ENCRYPTION */]);
20
21impl PartialEq for Key {
22 fn eq(&self, other: &Self) -> bool {
23 use subtle::ConstantTimeEq;
24
25 self.0.ct_eq(&other.0).into()
26 }
27}
28
29impl Key {
30 // An empty key structure, to be filled.
31 const fn zero() -> Self {
32 Key([0; COMBINED_KEY_LENGTH])
33 }
34
35 /// Creates a new `Key` from a 512-bit cryptographically random string.
36 ///
37 /// The supplied key must be at least 512-bits (64 bytes). For security, the
38 /// master key _must_ be cryptographically random.
39 ///
40 /// # Panics
41 ///
42 /// Panics if `key` is less than 64 bytes in length.
43 ///
44 /// # Example
45 ///
46 /// ```rust
47 /// use cookie::Key;
48 ///
49 /// # /*
50 /// let key = { /* a cryptographically random key >= 64 bytes */ };
51 /// # */
52 /// # let key: &Vec<u8> = &(0..64).collect();
53 ///
54 /// let key = Key::from(key);
55 /// ```
56 pub fn from(key: &[u8]) -> Key {
57 if key.len() < 64 {
58 panic!("bad key length: expected >= 64 bytes, found {}", key.len());
59 }
60
61 let mut output = Key::zero();
62 output.0.copy_from_slice(&key[..COMBINED_KEY_LENGTH]);
63 output
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#[cfg(test)]
189mod test {
190 use super::Key;
191
192 #[test]
193 fn from_works() {
194 let key = Key::from(&(0..64).collect::<Vec<_>>());
195
196 let signing: Vec<u8> = (0..32).collect();
197 assert_eq!(key.signing(), &*signing);
198
199 let encryption: Vec<u8> = (32..64).collect();
200 assert_eq!(key.encryption(), &*encryption);
201 }
202
203 #[test]
204 #[cfg(feature = "key-expansion")]
205 fn deterministic_derive() {
206 let master_key: Vec<u8> = (0..32).collect();
207
208 let key_a = Key::derive_from(&master_key);
209 let key_b = Key::derive_from(&master_key);
210
211 assert_eq!(key_a.signing(), key_b.signing());
212 assert_eq!(key_a.encryption(), key_b.encryption());
213 assert_ne!(key_a.encryption(), key_a.signing());
214
215 let master_key_2: Vec<u8> = (32..64).collect();
216 let key_2 = Key::derive_from(&master_key_2);
217
218 assert_ne!(key_2.signing(), key_a.signing());
219 assert_ne!(key_2.encryption(), key_a.encryption());
220 }
221
222 #[test]
223 fn non_deterministic_generate() {
224 let key_a = Key::generate();
225 let key_b = Key::generate();
226
227 assert_ne!(key_a.signing(), key_b.signing());
228 assert_ne!(key_a.encryption(), key_b.encryption());
229 }
230}