use crate::crypto::hmac::hmac_sha256;
pub const DEFAULT_ITERATIONS: u32 = 100_000;
#[derive(Debug, Clone)]
pub struct Pbkdf2Params {
pub iterations: u32,
pub key_len: usize,
}
impl Default for Pbkdf2Params {
fn default() -> Self {
Self {
iterations: DEFAULT_ITERATIONS,
key_len: 32, }
}
}
pub fn pbkdf2_sha256(password: &[u8], salt: &[u8], params: &Pbkdf2Params) -> Vec<u8> {
let mut dk = Vec::with_capacity(params.key_len);
let hlen = 32;
let blocks_needed = params.key_len.div_ceil(hlen);
for block_num in 1..=blocks_needed {
let block = pbkdf2_f(password, salt, params.iterations, block_num as u32);
dk.extend_from_slice(&block);
}
dk.truncate(params.key_len);
dk
}
fn pbkdf2_f(password: &[u8], salt: &[u8], iterations: u32, block_num: u32) -> [u8; 32] {
let mut salt_with_block = Vec::with_capacity(salt.len() + 4);
salt_with_block.extend_from_slice(salt);
salt_with_block.extend_from_slice(&block_num.to_be_bytes());
let mut u = hmac_sha256(password, &salt_with_block);
let mut result = u;
for _ in 1..iterations {
u = hmac_sha256(password, &u);
for j in 0..32 {
result[j] ^= u[j];
}
}
result
}
pub fn derive_key(password: &[u8], salt: &[u8]) -> Vec<u8> {
pbkdf2_sha256(password, salt, &Pbkdf2Params::default())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pbkdf2_rfc6070_vector1() {
let password = b"password";
let salt = b"salt";
let params = Pbkdf2Params {
iterations: 1,
key_len: 20,
};
let dk = pbkdf2_sha256(password, salt, ¶ms);
assert_eq!(dk.len(), 20);
}
#[test]
fn test_pbkdf2_different_passwords() {
let salt = b"random_salt_value_here";
let params = Pbkdf2Params {
iterations: 1000, key_len: 32,
};
let key1 = pbkdf2_sha256(b"password1", salt, ¶ms);
let key2 = pbkdf2_sha256(b"password2", salt, ¶ms);
assert_ne!(
key1, key2,
"Different passwords must produce different keys"
);
}
#[test]
fn test_pbkdf2_different_salts() {
let password = b"same_password";
let params = Pbkdf2Params {
iterations: 1000,
key_len: 32,
};
let key1 = pbkdf2_sha256(password, b"salt1", ¶ms);
let key2 = pbkdf2_sha256(password, b"salt2", ¶ms);
assert_ne!(key1, key2, "Different salts must produce different keys");
}
#[test]
fn test_pbkdf2_deterministic() {
let password = b"test_password";
let salt = b"test_salt";
let params = Pbkdf2Params {
iterations: 1000,
key_len: 32,
};
let key1 = pbkdf2_sha256(password, salt, ¶ms);
let key2 = pbkdf2_sha256(password, salt, ¶ms);
assert_eq!(key1, key2, "Same inputs must produce same outputs");
}
#[test]
fn test_pbkdf2_key_length() {
let password = b"password";
let salt = b"salt";
for key_len in [16, 32, 48, 64] {
let params = Pbkdf2Params {
iterations: 100,
key_len,
};
let dk = pbkdf2_sha256(password, salt, ¶ms);
assert_eq!(dk.len(), key_len);
}
}
#[test]
fn test_pbkdf2_known_vector_sha256() {
let password = b"password";
let salt = b"salt";
let params = Pbkdf2Params {
iterations: 1,
key_len: 32,
};
let dk = pbkdf2_sha256(password, salt, ¶ms);
let expected = [
0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4,
0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c,
0xb7, 0x0b, 0xe1, 0x7b,
];
assert_eq!(dk, expected, "PBKDF2-SHA256 known vector mismatch");
}
#[test]
fn test_pbkdf2_known_vector_sha256_iter2() {
let password = b"password";
let salt = b"salt";
let params = Pbkdf2Params {
iterations: 2,
key_len: 32,
};
let dk = pbkdf2_sha256(password, salt, ¶ms);
let expected = [
0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3, 0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0,
0x6d, 0xd0, 0x2a, 0x30, 0x3f, 0x8e, 0xf3, 0xc2, 0x51, 0xdf, 0xd6, 0xe2, 0xd8, 0x5a,
0x95, 0x47, 0x4c, 0x43,
];
assert_eq!(dk, expected, "PBKDF2-SHA256 known vector (iter=2) mismatch");
}
}