跳到主要内容

JEP 478: Key Derivation Function API (Preview)

Summary

Introduce an API for Key Derivation Functions (KDFs), which are cryptographic algorithms for deriving additional keys from a secret key and other data. This is a preview API.

Goals

  • Enable applications to use KDF algorithms such as the HMAC-based Extract-and-Expand Key Derivation Function (HKDF, RFC 5869) and Argon2 (RFC 9106).

  • Enable the use of KDFs in Key Encapsulation Mechanism (KEM, JEP 452) implementations such as ML-KEM, in higher level protocols such as Hybrid Key Exchange in TLS 1.3, and in cryptographic schemes such as Hybrid Public Key Encryption (HPKE, RFC 9180).

  • Allow security providers to implement KDF algorithms in either Java code or native code.

  • Include an implementation of HKDF and introduce additional HKDF-specific APIs.

Non-Goals

  • It is not a goal to make the existing implementations of the Password-Based Key Derivation Functions PBKDF1 and PBKDF2 available via the new KDF API. These implementations will remain available via the existing SecretKeyFactory API.

  • It is not a goal to deliver a PKCS#11 implementation of HKDF. We intend to deliver that as a separate enhancement.

  • It is not a goal to refactor the key derivation functions used in the JDK's TLS implementation to use the new KDF API. We may, however, do that in follow-on work.

Motivation

Key Derivation Functions (KDFs) make use of cryptographic inputs, such as initial key material, a salt value, and a pseudorandom function, to create new cryptographically strong key material. A KDF is often used to create cryptographic data from which multiple keys can be obtained. A KDF allows keys to be created in a manner that is both secure and reproducible by two parties sharing knowledge of the inputs.

Deriving keys is similar to hashing passwords. A KDF uses a keyed hash along with additional entropy from its other inputs to either extract new key material or securely expand values into a larger stream of key material.

With the advent of quantum computing, classical cryptographic algorithms will increasingly be vulnerable to practical attacks. It is therefore critical for the Java Platform to support Post-Quantum Cryptography (PQC), which is resistant to these attacks. We aim to do so eventually by supporting Hybrid Public Key Encryption (HPKE), which enables the smooth transition to quantum-safe encryption algorithms. The KEM API (JEP 452), integrated in JDK 21, is one building block of HPKE, and was our first step toward HPKE and post-quantum readiness; the KDF API proposed here is one more building block of HPKE, and will be the second step.

The extensibility afforded by the addition of a KDF API will bring additional benefits. The PKCS#11 standard for cryptographic hardware devices has described KDF support for years. Making this technology available via the javax.crypto API will benefit applications and libraries that interact with such devices. Furthermore, developers of third-party crypto providers may offer custom KDF implementations, specifically those validated under test and subsequently certified by the National Institute of Standards and Technology.

Finally, it is paramount that the Java Platform offer better API support for password-hashing KDFs more sophisticated than PBKDF1 & PBKDF2, such as Argon2. None of the existing cryptographic APIs in the Java Platform is currently capable of representing KDFs in a natural way (see below). Implementors of third-party security providers have already expressed a need for a standard KDF API.

Description

A key derivation function has two fundamental operations:

  • Instantiation and initialization, which creates the KDF and initializes it with the appropriate parameters, and

  • Derivation, which accepts key material and other optional inputs as well as parameters to describe the output, and then generates the derived key or data.

We define a new class, javax.crypto.KDF, to represent key derivation functions.

This is a preview API, disabled by default

To use this new API in JDK 24, you must enable preview features:

  • Compile the program with javac --release 24 --enable-preview Main.java and run it with java --enable-preview Main; or,

  • When using the source code launcher, run the program with java --enable-preview Main.java; or,

  • When using jshell, start it with jshell --enable-preview.

Instantiation and initialization

The KDF class provides the usual suite of getInstance methods with the usual combinations of parameters, including optional KDFParameters and crypto provider names. The getInstance methods both instantiate a KDF and initialize its algorithm.

The HKDF algorithm, which is the only KDF we intend to include at this time, does not require a KDFParameters object. Other algorithms, however, such as SHAKE, may need it.

Derivation

The KDF class defines two methods for deriving keys:

We use the empty interface AlgorithmParameterSpec because different KDF algorithms take different parameters. A KDF implementation should define one or more AlgorithmParameterSpec subclasses to describe its parameters.

For the included HKDF implementation we provide three such subclasses, each representing inputs for a different mode of operation:

The containing HKDFParameterSpec interface defines static factory methods for creating instances of these three classes. It also defines a builder class, HKDFParameterSpec.Builder, for assembling key material for extraction operations.

Example

// Create a KDF object for the specified algorithm
KDF hkdf = KDF.getInstance("HKDF-SHA256");

// Create an ExtractExpand parameter specification
AlgorithmParameterSpec params =
HKDFParameterSpec.ofExtract()
.addIKM(initialKeyMaterial)
.addSalt(salt).thenExpand(info, 32);

// Derive a 32-byte AES key
SecretKey key = hkdf.deriveKey("AES", params);

// Additional deriveKey calls can be made with the same KDF object

Implementing KDF providers

A KDF implementation must extend the abstract class javax.crypto.KDFSpi.

Some KDF algorithms derive multiple cryptographic keys in a single derivation operation. If you are implementing such an algorithm, we recommend that you either provide a SecretKey subclass with methods that provide access to each key, or else return all of the keys in a single byte array and document how to separate them.

Future Work

  • Refactor TLS 1.3 — We intend to enhance the JDK's TLS 1.3 implementation to use the KDF API to derive keys via HKDF. At that time, we will add new functional tests to demonstrate the efficacy of retrieving a KDF implementation via the new API.

    We do not, initially, plan to do this for TLS versions prior to 1.3.

  • Implement Argon2 — We intend eventually to implement the Argon2 password-hashing KDF.

Alternatives

  • Use existing APIs — We considered using the existing KeyGenerator and SecretKeyFactory APIs to represent KDFs. Earlier key derivation algorithms such as TLS-PRF, PBKDF1, and PBKDF2 have been made to fit into these APIs, but in general these APIs do not work well for KDFs.

    • KeyGenerator is designed around the introduction of entropy, via a SecureRandom object, to create a non-deterministic key from a set of inputs. KDFs, by contrast, support the independent derivation by two separate parties of the same key material.

    • SecretKeyFactory is designed for the creation of a single key. Though there are scenarios in which a KDF may be used in this manner, KDFs are also required to support successive derivations from a key stream in a deterministic fashion.

  • Make PBKDF2 available via the new KDF API — PBKDF2 is rapidly being replaced by stronger algorithms, such as Argon2. Developers who use PBKDF2 already will likely continue to use it via the SecretKeyFactory API, rather than refactor existing code to use the KDF API. Making PBKDF2 available via the new API is thus unwarranted at this time, but we could do so later should a compelling need arise.

Testing

We will add RFC 5869 known-answer (KAT) tests, if available, along with tests for exception handling and SSL/TLS regression testing.