feat(sdk): add ML-KEM key access objects (DSPX-3229)#933
feat(sdk): add ML-KEM key access objects (DSPX-3229)#933dmihalcik-virtru wants to merge 7 commits into
Conversation
ml-kem kaos
Documents the mlkem:512/768/1024 algorithm family, wrappedKey blob layout (mlkem_ct || iv || aes-256-gcm ct || tag), CryptoService additions, @noble/post-quantum dependency, and acceptance criteria covering unit tests, Playwright roundtrip, and test server changes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Adds NIST FIPS 203 ML-KEM (levels 512/768/1024) as a third key-wrap family alongside RSA-OAEP and ECDH+HKDF, using @noble/post-quantum. Public keys are transmitted as raw base64 (no PEM); wrappedKey blob is base64(mlkem_ct || iv(12) || aes-256-gcm ct(32) || tag(16)). Includes new MlKemWrapped KAO class, encapsulate/decapsulate/HKDF crypto core, encrypt/rewrap routing, mocha test server with ML-KEM re-encapsulation, unit tests, encrypt-decrypt matrix coverage, and a sample-app dropdown + Playwright roundtrips. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
If these changes look good, signoff on them with: If they aren't any good, please remove them with: |
There was a problem hiding this comment.
Code Review
This pull request introduces support for NIST FIPS 203 ML-KEM (Module-Lattice-Based Key-Encapsulation Mechanism) as a post-quantum cryptographic option for TDF Key Access Objects. It adds the @noble/post-quantum dependency and implements key generation, encapsulation, and decapsulation for ML-KEM-512, 768, and 1024. Key changes include updates to the CryptoService, the addition of an MlKemWrapped key access class, and support in the TDF client and web application for selecting these algorithms. Feedback was provided regarding the need for input length validation when processing wrapped keys to prevent errors with malformed data.
| const level = parseInt(wrappingKeyAlgorithm.split(':')[1], 10) as 512 | 768 | 1024; | ||
| const ctLen = MLKEM_CT_SIZES[level]; | ||
| const kemCt = entityWrappedKey.slice(0, ctLen); | ||
| const rest = entityWrappedKey.slice(ctLen); | ||
| const iv = rest.slice(0, 12); | ||
| const wrappedKey = rest.slice(12); |
There was a problem hiding this comment.
The code assumes that entityWrappedKey contains at least ctLen + 12 bytes. If the input is malformed or truncated, slice will return shorter arrays, which could lead to unexpected behavior or cryptic errors in subsequent crypto operations. It is safer to validate the total length of entityWrappedKey against the expected structure (ctLen + 12 (IV) + 32 (AES CT) + 16 (Tag)) before processing.
|
If these changes look good, signoff on them with: If they aren't any good, please remove them with: |
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Round 2 brings ML-KEM into the same RSA/EC PEM + OID code path it was
special-casing in the initial implementation:
- publicKeyAlgorithmToJwa returns ML-KEM-{512,768,1024}+A{128,192,256}KW
per draft-ietf-jose-pqc-kem-05 §9 instead of throwing.
- fetchKasPubKey drops its ML-KEM exclusion, so a KAS may advertise an
ML-KEM WellKnown base key.
- New mlkem-asn1.ts SPKI codec wraps/unwraps ML-KEM public keys using
the NIST OIDs 2.16.840.1.101.3.4.4.{1,2,3}, byte-compatible with
`openssl pkey -pubout`.
- parsePublicKeyPem detects ML-KEM by OID; importPublicKey and
exportPublicKeyPem now consume/emit PEM SPKI for ML-KEM. Callers in
client/index.ts and tdf.ts no longer branch on wrappingKeyAlgorithm.
- Test KAS server returns PEM SPKI for ML-KEM and gains a BASE_KEY_ALG
env switch so the WellKnown base key can be flipped to mlkem:768 for
end-to-end validation.
- Sample web-app gains a #kaoMetadata table that shows kid/type/url
for each KAO on decrypt; Playwright roundtrips assert that the kid
matches the expected mlkemN variant.
- AES-256-GCM stays as the wrap primitive for all ML-KEM levels;
rationale captured in the spec (WebCrypto AES-GCM has no 192-bit
support, GCM ≠ KW so JWA names are informational, ECWrapped already
uses AES-256-GCM regardless of curve strength).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
e613ab9 to
819fe70
Compare
Summary
@noble/post-quantum.MlKemWrappedKAO class, crypto core (encapsulate/decapsulate/HKDF), encrypt + rewrap dispatch, key-format raw-base64 handling, and mocha test server with ML-KEM re-encapsulation.Format
wrappedKey = base64(mlkem_ct || iv(12) || aes-256-gcm ct(32) || tag(16))type: "wrapped",alg: mlkem:{512,768,1024}; noephemeralPublicKeyfield.rsa:2048until KAS rollout.Test plan
cd lib && npm test— unit tests + 25-cell encrypt/decrypt matrix (3 ML-KEM levels × {ec, rsa, mlkem})cd lib && npm run build— type-check passesmake lint/make license-check—@noble/post-quantumis MITcd web-app && npm run build— sample app still builds with new dropdowncd web-app/tests && npm test— Playwright roundtrips formlkem:512/768/1024(requires KAS-side ML-KEM support)mlkem:768selected; verify the manifestwrappedKeydecodes to 1088 + 60 = 1148 bytes; decrypt round-trips.🤖 Generated with Claude Code