Jump to content

HKDF: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
m v2.05 - auto / Fix errors for CW project (Link equal to linktext)
 
(46 intermediate revisions by 29 users not shown)
Line 1: Line 1:
{{Short description|Key derivation function based on an HMAC}}
{{Multiple issues|
{{Primary sources|date=October 2017}}
{{Original research|date=October 2017}}
{{refimprove|date=October 2017}}
}}


'''HKDF''' is a simple [[key derivation function]] (KDF) based on a [[hash-based message authentication code]] (HMAC).<ref name=rfc/> 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.<ref name=rfc/> 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).<ref name=rfc/>
'''HKDF''' is a simple [[key derivation function]] (KDF) based on the [[HMAC]] [[message authentication code]].<ref name="iacr" /><ref name=rfc/> 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.<ref name=rfc/> 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).<ref name=rfc/>


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.<ref name=iacr/>
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.<ref name=iacr/>


It is formally described in the RFC 5869.<ref name=rfc>{{cite web |title=RFC 5869 |last1=Krawczyk |first1=H. |last2=Eronen |first2=P. |url=https://tools.ietf.org/html/rfc5869 |website=Internet Engineering Task Force |date=May 2010}}</ref> One of its authors also described the algorithm in a companion paper in 2010.<ref name=iacr>{{cite journal |last=Krawczyk |first=Hugo |title=Cryptographic Extraction and Key Derivation: The HKDF Scheme |work=Cryptology ePrint Archive |publisher=International Association for Cryptologic Research |date=2010 |url=https://eprint.iacr.org/2010/264.pdf}}</ref>
It is formally described in RFC 5869.<ref name=rfc>{{cite journal |title=RFC 5869 |last1=Krawczyk |first1=H. |last2=Eronen |first2=P. |url=https://tools.ietf.org/html/rfc5869 |website=Internet Engineering Task Force |date=May 2010|doi=10.17487/RFC5869 }}</ref> One of its authors also described the algorithm in a companion paper in 2010.<ref name=iacr>{{cite journal |last=Krawczyk |first=Hugo |title=Cryptographic Extraction and Key Derivation: The HKDF Scheme |journal=Cryptology ePrint Archive |publisher=International Association for Cryptologic Research |date=2010 |url=https://eprint.iacr.org/2010/264}}</ref>

NIST SP800-56Cr2<ref>{{cite journal|url=https://doi.org/10.6028/NIST.SP.800-56Cr2 |title=NIST Special Publication 800-56C: Recommendation for Key-Derivation Methods in Key-Establishment Schemes |author1=Elaine Barker|author2=Lily Chen|author3=Richard Davis|date=August 2020|doi=10.6028/NIST.SP.800-56Cr2 }}</ref> specifies a parameterizable extract-then-expand scheme, noting that RFC 5869 HKDF is a version of it and citing its paper<ref name=iacr/> for the rationale for the recommendations' extract-and-expand mechanisms.

There are implementations of HKDF for [[C Sharp (programming language)|C#]], [[Go (programming language)|Go]],<ref>{{cite web|url=https://pkg.go.dev/golang.org/x/crypto/hkdf|title=package hkdf |website=pkg.go.dev}}</ref> [[Java (programming language)|Java]],<ref>{{cite web|url=https://github.com/patrickfav/hkdf|title=A standalone Java 7 implementation of HMAC-based key derivation function |website=github.com|date=27 September 2022 }}</ref> [[JavaScript]],<ref>{{cite web|url=https://www.npmjs.com/package/futoin-hkdf|title=Node.js implementation of RFC5869: HMAC-based Extract-and-Expand Key Derivation Function |website=npmjs.com|date=30 July 2023 }}</ref> [[Perl]], [[PHP]],<ref>{{cite web|url=https://www.php.net/manual/en/function.hash-hkdf.php|title=hash_hkdf — Generate a HKDF key derivation of a supplied key input |website=php.net}}</ref> [[Python (programming language)|Python]],<ref>{{cite web|url=https://github.com/casebeer/python-hkdf|title=HMAC-based Extract-and-Expand Key Derivation Function (HKDF) implemented in Python. |website=github.com|date=17 March 2022 }}</ref> [[Ruby (programming language)|Ruby]], [[Rust (programming language)|Rust]],<ref>{{cite web|url=https://docs.rs/ring/0.17.5/ring/hkdf/index.html|title=Module ring::hkdf|date=19 October 2023|access-date=25 October 2023}}</ref> and other [[programming language]]s.


==Mechanism==
==Mechanism==
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 extracts a [[pseudorandom]] key (PRK) using an [[HMAC]] hash function (e.g. [[HMAC]]-[[SHA2|SHA256]]) on an optional [[salt (cryptography)|salt]] (acting as a key) and any potentially weak input key material (IKM) (acting as data). It then generates similarly cryptographically strong output key material (OKM) of any desired length by repeatedly generating PRK-keyed hash-blocks and then appending them into the output key material, finally truncating to the desired length.


===HKDF-Extract===
For added security, the PRK-keyed HMAC-hashed blocks are chained during their generation by prepending the previous hash block to an incrementing 8-bit counter with an optional context string in the middle before being hashed by HMAC to generate the current hash block.


HKDF-Extract takes "input key material" (IKM) such as a shared secret generated using Diffie-Hellman, and an optional [[salt (cryptography)|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.
Note: HKDF does not amplify entropy but does allow a large source of weaker entropy to be utilised more evenly and effectively.


HKDF-Extract is the output of HMAC with the "salt" as the key and the "IKM" as the message.
==Uses==
HKDF has two primary and potentially independent uses:


===HKDF-Expand===
1. To "extract" (condense/blend) entropy from a larger random source to provide a more uniformly unbiased and higher entropy but smaller output (e.g. an encryption key). This is done by utilising the diffusion properties of cryptographic MACs.


HKDF-Expand takes the PRK, some "info", and a length, and generates output of the desired length. HKDF-Expand acts as a [[pseudorandom function family|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.
2. To "expand" the generated output of an already reasonably random input such as an existing shared key into a larger cryptographically independent output, thereby producing multiple keys deterministically from that initial shared key, so that the same process may produce those same secret keys safely on multiple devices, as long as the same inputs are utilised.


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.<ref name=rfc/>
These two functions may also be combined and used to form a [[pseudorandom number generator|PRNG]] to improve a random number generator's potentially-biased output, as well as to protect it from analysis and help defend the random number generation from malicious inputs.


== Example: Python implementation ==
== Example: Python implementation ==
<source lang="python3">
<syntaxhighlight lang="python3">
#!/usr/bin/env python3
#!/usr/bin/env python3

import hashlib
import hmac
import hashlib
from math import ceil
import hmac

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

def hmac_sha256(key, data):

return hmac.new(key, data, hashlib.sha256).digest()
def hmac_digest(key: bytes, data: bytes) -> bytes:
return hmac.new(key, data, hash_function).digest()
def hkdf(length, ikm, salt=b"", info=b""):

prk = hmac_sha256(salt, ikm)

t = b""
def hkdf_extract(salt: bytes, ikm: bytes) -> bytes:
okm = b""
if len(salt) == 0:
for i in range(ceil(length / hash_len)):
t = hmac_sha256(prk, t + info + bytes([1+i]))
salt = bytes([0] * hash_function().digest_size)
return hmac_digest(salt, ikm)
okm += t

return okm[:length]

</source>
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"
)
</syntaxhighlight>


== References ==
== References ==
Line 52: Line 91:


== External links ==
== External links ==
{{Cryptography navbox | hash}}
* [https://tools.ietf.org/html/rfc5869 RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF)]


[[Category:Cryptography]]
[[Category:Cryptography]]

Latest revision as of 13:00, 4 December 2024

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]