50 lines
1.4 KiB
Rust
50 lines
1.4 KiB
Rust
use std::string::String;
|
|
|
|
use argon2::{
|
|
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
|
Argon2,
|
|
};
|
|
|
|
pub fn hash(password: &str) -> Result<String, Box<dyn std::error::Error>> {
|
|
let salt = SaltString::generate(&mut OsRng);
|
|
let argon2 = Argon2::default();
|
|
argon2
|
|
.hash_password(password.as_bytes(), &salt)
|
|
.map(|h| h.to_string())
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
pub fn verify_password(
|
|
password: &str,
|
|
hashed_password: &str,
|
|
) -> Result<bool, Box<dyn std::error::Error>> {
|
|
let argon2 = Argon2::default();
|
|
let parsed_hash = PasswordHash::new(hashed_password)?;
|
|
Ok(argon2
|
|
.verify_password(password.as_bytes(), &parsed_hash)
|
|
.is_ok())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn simple_case() -> Result<(), Box<dyn std::error::Error>> {
|
|
let password = "12345";
|
|
let hash = hash(password)?;
|
|
println!("hash: {}", &hash);
|
|
assert!(verify_password(password, &hash)?);
|
|
assert!(!verify_password("54321", &hash)?);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn password_with_special_characters() -> Result<(), Box<dyn std::error::Error>> {
|
|
let password = "éà ä_\\😺🎮🇨🇭";
|
|
let hash = hash(password)?;
|
|
println!("hash: {}", &hash);
|
|
assert!(verify_password(password, &hash)?);
|
|
Ok(())
|
|
}
|
|
}
|