use argon2::{self, Config, ThreadMode, Variant, Version};
use rand::Rng;
pub enum HashStrength {
Basic,
Extra,
Secret,
Extreme
}
pub fn hash_password(password: &str, strength: HashStrength) -> String {
let mem = match strength {
HashStrength::Basic => 0x100_000, HashStrength::Extra => 0x200_000, HashStrength::Secret => 0x400_000, HashStrength::Extreme => 0x800_000 };
let config = Config {
variant: Variant::Argon2id,
version: Version::Version13,
mem_cost: mem,
time_cost: 1,
thread_mode: ThreadMode::Parallel,
lanes: 2,
secret: &[],
ad: &[],
hash_length: 32
};
let salt = rand::thread_rng().gen::<[u8; 16]>();
let hash = argon2::hash_encoded(password.as_bytes(), &salt, &config).unwrap();
hash
}
pub fn hash_password_enhanced(password: &str, memcost: u32, timecost: u32, threads: u32) -> String {
let config = Config {
variant: Variant::Argon2id,
version: Version::Version13,
mem_cost: memcost,
time_cost: timecost,
thread_mode: ThreadMode::Parallel,
lanes: threads,
secret: &[],
ad: &[],
hash_length: 32
};
let salt = rand::thread_rng().gen::<[u8; 16]>();
let hash = argon2::hash_encoded(password.as_bytes(), &salt, &config).unwrap();
hash
}
pub fn check_password(password: &str, hash: &str) -> Result<bool, argon2::Error> {
argon2::verify_encoded(&hash, password.as_bytes())
}
#[cfg(test)]
mod tests {
#[test]
fn pw_check_hash() {
let password = "MyS3cretPassw*rd";
let pwhash = crate::hash_password(password, crate::HashStrength::Basic);
match crate::check_password(password, &pwhash) {
Ok(v) => assert!(v),
Err(e) => panic!("{}",e)
}
let pwhash = crate::hash_password_enhanced(password, 65536, 1, 4);
match crate::check_password(password, &pwhash) {
Ok(v) => assert!(v),
Err(e) => panic!("{}", e)
}
}
}