dcrypt 1.2.3

dcrypt is a pure-Rust, software-only cryptography library providing both classical and post-quantum primitives with a focus on security, hybrid KEMs/signatures, and memory-safe, no-FFI design.
Documentation
# HMAC-based Key Derivation Function (HKDF)

## Overview

This module provides a secure and constant-time implementation of the HMAC-based Key Derivation Function (HKDF) as specified in [RFC 5869](https://tools.ietf.org/html/rfc5869).

HKDF is a standard and highly-regarded KDF used to derive one or more cryptographically strong keys from a source of initial keying material (IKM), which may not be perfectly uniform or random. A common use case is to convert a shared secret from a key exchange protocol (like ECDH) into symmetric keys suitable for encryption and authentication.

### Key Concepts

HKDF follows a two-step "extract-then-expand" process:

1.  **Extract**: This step takes the input keying material (IKM) and an optional salt to produce a fixed-length pseudorandom key (PRK). The purpose of the extraction phase is to concentrate the entropy of the IKM.
    -   `PRK = HMAC-Hash(salt, IKM)`

2.  **Expand**: This step takes the PRK generated by the extraction phase, an optional context-specific "info" string, and the desired output length. It expands the PRK into the final output keying material (OKM) of the requested length. The same PRK can be used to generate multiple unique keys by providing different `info` strings.
    -   `OKM = HMAC-PRK(T(1) | info | 0x01), HMAC-PRK(T(2) | info | 0x02), ...`

### Core Features of this Implementation

*   **Generic over Hash Functions**: The `Hkdf` struct is generic over any hash function that implements the `HashFunction` trait, such as `Sha256` or `Sha512`.
*   **Secure Memory Handling**: All intermediate secret values, such as the Pseudorandom Key (PRK), are stored in secure memory buffers (`SecretBuffer`, `Zeroizing`) that are automatically zeroed on drop to prevent leakage.
*   **Constant-Time Operations**: The underlying `Hmac` implementation is constant-time, protecting against timing side-channel attacks.
*   **Ergonomic API**: The module provides both a simple one-shot `derive` function for common use cases and a fluent builder pattern through the `KeyDerivationFunction` trait for more complex scenarios.

## Usage

### Example 1: Basic One-Shot Derivation

This is the most common and straightforward way to use HKDF. The `derive` function handles both the extract and expand steps internally.

```rust
use dcrypt::algorithms::kdf::Hkdf;
use dcrypt::algorithms::hash::Sha256;

// Input materials
let ikm = b"this-is-some-non-uniform-secret"; // e.g., from a key exchange
let salt = b"a-unique-salt-for-this-operation";
let info = b"aes-256-gcm-key-for-session-123";
let output_length = 32; // We want a 256-bit key

// Derive the key
let derived_key = Hkdf::<Sha256>::derive(Some(salt), ikm, Some(info), output_length).unwrap();

assert_eq!(derived_key.len(), output_length);
println!("Derived Key (hex): {}", hex::encode(&derived_key));
```

### Example 2: Two-Step Extract-then-Expand

You can also perform the `extract` and `expand` steps separately. This is useful if you need to derive multiple keys from the same initial secret but with different contexts.

```rust
use dcrypt::algorithms::kdf::Hkdf;
use dcrypt::algorithms::hash::Sha256;

let ikm = b"this-is-some-non-uniform-secret";
let salt = b"a-unique-salt-for-this-operation";

// 1. Extract a Pseudorandom Key (PRK).
// The PRK will have the same length as the hash function's output (32 bytes for SHA-256).
let prk = Hkdf::<Sha256>::extract(Some(salt), ikm).unwrap();
assert_eq!(prk.len(), 32);

// 2. Expand the PRK to get different keys using different "info" strings.
let encryption_key = Hkdf::<Sha256>::expand(&prk, Some(b"encryption-key"), 32).unwrap();
let mac_key = Hkdf::<Sha256>::expand(&prk, Some(b"mac-key"), 32).unwrap();

assert_eq!(encryption_key.len(), 32);
assert_eq!(mac_key.len(), 32);
assert_ne!(encryption_key, mac_key); // The keys will be different due to the different info.
```

### Example 3: Using the Builder Pattern

The `KeyDerivationFunction` trait provides a fluent builder pattern for configuring the derivation.

```rust
use dcrypt::algorithms::kdf::{Hkdf, KeyDerivationFunction, KdfOperation};
use dcrypt::algorithms::hash::Sha256;

let kdf = Hkdf::<Sha256>::new();

// Derive into a Vec<u8>
let key_vec: Vec<u8> = kdf.builder()
    .with_ikm(b"input-keying-material")
    .with_salt(b"some-salt")
    .with_info(b"some-info")
    .with_output_length(42)
    .derive()
    .unwrap();
assert_eq!(key_vec.len(), 42);

// Or derive directly into a fixed-size array
let key_array: [u8; 32] = kdf.builder()
    .with_ikm(b"input-keying-material")
    .with_salt(b"some-salt")
    .with_info(b"some-info")
    .with_output_length(32) // Must match the array size
    .derive_array()
    .unwrap();
assert_eq!(key_array.len(), 32);
```

### Example 4: Using a Different Hash Function (SHA-512)

The implementation is generic, so switching the underlying hash function is trivial.

```rust
use dcrypt::algorithms::kdf::Hkdf;
use dcrypt::algorithms::hash::Sha512;

let ikm = b"this-is-some-non-uniform-secret";
let salt = b"a-unique-salt-for-this-operation";
let info = b"aes-256-gcm-key-for-session-123";

// We want two 256-bit keys, so we derive 64 bytes in total.
let output_length = 64;

// Use SHA-512 this time
let derived_material = Hkdf::<Sha512>::derive(Some(salt), ikm, Some(info), output_length).unwrap();

let (key1, key2) = derived_material.split_at(32);
assert_eq!(key1.len(), 32);
assert_eq!(key2.len(), 32);
```

## Security Considerations

*   **IKM (Input Keying Material)**: While HKDF is designed to handle non-uniform inputs, the IKM must have sufficient entropy to be secure. It should be a secret value that is unpredictable to an attacker.
*   **Salt**: The salt is not required to be secret, but it should ideally be a random, non-repeating value. Its primary purpose is to ensure that different HKDF instances with the same IKM produce different keys, preventing pre-computation attacks if the same IKM is used in different contexts. A salt of the same length as the hash function's output is recommended.
*   **Info (Context String)**: The `info` parameter is crucial for **domain separation**. It binds the derived key to a specific application or context. For example, deriving an encryption key and a MAC key from the same PRK should use different `info` strings (e.g., `b"encryption"` and `b"authentication"`) to ensure the keys are cryptographically distinct.

## API Reference

*   `Hkdf<H: HashFunction>`: The main struct for HKDF operations, generic over a hash function.
*   **Trait `KeyDerivationFunction`**: Provides the main interface for HKDF.
    *   `new()`: Creates a new HKDF instance with default parameters.
    *   `derive_key()`: The primary one-shot derivation method.
    *   `builder()`: Returns a fluent builder for configuring and executing the KDF.
*   **Static Methods on `Hkdf`**:
    *   `Hkdf::extract(salt, ikm)`: Performs the HKDF-Extract step.
    *   `Hkdf::expand(prk, info, length)`: Performs the HKDF-Expand step.

## `no_std` Support

This module is fully compatible with `no_std` environments, provided the `alloc` feature is enabled, as it requires `Vec<u8>` for its operations.