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§
Sourceconst HPKE_KDF_ID: u16
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§
Sourceconst OUTPUT_SIZE: usize = <Self::Hash as crypto::Hasher>::OUTPUT_SIZE
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].
Sourceconst SINGLE_STAGE: bool = false
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§
Provided Methods§
Sourcefn labeled_extract(
salt: &[u8],
suite_id: &[u8],
label: &[u8],
input_keying_material: &[u8],
) -> Hash
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.
Sourcefn labeled_expand(
out: &mut [u8],
pseudorandom_key: &[u8],
suite_id: &[u8],
label: &[u8],
info: &[u8],
) -> Result<(), HpkeError>
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.
Sourcefn labeled_derive(
_out: &mut [u8],
_input_keying_material: &[&[u8]],
_suite_id: &[u8],
_label: &[u8],
_context: &[&[u8]],
) -> Result<(), HpkeError>
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".