Skip to main content

Kdf

Trait Kdf 

Source
pub trait Kdf {
    type Hash: Hasher;

    const HPKE_KDF_ID: u16;
    const OUTPUT_SIZE: usize = <Self::Hash as crypto::Hasher>::OUTPUT_SIZE;
    const SINGLE_STAGE: bool = false;

    // Provided methods
    fn labeled_extract(
        salt: &[u8],
        suite_id: &[u8],
        label: &[u8],
        input_keying_material: &[u8],
    ) -> Hash { ... }
    fn labeled_expand(
        out: &mut [u8],
        pseudorandom_key: &[u8],
        suite_id: &[u8],
        label: &[u8],
        info: &[u8],
    ) -> Result<(), HpkeError> { ... }
    fn labeled_derive(
        _out: &mut [u8],
        _input_keying_material: &[&[u8]],
        _suite_id: &[u8],
        _label: &[u8],
        _context: &[&[u8]],
    ) -> Result<(), HpkeError> { ... }
}
Expand description

Key derivation function (KDF) usable within an HPKE ciphersuite.

The default implementations follow the draft-ietf-hpke-hpke-05 constructions on top of HKDF (RFC 5869) with the hash Kdf::Hash. suite_id is the caller’s domain separator: the 5-byte KEM suite_id ("KEM" || I2OSP(kem_id, 2)) inside a KEM, or the 10-byte ciphersuite suite_id ("HPKE" || I2OSP(kem_id, 2) || I2OSP(kdf_id, 2) || I2OSP(aead_id, 2)) everywhere else. Passing the wrong one silently breaks interoperability.

Implementors only need to provide Kdf::HPKE_KDF_ID and the hash Kdf::Hash; for example, a KDF based on another hash is two lines.

§Single-stage KDFs

The two-stage key schedule is built from Kdf::labeled_extract and Kdf::labeled_expand. draft-ietf-hpke-hpke-05 also defines single-stage KDFs which derive the whole key schedule from a single Kdf::labeled_derive call, such as the SHAKE256 KDF of draft-ietf-hpke-pq-05. A single-stage KDF sets Kdf::SINGLE_STAGE to true and overrides Kdf::labeled_derive (its Kdf::labeled_extract and Kdf::labeled_expand implementations are never used).

§Input length restrictions

A single-stage LabeledDerive prefixes each length with two bytes, so the psk, psk_id, and info inputs are limited to 65,535 bytes; the key schedule and single-stage export enforce this (draft-ietf-hpke-hpke-05 Section 7.2.1). For two-stage KDFs the inputs are streamed into the underlying KDF, so info values of at least 16,384 bytes are supported, as Section 7.2.1 recommends.

§Example

use hpke::kdf::{HkdfSha256, Kdf};

let suite_id = b"HPKE\x00\x20\x00\x01\x00\x02";
let pseudorandom_key = HkdfSha256::labeled_extract(b"salt", suite_id, b"label", b"ikm");
let mut output_keying_material = [0u8; 32];
HkdfSha256::labeled_expand(&mut output_keying_material, &pseudorandom_key, suite_id, b"label", b"info").unwrap();

Required Associated Constants§

Source

const HPKE_KDF_ID: u16

The HPKE KDF identifier (draft-ietf-hpke-hpke-05 Section 7.2, IANA “HPKE KDF Identifiers”), used to build the ciphersuite suite_id.

Provided Associated Constants§

Source

const OUTPUT_SIZE: usize = <Self::Hash as crypto::Hasher>::OUTPUT_SIZE

Output size of the extract step (the hash output size).

Must not exceed [MAX_HASH_OUTPUT_SIZE].

Source

const SINGLE_STAGE: bool = false

Whether this is a single-stage KDF (draft-ietf-hpke-hpke-05 Section 4).

Two-stage KDFs (the default) use the two-stage key schedule built on Kdf::labeled_extract and Kdf::labeled_expand. Single-stage KDFs (e.g. Shake256) build the schedule from a single Kdf::labeled_derive call and MUST override it.

Required Associated Types§

Source

type Hash: Hasher

The hash function underlying the default HKDF construction.

Provided Methods§

Source

fn labeled_extract( salt: &[u8], suite_id: &[u8], label: &[u8], input_keying_material: &[u8], ) -> Hash

draft-ietf-hpke-hpke-05 Section 4.4 LabeledExtract(salt, label, input_keying_material): Extract(salt, "HPKE-v1" || suite_id || label || input_keying_material).

salt may be empty, in which case the HKDF default salt (a string of Kdf::OUTPUT_SIZE zero bytes) is used. The prefix is fed to HMAC incrementally, so input_keying_material may be arbitrarily long.

Source

fn labeled_expand( out: &mut [u8], pseudorandom_key: &[u8], suite_id: &[u8], label: &[u8], info: &[u8], ) -> Result<(), HpkeError>

draft-ietf-hpke-hpke-05 Section 4.4 LabeledExpand(pseudorandom_key, label, info, L): Expand(pseudorandom_key, I2OSP(L, 2) || "HPKE-v1" || suite_id || label || info, L), where L == out.len(). The info string is absorbed incrementally, so it may be arbitrarily long.

§Errors

Returns HpkeError::InvalidPseudorandomKey when pseudorandom_key is not exactly Kdf::OUTPUT_SIZE bytes long, and HpkeError::KdfOutputTooLong when out.len() > 255 * OUTPUT_SIZE.

Source

fn labeled_derive( _out: &mut [u8], _input_keying_material: &[&[u8]], _suite_id: &[u8], _label: &[u8], _context: &[&[u8]], ) -> Result<(), HpkeError>

draft-ietf-hpke-hpke-05 Section 4.4 LabeledDerive(input_keying_material, label, context, L): Derive(input_keying_material || "HPKE-v1" || suite_id || I2OSP(len(label), 2) || label || I2OSP(L, 2) || context, L), where L == out.len() and the elements of input_keying_material and context are absorbed in order.

This is the single-stage counterpart of Kdf::labeled_extract/Kdf::labeled_expand. suite_id has the same meaning as for the two-stage functions: the 5-byte KEM suite_id inside a KEM, or the 10-byte ciphersuite suite_id everywhere else.

§Errors

Returns HpkeError::KdfOutputTooLong when out is longer than 2^16 - 1 bytes, and HpkeError::NotSupported by default (only single-stage KDFs implement this).

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl Kdf for Blake3

Source§

const HPKE_KDF_ID: u16 = 0xFF01

Source§

const SINGLE_STAGE: bool = true

Source§

type Hash = Blake3

Source§

impl Kdf for HkdfSha256

Source§

const HPKE_KDF_ID: u16 = 0x0001

Source§

type Hash = Sha256

Source§

impl Kdf for HkdfSha512

Source§

const HPKE_KDF_ID: u16 = 0x0003

Source§

type Hash = Sha512

Source§

impl Kdf for Shake256

Source§

const HPKE_KDF_ID: u16 = 0x0011

Source§

const SINGLE_STAGE: bool = true

Source§

type Hash = Shake256