dcrypt_algorithms/kdf/
mod.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3//! Key Derivation Functions with operation pattern and type-level guarantees
4//!
5//! This module provides implementations of key derivation functions (KDFs)
6//! with improved type safety and ergonomic APIs.
7//!
8/// ## Example usage
9///
10/// ```
11/// # use rand::rngs::OsRng;
12/// use dcrypt_algorithms::kdf::{TypedHkdf, KeyDerivationFunction, KdfOperation};
13/// use dcrypt_algorithms::hash::Sha256;
14///
15/// // Create KDF instance
16/// let kdf = TypedHkdf::<Sha256>::new();
17///
18/// // Generate a random salt
19/// let salt = TypedHkdf::<Sha256>::generate_salt(&mut OsRng);
20///
21/// // Traditional API
22/// let key1 = kdf.derive_key(
23///     b"password123",
24///     Some(salt.as_ref()),
25///     Some(b"context info"),
26///     32
27/// ).unwrap();
28///
29/// // Operation pattern API
30/// let key2 = kdf.builder()
31///     .with_ikm(b"password123")
32///     .with_salt(salt.as_ref())
33///     .with_info(b"context info")
34///     .with_output_length(32)
35///     .derive().unwrap();
36///
37/// // Derive to fixed-size array
38/// let key3: [u8; 32] = kdf.builder()
39///     .with_ikm(b"password123")
40///     .with_salt(salt.as_ref())
41///     .with_info(b"context info")
42///     .derive_array().unwrap();
43///
44/// assert_eq!(key1, key2);
45/// assert_eq!(&key1, key3.as_ref());
46/// ```
47// Conditional imports for no_std
48#[cfg(feature = "alloc")]
49extern crate alloc;
50
51#[cfg(not(feature = "std"))]
52#[cfg(feature = "alloc")]
53use alloc::vec::Vec;
54
55#[cfg(feature = "std")]
56use std::vec::Vec;
57
58#[cfg(feature = "std")]
59use std::time::Duration;
60
61#[cfg(not(feature = "std"))]
62use core::time::Duration;
63
64use ::core::marker::PhantomData;
65use rand::{CryptoRng, RngCore};
66
67// Import the new error types
68use crate::error::{Error, Result};
69use crate::hash::HashFunction;
70use crate::types::Salt;
71use zeroize::Zeroize;
72
73pub mod common;
74pub mod params;
75
76#[cfg(feature = "alloc")]
77pub mod hkdf;
78
79#[cfg(feature = "alloc")]
80pub mod pbkdf2;
81
82#[cfg(feature = "alloc")]
83pub mod argon2;
84
85pub use common::SecurityLevel;
86pub use params::{ParamProvider, PasswordHash};
87
88// Re-exports for convenience
89#[cfg(feature = "alloc")]
90pub use hkdf::Hkdf;
91
92#[cfg(feature = "alloc")]
93pub use pbkdf2::{Pbkdf2, Pbkdf2Params};
94
95#[cfg(feature = "alloc")]
96pub use argon2::{Algorithm as Argon2Type, Argon2, Params as Argon2Params};
97
98/// Marker trait for KDF algorithms
99pub trait KdfAlgorithm {
100    /// Minimum salt size in bytes
101    const MIN_SALT_SIZE: usize;
102
103    /// Default output size in bytes
104    const DEFAULT_OUTPUT_SIZE: usize;
105
106    /// Static algorithm identifier for compile-time checking
107    const ALGORITHM_ID: &'static str;
108
109    /// Returns the KDF algorithm name
110    fn name() -> String {
111        Self::ALGORITHM_ID.to_string()
112    }
113
114    /// Security level provided by this KDF
115    fn security_level() -> SecurityLevel;
116}
117
118/// Operation for KDF operations with improved type safety
119pub trait KdfOperation<'a, A: KdfAlgorithm, T = Vec<u8>>: Sized {
120    /// Set the input keying material
121    fn with_ikm(self, ikm: &'a [u8]) -> Self;
122
123    /// Set the salt
124    fn with_salt(self, salt: &'a [u8]) -> Self;
125
126    /// Set the info/context data
127    fn with_info(self, info: &'a [u8]) -> Self;
128
129    /// Set the desired output length
130    fn with_output_length(self, length: usize) -> Self;
131
132    /// Execute the key derivation
133    fn derive(self) -> Result<T>;
134
135    /// Execute the key derivation into a fixed-size array
136    fn derive_array<const N: usize>(self) -> Result<[u8; N]>;
137}
138
139/// Common trait for all key derivation functions
140pub trait KeyDerivationFunction {
141    /// The algorithm this KDF implements
142    type Algorithm: KdfAlgorithm;
143
144    /// Salt type with appropriate validation
145    type Salt: AsRef<[u8]> + AsMut<[u8]> + Clone;
146
147    /// Creates a new instance of the KDF with default parameters
148    fn new() -> Self;
149
150    /// Derives a key using the KDF parameters
151    ///
152    /// # Arguments
153    /// * `input` - Input keying material
154    /// * `salt` - Optional salt value
155    /// * `info` - Optional context and application-specific information
156    /// * `length` - Length of the output key in bytes
157    ///
158    /// # Returns
159    /// The derived key as a byte vector
160    #[cfg(feature = "alloc")]
161    fn derive_key(
162        &self,
163        input: &[u8],
164        salt: Option<&[u8]>,
165        info: Option<&[u8]>,
166        length: usize,
167    ) -> Result<Vec<u8>>;
168
169    /// Creates a builder for fluent API usage - FIXED: Elided lifetime
170    fn builder(&self) -> impl KdfOperation<'_, Self::Algorithm>
171    where
172        Self: Sized;
173
174    /// Returns the security level of the KDF in bits
175    fn security_level() -> SecurityLevel {
176        Self::Algorithm::security_level()
177    }
178
179    /// Generate a random salt with appropriate size
180    fn generate_salt<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Salt;
181}
182
183/// Type-level constants for HKDF algorithm
184pub enum HkdfAlgorithm<H: HashFunction> {
185    /// Phantom field for the hash function
186    _Hash(PhantomData<H>),
187}
188
189impl<H: HashFunction> KdfAlgorithm for HkdfAlgorithm<H> {
190    const MIN_SALT_SIZE: usize = 16;
191    const DEFAULT_OUTPUT_SIZE: usize = 32;
192    const ALGORITHM_ID: &'static str = "HKDF";
193
194    fn name() -> String {
195        format!("{}-{}", Self::ALGORITHM_ID, H::name())
196    }
197
198    fn security_level() -> SecurityLevel {
199        match H::output_size() * 8 {
200            bits if bits >= 512 => SecurityLevel::L256,
201            bits if bits >= 384 => SecurityLevel::L192,
202            bits if bits >= 256 => SecurityLevel::L128,
203            bits => SecurityLevel::Custom(bits as u32 / 2),
204        }
205    }
206}
207
208/// Enhanced HKDF implementation with type-level guarantees
209#[cfg(feature = "alloc")]
210pub struct TypedHkdf<H: HashFunction + Clone> {
211    inner: hkdf::Hkdf<H, 16>, // Use default size of 16
212    _phantom: PhantomData<H>,
213}
214
215#[cfg(feature = "alloc")]
216impl<H: HashFunction + Clone> KeyDerivationFunction for TypedHkdf<H> {
217    type Algorithm = HkdfAlgorithm<H>;
218    type Salt = Salt<16>; // Updated to use generic Salt with size
219
220    fn new() -> Self {
221        Self {
222            inner: hkdf::Hkdf::new(),
223            _phantom: PhantomData,
224        }
225    }
226
227    #[cfg(feature = "alloc")]
228    fn derive_key(
229        &self,
230        input: &[u8],
231        salt: Option<&[u8]>,
232        info: Option<&[u8]>,
233        length: usize,
234    ) -> Result<Vec<u8>> {
235        self.inner.derive_key(input, salt, info, length)
236    }
237
238    // FIXED: Elided lifetime
239    fn builder(&self) -> impl KdfOperation<'_, Self::Algorithm> {
240        HKdfOperation {
241            kdf: self,
242            ikm: None,
243            salt: None,
244            info: None,
245            length: Self::Algorithm::DEFAULT_OUTPUT_SIZE,
246        }
247    }
248
249    // FIXED: Removed unnecessary let binding
250    fn generate_salt<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Salt {
251        Salt::random_with_size(rng, Self::Algorithm::MIN_SALT_SIZE).expect("Salt generation failed")
252    }
253}
254
255/// HKDF builder implementation
256#[cfg(feature = "alloc")]
257pub struct HKdfOperation<'a, H: HashFunction + Clone> {
258    kdf: &'a TypedHkdf<H>,
259    ikm: Option<&'a [u8]>,
260    salt: Option<&'a [u8]>,
261    info: Option<&'a [u8]>,
262    length: usize,
263}
264
265#[cfg(feature = "alloc")]
266impl<'a, H: HashFunction + Clone> KdfOperation<'a, HkdfAlgorithm<H>> for HKdfOperation<'a, H> {
267    fn with_ikm(mut self, ikm: &'a [u8]) -> Self {
268        self.ikm = Some(ikm);
269        self
270    }
271
272    fn with_salt(mut self, salt: &'a [u8]) -> Self {
273        self.salt = Some(salt);
274        self
275    }
276
277    fn with_info(mut self, info: &'a [u8]) -> Self {
278        self.info = Some(info);
279        self
280    }
281
282    fn with_output_length(mut self, length: usize) -> Self {
283        self.length = length;
284        self
285    }
286
287    fn derive(self) -> Result<Vec<u8>> {
288        let ikm = self
289            .ikm
290            .ok_or_else(|| Error::param("ikm", "Input keying material is required"))?;
291
292        self.kdf.derive_key(ikm, self.salt, self.info, self.length)
293    }
294
295    fn derive_array<const N: usize>(self) -> Result<[u8; N]> {
296        // Ensure the requested size matches
297        if self.length != N {
298            return Err(Error::Length {
299                context: "HKDF output",
300                expected: N,
301                actual: self.length,
302            });
303        }
304
305        let vec = self.derive()?;
306
307        // Convert to fixed-size array
308        let mut array = [0u8; N];
309        array.copy_from_slice(&vec);
310        Ok(array)
311    }
312}
313
314/// Type-level constants for PBKDF2 algorithm
315pub enum Pbkdf2Algorithm<H: HashFunction> {
316    /// Phantom field for the hash function
317    _Hash(PhantomData<H>),
318}
319
320impl<H: HashFunction> KdfAlgorithm for Pbkdf2Algorithm<H> {
321    const MIN_SALT_SIZE: usize = 16;
322    const DEFAULT_OUTPUT_SIZE: usize = 32;
323    const ALGORITHM_ID: &'static str = "PBKDF2";
324
325    fn name() -> String {
326        format!("{}-{}", Self::ALGORITHM_ID, H::name())
327    }
328
329    fn security_level() -> SecurityLevel {
330        // PBKDF2 security depends on iterations and hash size
331        match H::output_size() * 8 {
332            bits if bits >= 512 => SecurityLevel::L128, // Conservative estimate
333            bits if bits >= 384 => SecurityLevel::L128,
334            bits if bits >= 256 => SecurityLevel::L128,
335            bits => SecurityLevel::Custom(bits as u32 / 2),
336        }
337    }
338}
339
340/// Enhanced PBKDF2 implementation with type-level guarantees
341#[cfg(feature = "alloc")]
342pub struct TypedPbkdf2<H: HashFunction + Clone> {
343    inner: pbkdf2::Pbkdf2<H, 16>, // Use default size of 16
344    _phantom: PhantomData<H>,
345}
346
347#[cfg(feature = "alloc")]
348impl<H: HashFunction + Clone> KeyDerivationFunction for TypedPbkdf2<H> {
349    type Algorithm = Pbkdf2Algorithm<H>;
350    type Salt = Salt<16>; // Updated to use generic Salt with size
351
352    fn new() -> Self {
353        Self {
354            inner: pbkdf2::Pbkdf2::new(),
355            _phantom: PhantomData,
356        }
357    }
358
359    #[cfg(feature = "alloc")]
360    fn derive_key(
361        &self,
362        input: &[u8],
363        salt: Option<&[u8]>,
364        info: Option<&[u8]>,
365        length: usize,
366    ) -> Result<Vec<u8>> {
367        self.inner.derive_key(input, salt, info, length)
368    }
369
370    // FIXED: Elided lifetime
371    fn builder(&self) -> impl KdfOperation<'_, Self::Algorithm> {
372        Pbkdf2Builder {
373            kdf: self,
374            password: None,
375            salt: None,
376            iterations: 600_000, // OWASP recommended minimum
377            length: Self::Algorithm::DEFAULT_OUTPUT_SIZE,
378        }
379    }
380
381    // FIXED: Removed unnecessary let binding
382    fn generate_salt<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Salt {
383        Salt::random_with_size(rng, Self::Algorithm::MIN_SALT_SIZE).expect("Salt generation failed")
384    }
385}
386
387/// PBKDF2 builder implementation
388#[cfg(feature = "alloc")]
389pub struct Pbkdf2Builder<'a, H: HashFunction + Clone> {
390    kdf: &'a TypedPbkdf2<H>,
391    password: Option<&'a [u8]>,
392    salt: Option<&'a [u8]>,
393    iterations: u32,
394    length: usize,
395}
396
397// FIXED: Elided lifetime in impl block
398#[cfg(feature = "alloc")]
399impl<H: HashFunction + Clone> Pbkdf2Builder<'_, H> {
400    /// Set the number of iterations
401    pub fn with_iterations(mut self, iterations: u32) -> Self {
402        self.iterations = iterations;
403        self
404    }
405}
406
407#[cfg(feature = "alloc")]
408impl<'a, H: HashFunction + Clone> KdfOperation<'a, Pbkdf2Algorithm<H>> for Pbkdf2Builder<'a, H> {
409    fn with_ikm(mut self, password: &'a [u8]) -> Self {
410        self.password = Some(password);
411        self
412    }
413
414    fn with_salt(mut self, salt: &'a [u8]) -> Self {
415        self.salt = Some(salt);
416        self
417    }
418
419    fn with_info(self, _info: &'a [u8]) -> Self {
420        // PBKDF2 doesn't use info, but we implement for API compatibility
421        self
422    }
423
424    fn with_output_length(mut self, length: usize) -> Self {
425        self.length = length;
426        self
427    }
428
429    fn derive(self) -> Result<Vec<u8>> {
430        let password = self
431            .password
432            .ok_or_else(|| Error::param("password", "Password is required"))?;
433        let salt = self
434            .salt
435            .ok_or_else(|| Error::param("salt", "Salt is required"))?;
436
437        // Adjust inner Pbkdf2Params
438        let mut params = self.kdf.inner.params().clone();
439        params.iterations = self.iterations;
440        params.key_length = self.length;
441
442        // Use inner implementation
443        let mut kdf = self.kdf.inner.clone();
444        kdf.set_params(params);
445
446        kdf.derive_key(password, Some(salt), None, self.length)
447    }
448
449    fn derive_array<const N: usize>(self) -> Result<[u8; N]> {
450        // Ensure the requested size matches
451        if self.length != N {
452            return Err(Error::Length {
453                context: "PBKDF2 output",
454                expected: N,
455                actual: self.length,
456            });
457        }
458
459        let vec = self.derive()?;
460
461        // Convert to fixed-size array
462        let mut array = [0u8; N];
463        array.copy_from_slice(&vec);
464        Ok(array)
465    }
466}
467
468/// Trait for password hashing functions with type-level guarantees
469pub trait PasswordHashFunction: KeyDerivationFunction + ParamProvider {
470    /// Password type with zeroizing
471    type Password: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
472
473    /// Hashes a password with the configured parameters
474    fn hash_password(&self, password: &Self::Password) -> Result<PasswordHash>;
475
476    /// Verifies a password against a hash
477    fn verify(&self, password: &Self::Password, hash: &PasswordHash) -> Result<bool>;
478
479    /// Benchmarks the current parameters on this system
480    fn benchmark(&self) -> Duration;
481
482    /// Recommends parameters based on a target duration
483    fn recommended_params(target_duration: Duration) -> Self::Params;
484}