Jump to content

HKDF

From Wikipedia, the free encyclopedia

This is the current revision of this page, as edited by Ciphergoth (talk | contribs) at 14:51, 26 July 2024 (HKDF isn't magic, it can't make good randomness out of bad min-entropy. It does the best it can given a high min-entropy source.). The present address (URL) is a permanent link to this version.

(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

HKDF is a simple key derivation function (KDF) based on the HMAC message authentication code.[1][2] It was initially proposed by its authors as a building block in various protocols and applications, as well as to discourage the proliferation of multiple KDF mechanisms.[2] The main approach HKDF follows is the "extract-then-expand" paradigm, where the KDF logically consists of two modules: the first stage takes the input keying material and "extracts" from it a fixed-length pseudorandom key, and then the second stage "expands" this key into several additional pseudorandom keys (the output of the KDF).[2]

It can be used, for example, to convert shared secrets exchanged via Diffie–Hellman into key material suitable for use in encryption, integrity checking or authentication.[1]

It is formally described in RFC 5869.[2] One of its authors also described the algorithm in a companion paper in 2010.[1]

NIST SP800-56Cr2[3] specifies a parameterizable extract-then-expand scheme, noting that RFC 5869 HKDF is a version of it and citing its paper[1] for the rationale for the recommendations' extract-and-expand mechanisms.

There are implementations of HKDF for C#, Go,[4] Java,[5] JavaScript,[6] Perl, PHP,[7] Python,[8] Ruby, Rust,[9] and other programming languages.

Mechanism

[edit]

HKDF is the composition of two functions, HKDF-Extract and HKDF-Expand: HKDF(salt, IKM, info, length) = HKDF-Expand(HKDF-Extract(salt, IKM), info, length)

HKDF-Extract

[edit]

HKDF-Extract takes "input key material" (IKM) such as a shared secret generated using Diffie-Hellman, and an optional salt, and generates a cryptographic key called the PRK ("pseudorandom key"). This acts as a "randomness extractor", taking a potentially non-uniform value of high min-entropy and generating a value indistinguishable from a uniform random value.

HKDF-Extract is the output of HMAC with the "salt" as the key and the "IKM" as the message.

HKDF-Expand

[edit]

HKDF-Expand takes the PRK, some "info", and a length, and generates output of the desired length. HKDF-Expand acts as a pseudorandom function keyed on PRK. This means that multiple outputs can be generated from a single IKM value by using different values for the "info" field.

HKDF-Expand works by repeatedly calling HMAC using the PRK as the key and the "info" field as the message. The HMAC inputs are chained by prepending the previous hash block to the "info" field and appending with an incrementing 8-bit counter.[2]

Example: Python implementation

[edit]
#!/usr/bin/env python3

import hashlib
import hmac

hash_function = hashlib.sha256  # RFC5869 also includes SHA-1 test vectors


def hmac_digest(key: bytes, data: bytes) -> bytes:
    return hmac.new(key, data, hash_function).digest()


def hkdf_extract(salt: bytes, ikm: bytes) -> bytes:
    if len(salt) == 0:
        salt = bytes([0] * hash_function().digest_size)
    return hmac_digest(salt, ikm)


def hkdf_expand(prk: bytes, info: bytes, length: int) -> bytes:
    t = b""
    okm = b""
    i = 0
    while len(okm) < length:
        i += 1
        t = hmac_digest(prk, t + info + bytes([i]))
        okm += t
    return okm[:length]


def hkdf(salt: bytes, ikm: bytes, info: bytes, length: int) -> bytes:
    prk = hkdf_extract(salt, ikm)
    return hkdf_expand(prk, info, length)


okm = hkdf(
    salt=bytes.fromhex("000102030405060708090a0b0c"),
    ikm=bytes.fromhex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
    info=bytes.fromhex("f0f1f2f3f4f5f6f7f8f9"),
    length=42,
)
assert okm == bytes.fromhex(
    "3cb25f25faacd57a90434f64d0362f2a"
    "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
    "34007208d5b887185865"
)

# Zero-length salt
assert hkdf(
    salt=b"",
    ikm=bytes.fromhex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
    info=b"",
    length=42,
) == bytes.fromhex(
    "8da4e775a563c18f715f802a063c5a31"
    "b8a11f5c5ee1879ec3454e5f3c738d2d"
    "9d201395faa4b61a96c8"
)

References

[edit]
  1. ^ a b c d Krawczyk, Hugo (2010). "Cryptographic Extraction and Key Derivation: The HKDF Scheme". Cryptology ePrint Archive. International Association for Cryptologic Research.
  2. ^ a b c d e Krawczyk, H.; Eronen, P. (May 2010). "RFC 5869". Internet Engineering Task Force. doi:10.17487/RFC5869.
  3. ^ Elaine Barker; Lily Chen; Richard Davis (August 2020). "NIST Special Publication 800-56C: Recommendation for Key-Derivation Methods in Key-Establishment Schemes". doi:10.6028/NIST.SP.800-56Cr2. {{cite journal}}: Cite journal requires |journal= (help)
  4. ^ "package hkdf". pkg.go.dev.
  5. ^ "A standalone Java 7 implementation of HMAC-based key derivation function". github.com. 27 September 2022.
  6. ^ "Node.js implementation of RFC5869: HMAC-based Extract-and-Expand Key Derivation Function". npmjs.com. 30 July 2023.
  7. ^ "hash_hkdf — Generate a HKDF key derivation of a supplied key input". php.net.
  8. ^ "HMAC-based Extract-and-Expand Key Derivation Function (HKDF) implemented in Python". github.com. 17 March 2022.
  9. ^ "Module ring::hkdf". 19 October 2023. Retrieved 25 October 2023.
[edit]