summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cookie/src/secure/key.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cookie/src/secure/key.rs')
-rw-r--r--third_party/rust/cookie/src/secure/key.rs174
1 files changed, 174 insertions, 0 deletions
diff --git a/third_party/rust/cookie/src/secure/key.rs b/third_party/rust/cookie/src/secure/key.rs
new file mode 100644
index 0000000000..77997ae90d
--- /dev/null
+++ b/third_party/rust/cookie/src/secure/key.rs
@@ -0,0 +1,174 @@
+use secure::ring::hkdf::expand;
+use secure::ring::digest::{SHA256, Algorithm};
+use secure::ring::hmac::SigningKey;
+use secure::ring::rand::{SecureRandom, SystemRandom};
+
+use secure::private::KEY_LEN as PRIVATE_KEY_LEN;
+use secure::signed::KEY_LEN as SIGNED_KEY_LEN;
+
+static HKDF_DIGEST: &'static Algorithm = &SHA256;
+const KEYS_INFO: &'static str = "COOKIE;SIGNED:HMAC-SHA256;PRIVATE:AEAD-AES-256-GCM";
+
+/// A cryptographic master key for use with `Signed` and/or `Private` jars.
+///
+/// This structure encapsulates secure, cryptographic keys for use with both
+/// [PrivateJar](struct.PrivateJar.html) and [SignedJar](struct.SignedJar.html).
+/// It can be derived from a single master key via
+/// [from_master](#method.from_master) or generated from a secure random source
+/// via [generate](#method.generate). A single instance of `Key` can be used for
+/// both a `PrivateJar` and a `SignedJar`.
+///
+/// This type is only available when the `secure` feature is enabled.
+#[derive(Clone)]
+pub struct Key {
+ signing_key: [u8; SIGNED_KEY_LEN],
+ encryption_key: [u8; PRIVATE_KEY_LEN]
+}
+
+impl Key {
+ /// Derives new signing/encryption keys from a master key.
+ ///
+ /// The master key must be at least 256-bits (32 bytes). For security, the
+ /// master key _must_ be cryptographically random. The keys are derived
+ /// deterministically from the master key.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `key` is less than 32 bytes in length.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use cookie::Key;
+ ///
+ /// # /*
+ /// let master_key = { /* a cryptographically random key >= 32 bytes */ };
+ /// # */
+ /// # let master_key: &Vec<u8> = &(0..32).collect();
+ ///
+ /// let key = Key::from_master(master_key);
+ /// ```
+ pub fn from_master(key: &[u8]) -> Key {
+ if key.len() < 32 {
+ panic!("bad master key length: expected at least 32 bytes, found {}", key.len());
+ }
+
+ // Expand the user's key into two.
+ let prk = SigningKey::new(HKDF_DIGEST, key);
+ let mut both_keys = [0; SIGNED_KEY_LEN + PRIVATE_KEY_LEN];
+ expand(&prk, KEYS_INFO.as_bytes(), &mut both_keys);
+
+ // Copy the keys into their respective arrays.
+ let mut signing_key = [0; SIGNED_KEY_LEN];
+ let mut encryption_key = [0; PRIVATE_KEY_LEN];
+ signing_key.copy_from_slice(&both_keys[..SIGNED_KEY_LEN]);
+ encryption_key.copy_from_slice(&both_keys[SIGNED_KEY_LEN..]);
+
+ Key {
+ signing_key: signing_key,
+ encryption_key: encryption_key
+ }
+ }
+
+ /// Generates signing/encryption keys from a secure, random source. Keys are
+ /// generated nondeterministically.
+ ///
+ /// # Panics
+ ///
+ /// Panics if randomness cannot be retrieved from the operating system. See
+ /// [try_generate](#method.try_generate) for a non-panicking version.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use cookie::Key;
+ ///
+ /// let key = Key::generate();
+ /// ```
+ pub fn generate() -> Key {
+ Self::try_generate().expect("failed to generate `Key` from randomness")
+ }
+
+ /// Attempts to generate signing/encryption keys from a secure, random
+ /// source. Keys are generated nondeterministically. If randomness cannot be
+ /// retrieved from the underlying operating system, returns `None`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use cookie::Key;
+ ///
+ /// let key = Key::try_generate();
+ /// ```
+ pub fn try_generate() -> Option<Key> {
+ let mut sign_key = [0; SIGNED_KEY_LEN];
+ let mut enc_key = [0; PRIVATE_KEY_LEN];
+
+ let rng = SystemRandom::new();
+ if rng.fill(&mut sign_key).is_err() || rng.fill(&mut enc_key).is_err() {
+ return None
+ }
+
+ Some(Key { signing_key: sign_key, encryption_key: enc_key })
+ }
+
+ /// Returns the raw bytes of a key suitable for signing cookies.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use cookie::Key;
+ ///
+ /// let key = Key::generate();
+ /// let signing_key = key.signing();
+ /// ```
+ pub fn signing(&self) -> &[u8] {
+ &self.signing_key[..]
+ }
+
+ /// Returns the raw bytes of a key suitable for encrypting cookies.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use cookie::Key;
+ ///
+ /// let key = Key::generate();
+ /// let encryption_key = key.encryption();
+ /// ```
+ pub fn encryption(&self) -> &[u8] {
+ &self.encryption_key[..]
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::Key;
+
+ #[test]
+ fn deterministic_from_master() {
+ let master_key: Vec<u8> = (0..32).collect();
+
+ let key_a = Key::from_master(&master_key);
+ let key_b = Key::from_master(&master_key);
+
+ assert_eq!(key_a.signing(), key_b.signing());
+ assert_eq!(key_a.encryption(), key_b.encryption());
+ assert_ne!(key_a.encryption(), key_a.signing());
+
+ let master_key_2: Vec<u8> = (32..64).collect();
+ let key_2 = Key::from_master(&master_key_2);
+
+ assert_ne!(key_2.signing(), key_a.signing());
+ assert_ne!(key_2.encryption(), key_a.encryption());
+ }
+
+ #[test]
+ fn non_deterministic_generate() {
+ let key_a = Key::generate();
+ let key_b = Key::generate();
+
+ assert_ne!(key_a.signing(), key_b.signing());
+ assert_ne!(key_a.encryption(), key_b.encryption());
+ }
+}