#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
pub use super::hltypes::{Password, Salt, SecretKey};
use crate::{errors::UnknownCryptoError, hazardous::kdf::argon2i, pwhash::MIN_ITERATIONS};
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn derive_key(
password: &Password,
salt: &Salt,
iterations: u32,
memory: u32,
length: u32,
) -> Result<SecretKey, UnknownCryptoError> {
if iterations < MIN_ITERATIONS {
return Err(UnknownCryptoError);
}
let mut dk = SecretKey::from_slice(&vec![0u8; length as usize])?;
argon2i::derive_key(
password.unprotected_as_bytes(),
salt.as_ref(),
iterations,
memory,
None,
None,
&mut dk.value,
)?;
Ok(dk)
}
#[cfg(test)]
mod public {
use super::*;
mod test_derive_key_and_verify {
use super::*;
#[test]
fn test_derive_key() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 16]).unwrap();
let dk_first = derive_key(&password, &salt, 3, 1024, 32).unwrap();
let dk_second = derive_key(&password, &salt, 3, 1024, 32).unwrap();
assert_eq!(dk_first, dk_second);
}
#[test]
fn test_derive_key_err_diff_iter() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 64]).unwrap();
let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
let dk_diff_iter = derive_key(&password, &salt, 4, 1024, 32).unwrap();
assert_ne!(dk, dk_diff_iter);
}
#[test]
fn test_derive_key_err_diff_mem() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 64]).unwrap();
let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
let dk_diff_mem = derive_key(&password, &salt, 3, 512, 32).unwrap();
assert_ne!(dk, dk_diff_mem);
}
#[test]
fn test_derive_key_err_diff_salt() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 64]).unwrap();
let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
let dk_diff_salt = derive_key(
&password,
&Salt::from_slice(&[1u8; 64]).unwrap(),
3,
1024,
32,
)
.unwrap();
assert_ne!(dk, dk_diff_salt);
}
#[test]
fn test_derive_key_err_diff_len() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 64]).unwrap();
let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
let dk_diff_len = derive_key(&password, &salt, 3, 1024, 64).unwrap();
assert_ne!(dk, dk_diff_len);
}
#[test]
fn test_derive_key_err_diff_pass() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 64]).unwrap();
let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
let dk_diff_pass = derive_key(
&Password::from_slice(&[1u8; 64]).unwrap(),
&salt,
3,
1024,
32,
)
.unwrap();
assert_ne!(dk, dk_diff_pass);
}
#[test]
fn test_derive_key_bad_length() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 64]).unwrap();
assert!(derive_key(&password, &salt, 3, 1024, 3).is_err());
assert!(derive_key(&password, &salt, 3, 1024, 4).is_ok());
assert!(derive_key(&password, &salt, 3, 1024, 5).is_ok());
}
#[test]
fn test_derive_key_bad_iter() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 16]).unwrap();
assert!(derive_key(&password, &salt, 2, 1024, 32).is_err());
assert!(derive_key(&password, &salt, 3, 1024, 32).is_ok());
assert!(derive_key(&password, &salt, 4, 1024, 32).is_ok());
}
#[test]
fn test_derive_key_bad_mem() {
let password = Password::from_slice(&[0u8; 64]).unwrap();
let salt = Salt::from_slice(&[0u8; 16]).unwrap();
assert!(derive_key(&password, &salt, 3, 7, 32).is_err());
assert!(derive_key(&password, &salt, 3, 8, 32).is_ok());
assert!(derive_key(&password, &salt, 3, 9, 32).is_ok());
}
}
}