use std::string::String; use argon2::{ password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, Argon2, }; fn get_argon2<'k>() -> Argon2<'k> { Argon2::new( argon2::Algorithm::Argon2id, argon2::Version::V0x13, argon2::Params::new( 4_096, // 4 MB. The code run on raspberry pi zero, the default memory is too high. 4, // Number of iteration. 2, // Degree of parallelism. None, ) .unwrap(), ) } pub fn hash(password: &str) -> Result> { let salt = SaltString::generate(&mut OsRng); let argon2 = get_argon2(); 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> { let argon2 = get_argon2(); 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> { 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> { let password = "éà ä_\\😺🎮🇨🇭"; let hash = hash(password)?; println!("hash: {}", &hash); assert!(verify_password(password, &hash)?); Ok(()) } }