JEP 478: Key Derivation Function API (Preview)
Owner | Kevin Driver |
Type | Feature |
Scope | SE |
Status | Integrated |
Release | 24 |
Component | security-libs / javax.crypto |
Discussion | security dash dev at openjdk dot org |
Effort | M |
Duration | M |
Reviewed by | Sean Mullan |
Endorsed by | Sean Mullan |
Created | 2017/10/23 16:56 |
Updated | 2024/11/06 14:48 |
Issue | 8189808 |
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 withjava --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 withjshell --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:
-
deriveKey(String alg, AlgorithmParameterSpec spec
) constructs aSecretKey
object, using the specified algorithm and according to the specified parameters. -
deriveData(AlgorithmParameterSpec spec)
returns a byte array, which can be used for entropy or if key material is required in that form.
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
andSecretKeyFactory
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 aSecureRandom
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 theSecretKeyFactory
API, rather than refactor existing code to use theKDF
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.