crypto_argon2id/
derive.rs1use argon2::{Algorithm, Argon2, Params, Version};
6use crypto_core::{CryptoError, KdfAlgorithm, KdfFailureKind};
7use zeroize::{Zeroize, Zeroizing};
8
9use crate::constants::ARGON2ID_DERIVED_KEY_LENGTH;
10use crate::material::{Argon2Salt, Argon2Secret, Argon2idDerivedKey};
11use crate::profile::{Argon2KdfVersion, Argon2Profile};
12
13pub struct DeriveKeyRequest<'a> {
15 pub profile: Argon2Profile,
17 pub secret: &'a Argon2Secret,
19 pub salt: &'a Argon2Salt,
21}
22
23pub fn derive_key(request: &DeriveKeyRequest<'_>) -> Result<Argon2idDerivedKey, CryptoError> {
27 let profile = request.profile;
28 let kdf_profile = profile.to_kdf_profile();
29 let (m_cost, t_cost, p_cost) = profile.params_tuple();
30
31 let params =
32 Params::new(m_cost, t_cost, p_cost, Some(ARGON2ID_DERIVED_KEY_LENGTH)).map_err(|_| {
33 CryptoError::Kdf {
34 algorithm: KdfAlgorithm::Argon2id,
35 profile: kdf_profile,
36 kind: KdfFailureKind::InvalidParams,
37 }
38 })?;
39
40 let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
41
42 let mut output = Zeroizing::new(vec![0u8; ARGON2ID_DERIVED_KEY_LENGTH]);
43 argon2
44 .hash_password_into(
45 request.secret.as_bytes(),
46 request.salt.as_bytes(),
47 &mut output,
48 )
49 .map_err(|_| CryptoError::Kdf {
50 algorithm: KdfAlgorithm::Argon2id,
51 profile: kdf_profile,
52 kind: KdfFailureKind::DerivationFailed,
53 })?;
54
55 let mut bytes = [0u8; ARGON2ID_DERIVED_KEY_LENGTH];
56 bytes.copy_from_slice(&output);
57 output.zeroize();
58
59 Ok(Argon2idDerivedKey::from_array(bytes))
60}
61
62pub fn derive_key_for_version(
66 kdf_version: u32,
67 secret: &[u8],
68 salt: &[u8],
69) -> Result<Argon2idDerivedKey, CryptoError> {
70 let version = Argon2KdfVersion::try_from(kdf_version)?;
71 let profile = Argon2Profile::from(version);
72
73 let secret = Argon2Secret::from_slice(secret, profile)?;
74 let salt = Argon2Salt::from_slice(salt, profile)?;
75
76 derive_key(&DeriveKeyRequest {
77 profile,
78 secret: &secret,
79 salt: &salt,
80 })
81}