crypto_argon2id/
derive.rs1use argon2::{Algorithm, Argon2, Block, 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 block_count = params.block_count();
41 let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
42
43 let mut blocks = Vec::new();
48 blocks
49 .try_reserve_exact(block_count)
50 .map_err(|_| CryptoError::Kdf {
51 algorithm: KdfAlgorithm::Argon2id,
52 profile: kdf_profile,
53 kind: KdfFailureKind::DerivationFailed,
54 })?;
55 blocks.resize(block_count, Block::default());
56 let mut blocks = Zeroizing::new(blocks);
57
58 let mut output = Zeroizing::new(vec![0u8; ARGON2ID_DERIVED_KEY_LENGTH]);
59 argon2
60 .hash_password_into_with_memory(
61 request.secret.as_bytes(),
62 request.salt.as_bytes(),
63 &mut output,
64 blocks.as_mut_slice(),
65 )
66 .map_err(|_| CryptoError::Kdf {
67 algorithm: KdfAlgorithm::Argon2id,
68 profile: kdf_profile,
69 kind: KdfFailureKind::DerivationFailed,
70 })?;
71
72 let mut bytes = [0u8; ARGON2ID_DERIVED_KEY_LENGTH];
73 bytes.copy_from_slice(&output);
74 output.zeroize();
75
76 Ok(Argon2idDerivedKey::from_array(bytes))
77}
78
79pub fn derive_key_for_version(
83 kdf_version: u32,
84 secret: &[u8],
85 salt: &[u8],
86) -> Result<Argon2idDerivedKey, CryptoError> {
87 let version = Argon2KdfVersion::try_from(kdf_version)?;
88 let profile = Argon2Profile::from(version);
89
90 let secret = Argon2Secret::from_slice(secret, profile)?;
91 let salt = Argon2Salt::from_slice(salt, profile)?;
92
93 derive_key(&DeriveKeyRequest {
94 profile,
95 secret: &secret,
96 salt: &salt,
97 })
98}