Skip to content

feat(sdk): add ML-KEM key access objects (DSPX-3229)#933

Draft
dmihalcik-virtru wants to merge 7 commits into
mainfrom
DSPX-3229-claude-version
Draft

feat(sdk): add ML-KEM key access objects (DSPX-3229)#933
dmihalcik-virtru wants to merge 7 commits into
mainfrom
DSPX-3229-claude-version

Conversation

@dmihalcik-virtru
Copy link
Copy Markdown
Member

Summary

  • Adds NIST FIPS 203 ML-KEM (levels 512/768/1024) as a third TDF key-wrap family alongside RSA-OAEP and ECDH+HKDF, using @noble/post-quantum.
  • New MlKemWrapped KAO class, crypto core (encapsulate/decapsulate/HKDF), encrypt + rewrap dispatch, key-format raw-base64 handling, and mocha test server with ML-KEM re-encapsulation.
  • Sample web-app gains a key-wrap-algorithm dropdown; Playwright roundtrips cover all three ML-KEM levels.

Format

  • wrappedKey = base64(mlkem_ct || iv(12) || aes-256-gcm ct(32) || tag(16))
  • ML-KEM public keys travel as raw base64 (no PEM); RSA/EC unchanged.
  • KAO type: "wrapped", alg: mlkem:{512,768,1024}; no ephemeralPublicKey field.
  • Default encapsulation algorithm stays rsa:2048 until 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 passes
  • make lint / make license-check@noble/post-quantum is MIT
  • cd web-app && npm run build — sample app still builds with new dropdown
  • cd web-app/tests && npm test — Playwright roundtrips for mlkem:512/768/1024 (requires KAS-side ML-KEM support)
  • Manual: encrypt a file with mlkem:768 selected; verify the manifest wrappedKey decodes to 1088 + 60 = 1148 bytes; decrypt round-trips.

🤖 Generated with Claude Code

dmihalcik-virtru and others added 4 commits May 8, 2026 17:06
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>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 62e18a51-5900-4cef-8899-4e6028075f26

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch DSPX-3229-claude-version

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

If these changes look good, signoff on them with:

git pull && git commit --amend --signoff && git push --force-with-lease origin

If they aren't any good, please remove them with:

git pull && git reset --hard HEAD~1 && git push --force-with-lease origin

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread lib/tdf3/src/tdf.ts
Comment on lines +918 to +923
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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

@github-actions
Copy link
Copy Markdown

If these changes look good, signoff on them with:

git pull && git commit --amend --signoff && git push --force-with-lease origin

If they aren't any good, please remove them with:

git pull && git reset --hard HEAD~1 && git push --force-with-lease origin

dmihalcik-virtru and others added 3 commits May 14, 2026 11:18
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>
@dmihalcik-virtru dmihalcik-virtru force-pushed the DSPX-3229-claude-version branch from e613ab9 to 819fe70 Compare May 15, 2026 02:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant