use crate::hmac::HMac;
use crate::sha256::DIGEST_SIZE;
pub fn pbkdf2_sha256(password: &[u8], salt: &[u8], c: usize, out: &mut [u8]) {
let l: usize = (out.len() + DIGEST_SIZE - 1) / DIGEST_SIZE;
for i in 1..=l {
let ctr: [u8; 4] = [(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8];
let mut hmac = HMac::new(password);
hmac.update(salt);
hmac.update(&ctr);
let mut u = hmac.digest();
let mut t = u;
for _j in 2..=c {
let mut hmac = HMac::new(password);
hmac.update(&u);
u = hmac.digest();
for k in 0..u.len() {
t[k] ^= u[k];
}
}
let start = (i - 1) * DIGEST_SIZE;
let end = std::cmp::min(i * DIGEST_SIZE, out.len());
out[start..end].copy_from_slice(&t[..(end - start)]);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_should_compute_digest_for_vec0() {
let mut out: [u8; 64] = [0; 64];
pbkdf2_sha256(b"passwd", b"salt", 1, &mut out);
assert_eq!(
out.to_vec(),
vec![
0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f, 0xec, 0x16, 0x91, 0xc2, 0x25, 0x44,
0xb6, 0x05, 0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65, 0xe6, 0x8b, 0x9d, 0x57,
0xc2, 0x0d, 0xac, 0xbc, 0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45, 0x99, 0x16,
0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31, 0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5,
0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83,
]
);
}
#[test]
fn it_should_compute_digest_for_vec1() {
let mut out: [u8; 64] = [0; 64];
pbkdf2_sha256(b"Password", b"NaCl", 80000, &mut out);
assert_eq!(
out.to_vec(),
vec![
0x4d, 0xdc, 0xd8, 0xf6, 0x0b, 0x98, 0xbe, 0x21, 0x83, 0x0c, 0xee, 0x5e, 0xf2, 0x27,
0x01, 0xf9, 0x64, 0x1a, 0x44, 0x18, 0xd0, 0x4c, 0x04, 0x14, 0xae, 0xff, 0x08, 0x87,
0x6b, 0x34, 0xab, 0x56, 0xa1, 0xd4, 0x25, 0xa1, 0x22, 0x58, 0x33, 0x54, 0x9a, 0xdb,
0x84, 0x1b, 0x51, 0xc9, 0xb3, 0x17, 0x6a, 0x27, 0x2b, 0xde, 0xbb, 0xa1, 0xd0, 0x78,
0x47, 0x8f, 0x62, 0xb3, 0x97, 0xf3, 0x3c, 0x8d,
]
);
}
}