password_worker/hasher_impls/argon2id.rs
1use argon2::{Variant, Version};
2
3use crate::{Hasher, PasswordWorker, PasswordWorkerError};
4
5/// Use this type in the generic constructor to use argon2id
6///
7/// ```
8/// # fn get_rand() -> Vec<u8> { vec![1, 2, 3, 4, 5, 6, 7, 8] }
9/// # #[tokio::main]
10/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
11/// use password_worker::{Argon2id, Argon2idConfig, PasswordWorker};
12///
13/// let password = "hunter2";
14/// let salt: Vec<u8> = get_rand(); // Min length 8 bytes
15/// let max_threads = 4;
16/// let password_worker = PasswordWorker::<Argon2id>::new(max_threads)?;
17/// // let password_worker = PasswordWorker::new_argon2id(max_threads)?;
18///
19/// let hashed_password = password_worker
20/// .hash(
21/// password,
22/// Argon2idConfig {
23/// salt,
24/// ..Default::default()
25/// },
26/// )
27/// .await?;
28/// println!("Hashed password: {:?}", hashed_password);
29///
30/// let is_valid = password_worker.verify(password, hashed_password).await?;
31/// println!("Verification result: {:?}", is_valid);
32/// # Ok(())
33/// # }
34/// ```
35#[derive(Clone, Copy, Debug)]
36pub enum Argon2id {}
37
38impl Hasher for Argon2id {
39 type Config = Argon2idConfig;
40 type Error = argon2::Error;
41
42 fn hash(data: impl AsRef<[u8]>, config: &Self::Config) -> Result<String, Self::Error> {
43 let mut argon_config = argon2::Config::default();
44
45 // Change defaults
46 argon_config.variant = Variant::Argon2id;
47 argon_config.version = Version::Version13;
48
49 argon_config.time_cost = config.time_cost;
50 argon_config.mem_cost = config.mem_cost;
51 argon_config.hash_length = config.hash_length;
52
53 argon2::hash_encoded(data.as_ref(), &config.salt, &argon_config)
54 }
55
56 fn verify(data: impl AsRef<[u8]>, hash: &str) -> Result<bool, Self::Error> {
57 argon2::verify_encoded(hash, data.as_ref())
58 }
59}
60
61/// The configuration attributes needed to perform argon2id hashing
62///
63/// This implements Default using the default values from the rust-argon2 crate
64/// with the salt being an empty String.
65///
66/// ```
67/// # fn get_rand() -> Vec<u8> { vec![1, 2, 3, 4, 5, 6, 7, 8] }
68/// # #[tokio::main]
69/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
70/// use password_worker::Argon2idConfig;
71///
72/// let salt: Vec<u8> = get_rand(); // Min length 8 bytes
73/// let config = Argon2idConfig {
74/// salt,
75/// ..Default::default()
76/// };
77/// # Ok(())
78/// # }
79/// ```
80#[derive(Clone)]
81pub struct Argon2idConfig {
82 /// The salt for the password hash (Minimum length 8 bytes)
83 pub salt: Vec<u8>,
84 /// The time cost (higher takes longer)
85 pub time_cost: u32,
86 /// Memory cost (higher takes longer)
87 pub mem_cost: u32,
88 /// Length of hash output
89 pub hash_length: u32,
90}
91
92impl Default for Argon2idConfig {
93 fn default() -> Self {
94 Self {
95 salt: Vec::new(),
96 time_cost: 3,
97 mem_cost: 4096,
98 hash_length: 32,
99 }
100 }
101}
102
103impl PasswordWorker<Argon2id> {
104 /// This constructor creates a new argon2id instance
105 pub fn new_argon2id(max_threads: usize) -> Result<Self, PasswordWorkerError<Argon2id>> {
106 PasswordWorker::<Argon2id>::new(max_threads)
107 }
108}