use crate::hmac::hmac_sha256;
use crate::sha256::OUT_LEN;
pub fn pbkdf2_sha256_32(password: &[u8], salt: &[u8], iterations: u32) -> [u8; OUT_LEN] {
let mut salt_with_index = alloc::vec::Vec::with_capacity(salt.len() + 4);
salt_with_index.extend_from_slice(salt);
salt_with_index.extend_from_slice(&1u32.to_be_bytes());
let mut u = hmac_sha256(password, &salt_with_index);
let mut out = u;
for _ in 1..iterations {
u = hmac_sha256(password, &u);
for i in 0..OUT_LEN {
out[i] ^= u[i];
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
fn hex(b: &[u8]) -> alloc::string::String {
use alloc::string::String;
use core::fmt::Write;
let mut s = String::with_capacity(b.len() * 2);
for x in b {
let _ = write!(s, "{x:02x}");
}
s
}
#[test]
fn rfc7914_case_1iter() {
let out = pbkdf2_sha256_32(b"passwd", b"salt", 1);
assert_eq!(
hex(&out),
"55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc"
);
}
#[test]
fn standard_4096iter() {
let out = pbkdf2_sha256_32(b"password", b"salt", 4096);
assert_eq!(
hex(&out),
"c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"
);
}
}