1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
pub use argon2::{Algorithm, Version};
use super::KeyDerivation;
use crate::{
error::Error,
generic_array::typenum::{Unsigned, U16},
};
pub type SaltSize = U16;
pub const SALT_LENGTH: usize = SaltSize::USIZE;
pub const PARAMS_INTERACTIVE: Params = Params {
alg: Algorithm::Argon2i,
version: Version::V0x13,
mem_cost: 32768,
time_cost: 4,
};
pub const PARAMS_MODERATE: Params = Params {
alg: Algorithm::Argon2i,
version: Version::V0x13,
mem_cost: 131072,
time_cost: 6,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Params {
alg: Algorithm,
version: Version,
mem_cost: u32,
time_cost: u32,
}
#[derive(Debug)]
pub struct Argon2<'a> {
password: &'a [u8],
salt: &'a [u8],
params: Params,
}
impl<'a> Argon2<'a> {
pub fn new(password: &'a [u8], salt: &'a [u8], params: Params) -> Result<Self, Error> {
if salt.len() < SALT_LENGTH {
return Err(err_msg!(Usage, "Invalid salt for argon2i hash"));
}
Ok(Self {
password,
salt,
params,
})
}
}
impl KeyDerivation for Argon2<'_> {
fn derive_key_bytes(&mut self, key_output: &mut [u8]) -> Result<(), Error> {
if key_output.len() > u32::MAX as usize {
return Err(err_msg!(
Usage,
"Output length exceeds max for argon2i hash"
));
}
let context = argon2::Argon2::new(
None,
self.params.time_cost,
self.params.mem_cost,
1,
self.params.version,
)
.map_err(|_| err_msg!(Unexpected, "Error creating hasher"))?;
context
.hash_password_into(self.params.alg, self.password, self.salt, &[], key_output)
.map_err(|_| err_msg!(Unexpected, "Error deriving key"))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expected() {
let pass = b"my password";
let salt = b"long enough salt";
let mut output = [0u8; 32];
Argon2::new(pass, salt, PARAMS_INTERACTIVE)
.unwrap()
.derive_key_bytes(&mut output)
.unwrap();
assert_eq!(
output,
hex!("9ef87bcf828c46c0136a0d1d9e391d713f75b327c6dc190455bd36c1bae33259")
);
}
}