use std::fmt;
pub struct Prk(ring::hkdf::Prk);
impl Prk {
pub const MAX_OUT_LEN: usize = 255 * 32;
pub fn extract(salt: &[u8], ikm: &[u8]) -> Self {
let salt = ring::hkdf::Salt::new(ring::hkdf::HKDF_SHA256, salt);
Self(salt.extract(ikm))
}
pub fn expand(&self, info: &[&[u8]], out: &mut [u8]) {
struct OkmLength(usize);
impl ring::hkdf::KeyType for OkmLength {
fn len(&self) -> usize {
self.0
}
}
assert!(out.len() <= Self::MAX_OUT_LEN);
self.0
.expand(info, OkmLength(out.len()))
.expect("Output length is checked above")
.fill(out)
.expect("Output length matches")
}
}
impl fmt::Debug for Prk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Prk(..)")
}
}
#[cfg(test)]
mod test {
use lexe_hex::hex;
use super::*;
#[test]
fn rfc5869_test_case_1() {
let ikm = [0x0b; 22];
let salt = hex::decode("000102030405060708090a0b0c").unwrap();
let info = hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap();
let mut okm = [0u8; 42];
Prk::extract(&salt, &ikm).expand(&[&info[..5], &info[5..]], &mut okm);
assert_eq!(
hex::encode(&okm),
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db0\
2d56ecc4c5bf34007208d5b887185865",
);
}
}