#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
pub use super::hltypes::{Password, Salt, SecretKey};
pub use crate::hazardous::kdf::argon2::CostParams;
pub use crate::pwhash::OWASP_ARGON2ID_1ST;
pub use crate::pwhash::OWASP_ARGON2ID_2ND;
use crate::{errors::UnknownCryptoError, hazardous::kdf::argon2};
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn derive_key(
password: &Password,
salt: &Salt,
cost: &CostParams,
length: u32,
) -> Result<SecretKey, UnknownCryptoError> {
if salt.len() < 8 {
return Err(UnknownCryptoError);
}
let mut dk = SecretKey::try_from(&vec![0u8; length as usize])?;
argon2::Argon2::<argon2::ID, argon2::Sequential>::derive_key(
password.unprotected_as_ref(),
salt.as_ref(),
cost,
None,
None,
dk.data.as_mut(),
)?;
Ok(dk)
}
#[cfg(test)]
mod public {
use super::*;
mod test_derive_key_and_verify {
use super::*;
#[test]
fn test_derive_key() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let salt = Salt::try_from([0u8; 16].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
let dk_first = derive_key(&password, &salt, &cost, 32).unwrap();
let dk_second = derive_key(&password, &salt, &cost, 32).unwrap();
assert_eq!(dk_first, dk_second);
}
#[test]
fn test_derive_key_err_diff_iter() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let salt = Salt::try_from([0u8; 64].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
let dk = derive_key(&password, &salt, &cost, 32).unwrap();
let dk_diff_iter =
derive_key(&password, &salt, &CostParams::new(4, 1024, 1).unwrap(), 32).unwrap();
assert_ne!(dk, dk_diff_iter);
}
#[test]
fn test_derive_key_err_diff_mem() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let salt = Salt::try_from([0u8; 64].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
let dk = derive_key(&password, &salt, &cost, 32).unwrap();
let dk_diff_mem =
derive_key(&password, &salt, &CostParams::new(4, 512, 1).unwrap(), 32).unwrap();
assert_ne!(dk, dk_diff_mem);
}
#[test]
fn test_derive_key_err_diff_salt() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let salt = Salt::try_from([0u8; 64].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
let dk = derive_key(&password, &salt, &cost, 32).unwrap();
let dk_diff_salt = derive_key(
&password,
&Salt::try_from([1u8; 64].as_slice()).unwrap(),
&cost,
32,
)
.unwrap();
assert_ne!(dk, dk_diff_salt);
}
#[test]
fn test_derive_key_err_diff_len() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let salt = Salt::try_from([0u8; 64].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
let dk = derive_key(&password, &salt, &cost, 32).unwrap();
let dk_diff_len = derive_key(&password, &salt, &cost, 64).unwrap();
assert_ne!(dk, dk_diff_len);
}
#[test]
fn test_derive_key_err_diff_pass() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let salt = Salt::try_from([0u8; 64].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
let dk = derive_key(&password, &salt, &cost, 32).unwrap();
let dk_diff_pass = derive_key(
&Password::try_from([1u8; 64].as_slice()).unwrap(),
&salt,
&cost,
32,
)
.unwrap();
assert_ne!(dk, dk_diff_pass);
}
#[test]
fn test_derive_key_bad_length() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let salt = Salt::try_from([0u8; 64].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
assert!(derive_key(&password, &salt, &cost, 3).is_err());
assert!(derive_key(&password, &salt, &cost, 4).is_ok());
assert!(derive_key(&password, &salt, &cost, 5).is_ok());
}
#[test]
fn test_derive_salt_bad_length() {
let password = Password::try_from([0u8; 64].as_slice()).unwrap();
let cost: CostParams = CostParams::new(3, 1024, 1).unwrap();
assert!(
derive_key(
&password,
&Salt::try_from([0].as_slice()).unwrap(),
&cost,
3
)
.is_err()
);
assert!(
derive_key(
&password,
&Salt::try_from([0u8; 1].as_slice()).unwrap(),
&cost,
4
)
.is_err()
);
assert!(
derive_key(
&password,
&Salt::try_from([0u8; 8].as_slice()).unwrap(),
&cost,
5
)
.is_ok()
);
}
}
}