Argon2 Password Hash Verify
Hash passwords with argon2id at tuned cost parameters, verifying in constant time with encoded salt and version metadata.
Code
use argon2::password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString};
use argon2::{Algorithm, Argon2, Params, Version};
use rand_core::OsRng;
fn tuned_argon2() -> Argon2<'static> {
let params = Params::new(
19_456, // 19 MiB 内存成本
2, // 时间成本(迭代次数)
1, // 并行度
None,
)
.expect("valid parameters");
Argon2::new(Algorithm::Argon2id, Version::V0x13, params)
}
fn hash_password(plain: &str) -> Result<String, String> {
let salt = SaltString::generate(&mut OsRng);
tuned_argon2()
.hash_password(plain.as_bytes(), &salt)
.map(|hash| hash.to_string())
.map_err(|err| format!("hash failed: {err}"))
}
fn verify_password(plain: &str, stored: &str) -> bool {
let parsed = match PasswordHash::new(stored) {
Ok(hash) => hash,
Err(_) => return false, // 存储格式损坏视为验证失败
};
tuned_argon2()
.verify_password(plain.as_bytes(), &parsed)
.is_ok()
}
fn main() {
let stored = hash_password("correct horse battery staple").unwrap();
println!("format prefix: {}", &stored[..stored.find('$').unwrap()]);
println!("wrong rejected: {}", !verify_password("wrong", &stored));
println!("right accepted: {}", verify_password("correct horse battery staple", &stored));
// 不同盐产出不同密文:同密码两次哈希不相等
let again = hash_password("correct horse battery staple").unwrap();
println!("salts differ: {}", stored != again);
}Report a problem with this exampleOpens a pre-filled issue on GitHub.