Files

25 lines
2.4 KiB
Markdown

# 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` |
```bash
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.