use crate::error::*;
use nss::pbkdf2::pbkdf2_key_derive;
pub use nss::pbkdf2::HashAlgorithm;
pub fn derive(
passphrase: &[u8],
salt: &[u8],
iterations: u32,
hash_algorithm: HashAlgorithm,
out: &mut [u8],
) -> Result<()> {
pbkdf2_key_derive(passphrase, salt, iterations, hash_algorithm, out)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_correct_out() {
let expected = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b";
let mut out = vec![0u8; 32];
let password = b"password";
let salt = b"salt";
derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_longer_key() {
let expected = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b4dbf3a2f3dad3377264bb7b8e8330d4efc7451418617dabef683735361cdc18c";
let password = b"password";
let salt = b"salt";
let mut out = vec![0u8; 64];
derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_more_iterations() {
let expected = "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43";
let password = b"password";
let salt = b"salt";
let mut out = vec![0u8; 32];
derive(password, salt, 2, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_odd_length() {
let expected = "ad35240ac683febfaf3cd49d845473fbbbaa2437f5f82d5a415ae00ac76c6bfccf";
let password = b"password";
let salt = b"salt";
let mut out = vec![0u8; 33];
derive(password, salt, 3, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_nulls() {
let expected = "e25d526987819f966e324faa4a";
let password = b"passw\x00rd";
let salt = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
let mut out = vec![0u8; 13];
derive(password, salt, 5, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_password_null() {
let expected = "62384466264daadc4144018c6bd864648272b34da8980d31521ffcce92ae003b";
let password = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
let salt = b"salt";
let mut out = vec![0u8; 32];
derive(password, salt, 2, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_empty_password() {
let expected = "f135c27993baf98773c5cdb40a5706ce6a345cde61b000a67858650cd6a324d7";
let mut out = vec![0u8; 32];
let password = b"";
let salt = b"salt";
derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_empty_salt() {
let expected = "c1232f10f62715fda06ae7c0a2037ca19b33cf103b727ba56d870c11f290a2ab";
let mut out = vec![0u8; 32];
let password = b"password";
let salt = b"";
derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_tiny_out() {
let expected = "12";
let mut out = vec![0u8; 1];
let password = b"password";
let salt = b"salt";
derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).unwrap();
assert_eq!(expected, hex::encode(out));
}
#[test]
fn test_rejects_zero_iterations() {
let mut out = vec![0u8; 32];
let password = b"password";
let salt = b"salt";
assert!(derive(password, salt, 0, HashAlgorithm::SHA256, &mut out).is_err());
}
#[test]
fn test_rejects_empty_out() {
let mut out = vec![0u8; 0];
let password = b"password";
let salt = b"salt";
assert!(derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
}
#[test]
fn test_rejects_gaigantic_salt() {
if (u32::MAX as usize) < usize::MAX {
let salt = vec![0; (u32::MAX as usize) + 1];
let mut out = vec![0u8; 1];
let password = b"password";
assert!(derive(password, &salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
}
}
#[test]
fn test_rejects_gaigantic_password() {
if (u32::MAX as usize) < usize::MAX {
let password = vec![0; (u32::MAX as usize) + 1];
let mut out = vec![0u8; 1];
let salt = b"salt";
assert!(derive(&password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
}
}
#[test]
fn test_rejects_gaigantic_out() {
if (u32::MAX as usize) < usize::MAX {
let password = b"password";
let mut out = vec![0; (u32::MAX as usize) + 1];
let salt = b"salt";
assert!(derive(password, salt, 1, HashAlgorithm::SHA256, &mut out).is_err());
}
}
#[test]
fn test_rejects_gaigantic_iterations() {
let password = b"password";
let mut out = vec![0; 32];
let salt = b"salt";
assert!(derive(password, salt, u32::MAX, HashAlgorithm::SHA256, &mut out).is_err());
}
}