Skip to main content

dcrypt_algorithms/kdf/
common.rs

1//! Common utilities for key derivation functions
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6use dcrypt_internal::constant_time::ConstantTimeEq;
7use dcrypt_internal::random::{try_fill_bytes_zeroing_on_error, CryptoRng, Error as RandomError};
8#[cfg(feature = "alloc")]
9use dcrypt_internal::zeroing::{boxed_bytes_zeroed, Zeroizing, ZeroizingBytes};
10
11/// Security level for KDFs in bits
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
13pub enum SecurityLevel {
14    /// 128-bit security level
15    L128,
16    /// 192-bit security level
17    L192,
18    /// 256-bit security level
19    L256,
20    /// Custom security level (in bits)
21    Custom(u32),
22}
23
24impl SecurityLevel {
25    /// Get the security level in bits
26    pub fn bits(&self) -> u32 {
27        match self {
28            SecurityLevel::L128 => 128,
29            SecurityLevel::L192 => 192,
30            SecurityLevel::L256 => 256,
31            SecurityLevel::Custom(bits) => *bits,
32        }
33    }
34
35    /// Get the recommended output size in bytes for this security level
36    pub fn recommended_output_size(&self) -> usize {
37        // For KDFs, output size is typically twice the security level
38        // to account for birthday attacks
39        (self.bits() / 4) as usize
40    }
41
42    /// Check if this security level meets a minimum requirement
43    pub fn meets_minimum(&self, minimum: SecurityLevel) -> bool {
44        self.bits() >= minimum.bits()
45    }
46}
47
48/// Compare two slices in constant time
49#[inline]
50pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
51    if a.len() != b.len() {
52        return false;
53    }
54    a.ct_eq(b).into()
55}
56
57/// Generate a salt using a caller-owned cryptographic randomness source.
58///
59/// Randomness failures are returned to the caller; this function never falls
60/// back to operating-system entropy or deterministic bytes.
61#[cfg(feature = "alloc")]
62pub fn generate_salt<R: CryptoRng + ?Sized>(
63    rng: &mut R,
64    len: usize,
65) -> core::result::Result<ZeroizingBytes, RandomError> {
66    let mut salt = Zeroizing::new(boxed_bytes_zeroed(len));
67    try_fill_bytes_zeroing_on_error(rng, &mut salt)?;
68    Ok(salt)
69}