use hkdf::Hkdf;
use log::error;
use sha2::Sha256;
use std::convert::From;
pub struct Key([u8; 32]);
impl From<Key> for [u8; 32] {
fn from(key: Key) -> [u8; 32] {
key.0
}
}
pub fn generate_key(salt: Option<&[u8]>, ikm: &[u8], info: Option<&[u8]>) -> Key {
if salt.is_none() && info.is_none() {
error!("At least one of salt/info must be set when using the KDF to generate keys");
panic!("At least one of salt/info must be set when using the KDF to generate keys");
}
let hk = Hkdf::<Sha256>::new(salt, ikm);
let mut okm = [0u8; 32];
hk.expand(info.unwrap_or_default(), &mut okm)
.expect("32 is a valid byte length for Sha256 to output");
Key(okm)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_key_matches_external_tool() {
let ikm = b"hello";
let info: [u8; 7] = [0xcf, 0x0d, 0x57, 0xa2, 0xf9, 0xa2, 0xf9];
let salt: [u8; 16] = [
0x87, 0x7a, 0x0e, 0x60, 0x05, 0x74, 0xc9, 0x03, 0xbe, 0xc9, 0x92, 0xba, 0x50, 0x8a,
0x61, 0xdc,
];
let expected_okm: [u8; 32] = [
0x32, 0x1c, 0x30, 0x53, 0x26, 0xd9, 0x14, 0x94, 0xb9, 0x81, 0x1f, 0x54, 0x33, 0xaa,
0xb2, 0xf8, 0x79, 0x44, 0xd5, 0x49, 0xa3, 0x18, 0xee, 0x1b, 0xdf, 0xc2, 0xcb, 0xe3,
0x19, 0xc5, 0x39, 0x85,
];
let key = generate_key(Some(&salt), ikm, Some(&info));
assert_eq!(key.0, expected_okm);
}
}