use crate::error::{Error, Result};
use hkdf::Hkdf;
use sha3::Sha3_256;
pub fn hkdf_sha3_256(salt: &[u8], ikm: &[u8], info: &[u8], out: &mut [u8]) -> Result<()> {
if out.is_empty() {
return Err(Error::InvalidLength {
expected: 1,
got: 0,
});
}
if out.len() > 255 * 32 {
return Err(Error::InvalidLength {
expected: 255 * 32,
got: out.len(),
});
}
let hk = Hkdf::<Sha3_256>::new(Some(salt), ikm);
hk.expand(info, out)
.expect("HKDF output length already validated");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn case1() {
let ikm = [0x0b; 22];
let salt = hex!("000102030405060708090a0b0c");
let info = hex!("f0f1f2f3f4f5f6f7f8f9");
let expected = hex!(
"0c5160501d65021deaf2c14f5abce04c"
"5bd2635abceeba61c2edb6e8ed726749"
"00557728f2c9f2c4c179"
);
let mut out = [0u8; 42];
hkdf_sha3_256(&salt, &ikm, &info, &mut out).unwrap();
assert_eq!(out, expected);
}
#[test]
fn case2() {
let ikm: Vec<u8> = (0x00..=0x4f).collect();
let salt: Vec<u8> = (0x60..=0xaf).collect();
let info: Vec<u8> = (0xb0..=0xff).collect();
let expected = hex!(
"3dc251e66c75da6560405ec5ac10e17d"
"851eedfbfdc13feafbec16964c25d021"
"bd971465a3e9c615f27769019e3f0407"
"d84986fb0ba24e729c99834624baa21c"
"b623dc0098f430d52e18bbdf694df4ed"
"d8b2"
);
let mut out = [0u8; 82];
hkdf_sha3_256(&salt, &ikm, &info, &mut out).unwrap();
assert_eq!(out, expected);
}
#[test]
fn case3() {
let ikm = [0x0b; 22];
let salt = b"";
let info = b"";
let expected = hex!(
"bc1342cdd75c05e8b0c3ae609ce44106"
"84d197232875073499b30cdfe2de2853"
"c1c1bed63d725e885e78"
);
let mut out = [0u8; 42];
hkdf_sha3_256(salt, &ikm, info, &mut out).unwrap();
assert_eq!(out, expected);
}
#[test]
fn output_32_bytes() {
let mut out = [0u8; 32];
hkdf_sha3_256(b"salt", b"ikm", b"info", &mut out).unwrap();
assert!(out.iter().any(|&b| b != 0));
}
#[test]
fn output_64_bytes() {
let mut out = [0u8; 64];
hkdf_sha3_256(b"salt", b"ikm", b"info", &mut out).unwrap();
assert!(out.iter().any(|&b| b != 0));
}
#[test]
fn output_1_byte() {
let mut out = [0u8; 1];
hkdf_sha3_256(b"salt", b"ikm", b"info", &mut out).unwrap();
assert_ne!(out[0], 0u8);
}
#[test]
fn max_output() {
let mut out = vec![0u8; 255 * 32];
hkdf_sha3_256(b"salt", b"ikm", b"info", &mut out).unwrap();
assert!(out.iter().any(|&b| b != 0));
}
#[test]
fn max_output_kat() {
let salt = [0u8; 32];
let ikm = b"test input keying material";
let info = b"test info";
let mut out = vec![0u8; 8160];
hkdf_sha3_256(&salt, ikm, info, &mut out).unwrap();
assert_eq!(
&out[..32],
&hex_literal::hex!("fe631a871e206c76b2328b44340b951ec80635132cef2b633d9fffbed3b03af6")
);
assert_eq!(
&out[8128..],
&hex_literal::hex!("8e358e5b1b40fcdeb1a51bda1f65c3d76908111a55738dd5d5e6991541aa8b4c")
);
}
#[test]
fn empty_output_returns_error() {
let mut out: [u8; 0] = [];
assert!(hkdf_sha3_256(b"salt", b"ikm", b"info", &mut out).is_err());
}
#[test]
fn oversized_output_returns_error() {
let mut out = vec![0u8; 255 * 32 + 1];
assert!(hkdf_sha3_256(b"salt", b"ikm", b"info", &mut out).is_err());
}
}