const PRIVATE_KEY_LEN: usize = 32;
const SIGNED_KEY_LEN: usize = 32;
const COMBINED_KEY_LENGTH: usize = PRIVATE_KEY_LEN + SIGNED_KEY_LEN;
#[cfg(feature = "private")]
const_assert!(crate::secure::private::KEY_LEN == PRIVATE_KEY_LEN);
#[cfg(feature = "signed")]
const_assert!(crate::secure::signed::KEY_LEN == SIGNED_KEY_LEN);
#[cfg_attr(all(doc, not(doctest)), doc(cfg(any(feature = "private", feature = "signed"))))]
#[derive(Clone)]
pub struct Key {
pub(crate) signing: [u8; SIGNED_KEY_LEN],
pub(crate) encryption: [u8; PRIVATE_KEY_LEN]
}
impl Key {
const fn zero() -> Self {
Key { signing: [0; SIGNED_KEY_LEN], encryption: [0; PRIVATE_KEY_LEN] }
}
pub fn from(key: &[u8]) -> Key {
if key.len() < 64 {
panic!("bad key length: expected >= 64 bytes, found {}", key.len());
}
let mut output = Key::zero();
output.signing.copy_from_slice(&key[..SIGNED_KEY_LEN]);
output.encryption.copy_from_slice(&key[SIGNED_KEY_LEN..COMBINED_KEY_LENGTH]);
output
}
pub fn from_master(master_key: &[u8]) -> Self {
if master_key.len() < 32 {
panic!("bad master key length: expected >= 32 bytes, found {}", master_key.len());
}
const KEYS_INFO: &[u8] = b"COOKIE;SIGNED:HMAC-SHA256;PRIVATE:AEAD-AES-256-GCM";
let mut both_keys = [0; SIGNED_KEY_LEN + PRIVATE_KEY_LEN];
let hk = hkdf::Hkdf::<sha2::Sha256>::from_prk(master_key).expect("key length prechecked");
hk.expand(KEYS_INFO, &mut both_keys).expect("expand into keys");
Key::from(&both_keys)
}
pub fn generate() -> Key {
Self::try_generate().expect("failed to generate `Key` from randomness")
}
pub fn try_generate() -> Option<Key> {
use crate::secure::rand::RngCore;
let mut rng = crate::secure::rand::thread_rng();
let mut both_keys = [0; SIGNED_KEY_LEN + PRIVATE_KEY_LEN];
rng.try_fill_bytes(&mut both_keys).ok()?;
Some(Key::from(&both_keys))
}
pub fn signing(&self) -> &[u8] {
&self.signing[..]
}
pub fn encryption(&self) -> &[u8] {
&self.encryption[..]
}
}
#[cfg(test)]
mod test {
use super::Key;
#[test]
fn from_works() {
let key = Key::from(&(0..64).collect::<Vec<_>>());
let signing: Vec<u8> = (0..32).collect();
assert_eq!(key.signing(), &*signing);
let encryption: Vec<u8> = (32..64).collect();
assert_eq!(key.encryption(), &*encryption);
}
#[test]
fn deterministic_derive() {
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());
}
}