JEP 478: Key Derivation Function API (Preview)

OwnerKevin Driver
TypeFeature
ScopeSE
StatusCandidate
Componentsecurity-libs / javax.crypto
Discussionsecurity dash dev at openjdk dot org
EffortM
DurationM
Reviewed bySean Mullan
Endorsed bySean Mullan
Created2017/10/23 16:56
Updated2024/05/15 19:59
Issue8189808

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

Non-Goals

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:

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 23, you must enable preview features:

Instantiation and initialization

The KDF class provides the usual suite of getInstance methods with the usual combinations of parameters, including optional AlgorithmParameterSpec and crypto provider names. KDF objects are immutable, so 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 an AlgorithmParameterSpec. Other algorithms, however, such as SHAKE, may need it.

Derivation

The KDF class defines two methods for deriving keys:

The javax.crypto.spec.KDFParameterSpec interface is empty, since different KDF algorithms take different parameters. A KDF implementation should define one or more KDFParameterSpec 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("HKDFWithHmacSHA256"); 

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

// 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.

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.

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 on 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. We will add new SSL/TLS functional tests to demonstrate the efficacy of retrieving a KDF implementation via the new API rather than using the internal implementation.