requiem_http/cookie/secure/
key.rs

1use ring::hkdf::{Algorithm, KeyType, Prk, HKDF_SHA256};
2use ring::rand::{SecureRandom, SystemRandom};
3
4use super::private::KEY_LEN as PRIVATE_KEY_LEN;
5use super::signed::KEY_LEN as SIGNED_KEY_LEN;
6
7static HKDF_DIGEST: Algorithm = HKDF_SHA256;
8const KEYS_INFO: &[&[u8]] = &[b"COOKIE;SIGNED:HMAC-SHA256;PRIVATE:AEAD-AES-256-GCM"];
9
10/// A cryptographic master key for use with `Signed` and/or `Private` jars.
11///
12/// This structure encapsulates secure, cryptographic keys for use with both
13/// [PrivateJar](struct.PrivateJar.html) and [SignedJar](struct.SignedJar.html).
14/// It can be derived from a single master key via
15/// [from_master](#method.from_master) or generated from a secure random source
16/// via [generate](#method.generate). A single instance of `Key` can be used for
17/// both a `PrivateJar` and a `SignedJar`.
18///
19/// This type is only available when the `secure` feature is enabled.
20#[derive(Clone)]
21pub struct Key {
22    signing_key: [u8; SIGNED_KEY_LEN],
23    encryption_key: [u8; PRIVATE_KEY_LEN],
24}
25
26impl KeyType for &Key {
27    #[inline]
28    fn len(&self) -> usize {
29        SIGNED_KEY_LEN + PRIVATE_KEY_LEN
30    }
31}
32
33impl Key {
34    /// Derives new signing/encryption keys from a master key.
35    ///
36    /// The master key must be at least 256-bits (32 bytes). For security, the
37    /// master key _must_ be cryptographically random. The keys are derived
38    /// deterministically from the master key.
39    ///
40    /// # Panics
41    ///
42    /// Panics if `key` is less than 32 bytes in length.
43    ///
44    /// # Example
45    ///
46    /// ```rust
47    /// use requiem_http::cookie::Key;
48    ///
49    /// # /*
50    /// let master_key = { /* a cryptographically random key >= 32 bytes */ };
51    /// # */
52    /// # let master_key: &Vec<u8> = &(0..32).collect();
53    ///
54    /// let key = Key::from_master(master_key);
55    /// ```
56    pub fn from_master(key: &[u8]) -> Key {
57        if key.len() < 32 {
58            panic!(
59                "bad master key length: expected at least 32 bytes, found {}",
60                key.len()
61            );
62        }
63
64        // An empty `Key` structure; will be filled in with HKDF derived keys.
65        let mut output_key = Key {
66            signing_key: [0; SIGNED_KEY_LEN],
67            encryption_key: [0; PRIVATE_KEY_LEN],
68        };
69
70        // Expand the master key into two HKDF generated keys.
71        let mut both_keys = [0; SIGNED_KEY_LEN + PRIVATE_KEY_LEN];
72        let prk = Prk::new_less_safe(HKDF_DIGEST, key);
73        let okm = prk.expand(KEYS_INFO, &output_key).expect("okm expand");
74        okm.fill(&mut both_keys).expect("fill keys");
75
76        // Copy the key parts into their respective fields.
77        output_key
78            .signing_key
79            .copy_from_slice(&both_keys[..SIGNED_KEY_LEN]);
80        output_key
81            .encryption_key
82            .copy_from_slice(&both_keys[SIGNED_KEY_LEN..]);
83        output_key
84    }
85
86    /// Generates signing/encryption keys from a secure, random source. Keys are
87    /// generated nondeterministically.
88    ///
89    /// # Panics
90    ///
91    /// Panics if randomness cannot be retrieved from the operating system. See
92    /// [try_generate](#method.try_generate) for a non-panicking version.
93    ///
94    /// # Example
95    ///
96    /// ```rust
97    /// use requiem_http::cookie::Key;
98    ///
99    /// let key = Key::generate();
100    /// ```
101    pub fn generate() -> Key {
102        Self::try_generate().expect("failed to generate `Key` from randomness")
103    }
104
105    /// Attempts to generate signing/encryption keys from a secure, random
106    /// source. Keys are generated nondeterministically. If randomness cannot be
107    /// retrieved from the underlying operating system, returns `None`.
108    ///
109    /// # Example
110    ///
111    /// ```rust
112    /// use requiem_http::cookie::Key;
113    ///
114    /// let key = Key::try_generate();
115    /// ```
116    pub fn try_generate() -> Option<Key> {
117        let mut sign_key = [0; SIGNED_KEY_LEN];
118        let mut enc_key = [0; PRIVATE_KEY_LEN];
119
120        let rng = SystemRandom::new();
121        if rng.fill(&mut sign_key).is_err() || rng.fill(&mut enc_key).is_err() {
122            return None;
123        }
124
125        Some(Key {
126            signing_key: sign_key,
127            encryption_key: enc_key,
128        })
129    }
130
131    /// Returns the raw bytes of a key suitable for signing cookies.
132    ///
133    /// # Example
134    ///
135    /// ```rust
136    /// use requiem_http::cookie::Key;
137    ///
138    /// let key = Key::generate();
139    /// let signing_key = key.signing();
140    /// ```
141    pub fn signing(&self) -> &[u8] {
142        &self.signing_key[..]
143    }
144
145    /// Returns the raw bytes of a key suitable for encrypting cookies.
146    ///
147    /// # Example
148    ///
149    /// ```rust
150    /// use requiem_http::cookie::Key;
151    ///
152    /// let key = Key::generate();
153    /// let encryption_key = key.encryption();
154    /// ```
155    pub fn encryption(&self) -> &[u8] {
156        &self.encryption_key[..]
157    }
158}
159
160#[cfg(test)]
161mod test {
162    use super::Key;
163
164    #[test]
165    fn deterministic_from_master() {
166        let master_key: Vec<u8> = (0..32).collect();
167
168        let key_a = Key::from_master(&master_key);
169        let key_b = Key::from_master(&master_key);
170
171        assert_eq!(key_a.signing(), key_b.signing());
172        assert_eq!(key_a.encryption(), key_b.encryption());
173        assert_ne!(key_a.encryption(), key_a.signing());
174
175        let master_key_2: Vec<u8> = (32..64).collect();
176        let key_2 = Key::from_master(&master_key_2);
177
178        assert_ne!(key_2.signing(), key_a.signing());
179        assert_ne!(key_2.encryption(), key_a.encryption());
180    }
181
182    #[test]
183    fn non_deterministic_generate() {
184        let key_a = Key::generate();
185        let key_b = Key::generate();
186
187        assert_ne!(key_a.signing(), key_b.signing());
188        assert_ne!(key_a.encryption(), key_b.encryption());
189    }
190}