pub use self::native::Argon2;
mod native {
extern crate argon2rs;
use primitives::Primitive;
use sod::Sod;
use serde_mcf::Hashes;
use std::fmt;
pub struct Argon2 {
algorithm: argon2rs::Argon2,
}
impl ::primitives::PrimitiveImpl for Argon2 {
fn compute<'a>(&'a self, password: &[u8], salt: &[u8]) -> Vec<u8> {
let mut hash = [0_u8; 32];
self.algorithm.hash(&mut hash, password, salt, &[], &[]);
hash.to_vec()
}
fn params_as_vec(&self) -> Vec<(&'static str, String)> {
let (_, kib, passes, lanes) = self.algorithm.params();
vec![
("m", kib.to_string()),
("t", passes.to_string()),
("p", lanes.to_string()),
]
}
fn hash_id(&self) -> Hashes {
Hashes::Argon2i
}
}
lazy_static! {
pub static ref DEFAULT: Argon2 = {
Argon2 {
algorithm: argon2rs::Argon2::default(argon2rs::Variant::Argon2i),
}
};
}
impl Argon2 {
pub fn default() -> Primitive {
Primitive(Sod::Static(&*DEFAULT))
}
fn new_impl(passes: u32, lanes: u32, kib: u32) -> Self {
Self {
algorithm: argon2rs::Argon2::new(passes, lanes, kib, argon2rs::Variant::Argon2i)
.expect("invalid Argon2 parameters"),
}
}
#[allow(clippy::new_ret_no_self)]
pub fn new(passes: u32, lanes: u32, kib: u32) -> Primitive {
Self::new_impl(passes, lanes, kib).into()
}
}
impl fmt::Debug for Argon2 {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Argon2i: {:?}", self.algorithm.params())
}
}
}
benches!(Argon2);
#[cfg(test)]
mod test {
use super::*;
use data_encoding::HEXLOWER;
use hashing::*;
use serde_mcf;
#[test]
fn sanity_check() {
let password = "hunter2";
let params = super::Argon2::default();
println!("{:?}", params);
let salt = ::get_salt();
let hash = params.compute(password.as_bytes(), &salt);
let hash2 = params.compute(password.as_bytes(), &salt);
assert_eq!(hash, hash2);
let out = Output {
alg: Algorithm::Single(params),
salt,
hash,
};
println!("{:?}", serde_mcf::to_string(&out).unwrap());
}
fn hashtest(
passes: u32,
m: u32,
lanes: u32,
password: &str,
salt: &str,
hexpected: &str,
encoded: &str,
) {
let alg = Argon2::new(passes, lanes, 1 << m);
let hash = alg.compute(password.as_bytes(), salt.as_bytes());
assert_eq!(HEXLOWER.encode(&hash), hexpected);
assert_eq!(serde_mcf::from_str::<Output>(encoded).unwrap().hash, hash);
let output = Output {
alg: Algorithm::Single(alg),
hash,
salt: salt.as_bytes().to_vec(),
};
assert_eq!(&serde_mcf::to_string(&output).unwrap()[1..], encoded);
}
#[test]
fn argon2i_ref_tests() {
hashtest(
2,
8,
1,
"password",
"somesalt",
"fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06",
"$argon2i$m=256,t=2,p=1$c29tZXNhbHQ\
$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY",
);
hashtest(
2,
8,
2,
"password",
"somesalt",
"b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb",
"$argon2i$m=256,t=2,p=2$c29tZXNhbHQ\
$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs",
);
hashtest(
1,
16,
1,
"password",
"somesalt",
"81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2",
"$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ\
$gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI",
);
hashtest(
4,
16,
1,
"password",
"somesalt",
"f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b",
"$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ\
$8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs",
);
hashtest(
2,
16,
1,
"differentpassword",
"somesalt",
"e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3",
"$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ\
$6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM",
);
hashtest(
2,
16,
1,
"password",
"diffsalt",
"79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497",
"$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ\
$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc",
);
}
#[test]
#[cfg(feature = "long_tests")]
fn argon2i_ref_tests_long() {
hashtest(
2,
18,
1,
"password",
"somesalt",
"3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467",
"$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ\
$Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc",
);
}
}