mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 19:30:48 +02:00
165 lines
4.6 KiB
Rust
165 lines
4.6 KiB
Rust
#![cfg(all(feature = "password-hash", kdf_scrypt))]
|
|
|
|
mod common;
|
|
|
|
use password_hash::phc::PasswordHash;
|
|
use password_hash::{CustomizedPasswordHasher, PasswordHasher, PasswordVerifier};
|
|
use wolfssl_wolfcrypt::scrypt_password_hash::*;
|
|
|
|
/// Use modest scrypt parameters in tests to keep them fast while still
|
|
/// exercising the full code path.
|
|
fn test_params() -> Params {
|
|
Params { log_n: 10, r: 8, p: 1, output_len: 32 }
|
|
}
|
|
|
|
#[test]
|
|
fn test_hash_and_verify() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt { params: test_params() };
|
|
let salt = b"0123456789abcdef";
|
|
let password = b"hunter2";
|
|
|
|
let hash = hasher
|
|
.hash_password_with_salt(password, salt)
|
|
.expect("hashing failed");
|
|
|
|
assert!(hash.salt.is_some());
|
|
assert!(hash.hash.is_some());
|
|
assert_eq!(hash.hash.as_ref().unwrap().len(), 32);
|
|
|
|
hasher
|
|
.verify_password(password, &hash)
|
|
.expect("verification of correct password failed");
|
|
|
|
assert!(hasher.verify_password(b"wrong_password", &hash).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_hash_roundtrip_phc_string() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt { params: test_params() };
|
|
let salt = b"0123456789abcdef";
|
|
let password = b"password";
|
|
|
|
let hash = hasher
|
|
.hash_password_with_salt(password, salt)
|
|
.expect("hashing failed");
|
|
|
|
let phc_string = hash.to_string();
|
|
assert!(phc_string.starts_with("$scrypt$"));
|
|
assert!(phc_string.contains("ln=10"));
|
|
assert!(phc_string.contains("r=8"));
|
|
assert!(phc_string.contains("p=1"));
|
|
|
|
let parsed = PasswordHash::new(&phc_string).expect("parsing PHC string failed");
|
|
|
|
hasher
|
|
.verify_password(password, &parsed)
|
|
.expect("verification of parsed hash failed");
|
|
}
|
|
|
|
#[test]
|
|
fn test_default_params() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt::default();
|
|
assert_eq!(hasher.params.log_n, RECOMMENDED_LOG_N);
|
|
assert_eq!(hasher.params.r, RECOMMENDED_R);
|
|
assert_eq!(hasher.params.p, RECOMMENDED_P);
|
|
assert_eq!(hasher.params.output_len, DEFAULT_OUTPUT_LEN);
|
|
}
|
|
|
|
#[test]
|
|
fn test_customized_hash() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt::default();
|
|
let salt = b"0123456789abcdef";
|
|
let password = b"password";
|
|
let custom = Params { log_n: 11, r: 8, p: 2, output_len: 48 };
|
|
|
|
let hash = hasher
|
|
.hash_password_with_params(password, salt, custom)
|
|
.expect("customized hashing failed");
|
|
|
|
assert_eq!(hash.hash.as_ref().unwrap().len(), 48);
|
|
assert_eq!(hash.params.get_decimal("ln"), Some(11));
|
|
assert_eq!(hash.params.get_decimal("r"), Some(8));
|
|
assert_eq!(hash.params.get_decimal("p"), Some(2));
|
|
|
|
hasher
|
|
.verify_password(password, &hash)
|
|
.expect("customized hash verification failed");
|
|
}
|
|
|
|
#[test]
|
|
fn test_version_rejected() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt { params: test_params() };
|
|
let salt = b"0123456789abcdef";
|
|
|
|
let result = hasher.hash_password_customized(
|
|
b"password", salt, None, Some(1), test_params());
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_unknown_algorithm_rejected() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt { params: test_params() };
|
|
let salt = b"0123456789abcdef";
|
|
|
|
let result = hasher.hash_password_customized(
|
|
b"password", salt, Some("argon2id"), None, test_params());
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_invalid_params_rejected() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt { params: test_params() };
|
|
let salt = b"0123456789abcdef";
|
|
|
|
// r out of range
|
|
let bad = Params { log_n: 10, r: 9, p: 1, output_len: 32 };
|
|
assert!(hasher.hash_password_with_params(b"pw", salt, bad).is_err());
|
|
|
|
// p must be > 0
|
|
let bad = Params { log_n: 10, r: 8, p: 0, output_len: 32 };
|
|
assert!(hasher.hash_password_with_params(b"pw", salt, bad).is_err());
|
|
|
|
// log_n must be > 0
|
|
let bad = Params { log_n: 0, r: 8, p: 1, output_len: 32 };
|
|
assert!(hasher.hash_password_with_params(b"pw", salt, bad).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_deterministic_output() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt { params: test_params() };
|
|
let salt = b"0123456789abcdef";
|
|
let password = b"password";
|
|
|
|
let h1 = hasher.hash_password_with_salt(password, salt).unwrap();
|
|
let h2 = hasher.hash_password_with_salt(password, salt).unwrap();
|
|
assert_eq!(h1.hash, h2.hash);
|
|
}
|
|
|
|
#[test]
|
|
fn test_different_salts_produce_different_hashes() {
|
|
common::setup();
|
|
|
|
let hasher = Scrypt { params: test_params() };
|
|
let password = b"password";
|
|
|
|
let h1 = hasher.hash_password_with_salt(password, b"salt_aaaaaaaaaa01").unwrap();
|
|
let h2 = hasher.hash_password_with_salt(password, b"salt_aaaaaaaaaa02").unwrap();
|
|
assert_ne!(h1.hash, h2.hash);
|
|
}
|