#![cfg(all(feature = "password-hash", hmac, kdf_pbkdf2))] mod common; use password_hash::phc::PasswordHash; use password_hash::{CustomizedPasswordHasher, PasswordHasher, PasswordVerifier}; use wolfssl_wolfcrypt::pbkdf2_password_hash::*; #[test] fn test_hash_and_verify() { common::setup(); let hasher = Pbkdf2 { algorithm: Algorithm::Pbkdf2Sha256, params: Params { rounds: 4096, output_len: 32, }, }; let salt = b"0123456789abcdef"; // 16 bytes let password = b"hunter2"; let hash = hasher .hash_password_with_salt(password, salt) .expect("hashing failed"); assert_eq!(hash.algorithm, Algorithm::Pbkdf2Sha256.ident()); assert!(hash.salt.is_some()); assert!(hash.hash.is_some()); assert_eq!(hash.hash.as_ref().unwrap().len(), 32); // Verify correct password succeeds hasher .verify_password(password, &hash) .expect("verification of correct password failed"); // Verify wrong password fails let result = hasher.verify_password(b"wrong_password", &hash); assert!(result.is_err()); } #[test] fn test_hash_roundtrip_phc_string() { common::setup(); let hasher = Pbkdf2 { algorithm: Algorithm::Pbkdf2Sha256, params: Params { rounds: 4096, output_len: 32, }, }; let salt = b"0123456789abcdef"; let password = b"password"; let hash = hasher .hash_password_with_salt(password, salt) .expect("hashing failed"); // Serialize to PHC string and parse back let phc_string = hash.to_string(); assert!(phc_string.starts_with("$pbkdf2-sha256$")); let parsed = PasswordHash::new(&phc_string).expect("parsing PHC string failed"); // Verify with the parsed hash hasher .verify_password(password, &parsed) .expect("verification of parsed hash failed"); } #[test] fn test_default_params() { common::setup(); let hasher = Pbkdf2::default(); assert_eq!(hasher.algorithm, Algorithm::Pbkdf2Sha256); assert_eq!(hasher.params.rounds, DEFAULT_ROUNDS); assert_eq!(hasher.params.output_len, DEFAULT_OUTPUT_LEN); } #[test] #[cfg(sha384)] fn test_sha384_algorithm() { common::setup(); let hasher = Pbkdf2 { algorithm: Algorithm::Pbkdf2Sha384, params: Params { rounds: 4096, output_len: 48, }, }; let salt = b"0123456789abcdef"; let password = b"password"; let hash = hasher .hash_password_with_salt(password, salt) .expect("hashing with SHA-384 failed"); assert_eq!(hash.algorithm, Algorithm::Pbkdf2Sha384.ident()); assert_eq!(hash.hash.as_ref().unwrap().len(), 48); hasher .verify_password(password, &hash) .expect("SHA-384 verification failed"); } #[test] #[cfg(sha512)] fn test_sha512_algorithm() { common::setup(); let hasher = Pbkdf2 { algorithm: Algorithm::Pbkdf2Sha512, params: Params { rounds: 4096, output_len: 64, }, }; let salt = b"0123456789abcdef"; let password = b"password"; let hash = hasher .hash_password_with_salt(password, salt) .expect("hashing with SHA-512 failed"); assert_eq!(hash.algorithm, Algorithm::Pbkdf2Sha512.ident()); assert_eq!(hash.hash.as_ref().unwrap().len(), 64); hasher .verify_password(password, &hash) .expect("SHA-512 verification failed"); } #[test] fn test_customized_hash() { common::setup(); let hasher = Pbkdf2::default(); let salt = b"0123456789abcdef"; let password = b"password"; let custom_params = Params { rounds: 8192, output_len: 48, }; let hash = hasher .hash_password_with_params(password, salt, custom_params) .expect("customized hashing failed"); assert_eq!(hash.hash.as_ref().unwrap().len(), 48); assert_eq!(hash.params.get_decimal("i"), Some(8192)); hasher .verify_password(password, &hash) .expect("customized hash verification failed"); } #[test] #[cfg(sha512)] fn test_customized_hash_with_algorithm_override() { common::setup(); let hasher = Pbkdf2::default(); let salt = b"0123456789abcdef"; let password = b"password"; let params = Params { rounds: 4096, output_len: 64, }; let hash = hasher .hash_password_customized(password, salt, Some("pbkdf2-sha512"), None, params) .expect("algorithm override failed"); assert_eq!(hash.algorithm, Algorithm::Pbkdf2Sha512.ident()); assert_eq!(hash.hash.as_ref().unwrap().len(), 64); // Verify with a Pbkdf2 instance using the matching algorithm let verifier = Pbkdf2 { algorithm: Algorithm::Pbkdf2Sha512, ..Pbkdf2::default() }; verifier .verify_password(password, &hash) .expect("verification with algorithm override failed"); } #[test] fn test_version_rejected() { common::setup(); let hasher = Pbkdf2::default(); let salt = b"0123456789abcdef"; let result = hasher.hash_password_customized(b"password", salt, None, Some(1), Params::default()); assert!(result.is_err()); } #[test] fn test_unknown_algorithm_rejected() { common::setup(); let hasher = Pbkdf2::default(); let salt = b"0123456789abcdef"; let result = hasher.hash_password_customized( b"password", salt, Some("argon2id"), None, Params::default(), ); assert!(result.is_err()); } #[test] fn test_deterministic_output() { common::setup(); let hasher = Pbkdf2 { algorithm: Algorithm::Pbkdf2Sha256, params: Params { rounds: 4096, output_len: 32, }, }; let salt = b"0123456789abcdef"; let password = b"password"; let hash1 = hasher .hash_password_with_salt(password, salt) .expect("first hash failed"); let hash2 = hasher .hash_password_with_salt(password, salt) .expect("second hash failed"); assert_eq!(hash1.hash, hash2.hash); } #[test] fn test_different_salts_produce_different_hashes() { common::setup(); let hasher = Pbkdf2 { algorithm: Algorithm::Pbkdf2Sha256, params: Params { rounds: 4096, output_len: 32, }, }; let password = b"password"; let hash1 = hasher .hash_password_with_salt(password, b"salt_aaaaaaaaaa01") .expect("first hash failed"); let hash2 = hasher .hash_password_with_salt(password, b"salt_aaaaaaaaaa02") .expect("second hash failed"); assert_ne!(hash1.hash, hash2.hash); }