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