Files

kdf

Companion code for the ankurm.com article Key Derivation Function API in Java (JEP 510): HKDF Explained with Real Examples.

javax.crypto.KDF was a preview API in JDK 24 (JEP 478) and is final in JDK 25 (JEP 510): no --enable-preview. The JDK ships exactly three algorithms, all HKDF (RFC 5869), all from the SunJCE provider: HKDF-SHA256, HKDF-SHA384, HKDF-SHA512. Everything here ran on Temurin 25.0.5+8; no dependencies except the comparison tools (Python cryptography 50.0.1 and the openssl 3.0.13 command line) for the interop steps.

File What it shows Output
(script) javap of KDF, KDFParameters, KDFSpi, HKDFParameterSpec and its nested types; proof it is not a preview API output/01-api-shape.txt
src/ApiTour.java registered algorithms, getInstance failures, the three spec shapes (extract+expand, extract only, expand only), several IKM pieces, deriveKey vs Cipher.init key sizes output/02-api-tour.txt
src/Rfc5869Vectors.java RFC 5869 appendix A cases 1 to 3 (SHA-256) asserted three ways each: OKM, PRK, expand-only from the PRK output/03-rfc5869-vectors.txt
src/RefHkdf.java, src/RefCheck.java, src/Interop.java, interop/cases.tsv HKDF written by hand from the RFC with javax.crypto.Mac, checked against the RFC, then JDK vs hand-written vs Python cryptography on 300 generated cases (SHA-256/384/512) output/04-interop-java-vs-python-vs-reference.txt
interop/gen_cases.py, interop/openssl_check.py how cases.tsv was made (fixed seed, regenerates byte-identically) and a third opinion from openssl kdf output/05-interop-python-openssl.txt
src/Tenants.java per-tenant, per-purpose, per-version keys from one master key; length-prefixed info; AES-GCM isolation output/06-tenants.txt
src/Mistakes.java same info twice, ambiguous concatenation, salt facts, the 255 x HashLen limit, a 4-digit PIN through HKDF vs PBKDF2 output/07-mistakes.txt
JDK25=/path/to/jdk-25 ./run.sh     # needs python3 with `cryptography`, and openssl, for output/05

The demos assert as they go (PASS/FAIL lines, non-zero exit on failure), following the other standalone modules in this repo; there is no JUnit here. Output is byte-stable. Not reproduced: JDK 24's preview behaviour (no JDK 24 was installed), and openssl was only run with 3.0.13.