Skip to content

fix: improve subtle.supports per spec, rename KMAC/cSHAKE length → outputLength#1026

Merged
boorad merged 3 commits into
mainfrom
fix/1004-subtle-supports-improvements
May 6, 2026
Merged

fix: improve subtle.supports per spec, rename KMAC/cSHAKE length → outputLength#1026
boorad merged 3 commits into
mainfrom
fix/1004-subtle-supports-improvements

Conversation

@boorad
Copy link
Copy Markdown
Collaborator

@boorad boorad commented May 6, 2026

Summary

Closes the gaps in Subtle.supports and the WICG KmacParams / CShakeParams rename tracked in #1004. Brings RNQC's capability detector close to Node's webcrypto.js:1506-1731 SubtleCrypto.supports and lands the lengthoutputLength rename throughout KMAC sign/verify and cSHAKE digest.

Changes

  • Subtle.supports rewrite — composed-operation decomposition for deriveKey, wrapKey, unwrapKey, encapsulateKey, decapsulateKey, getPublicKey; per-algorithm length validators for deriveBits (HKDF / PBKDF2 / Argon2); HMAC + SHA3 generateKey-without-length now returns false; wrapKey/unwrapKey fall back to encrypt/decrypt when normalize fails (mirrors Node's check()).
  • KMAC outputLengthkmacSignVerify now reads algorithm.outputLength (in bits, required), rejects missing values with OperationError and non-multiple-of-8 with NotSupportedError. Removed the silent 256/512-bit default that previously masked spec violations. SubtleAlgorithm gains outputLength?: number.
  • cSHAKE outputLengthasyncDigest reads algorithm.outputLength for cSHAKE128/cSHAKE256 per the WICG CShakeParams rename.
  • Tests — supports tests cover composed decomposition, length validators, HMAC/KMAC sharedKey rules, and the FAKE-additional-algorithm rejection path. KMAC sign/verify and JWK round-trip tests updated to pass outputLength.
  • Operation type — adds 'get key length' to mirror Node's algorithm map; the deriveKey path now uses it for the getKeyLength lookup.

Notes for review

  • B.7 reconsidered. The original issue requested exposing supports on the subtle instance. After review the instance form was removed: the WICG spec WebIDL declares static boolean supports(...), and Node throws ERR_INVALID_THIS when called off the constructor. Keeping the instance form would mean RNQC users writing subtle.supports(...) get code that breaks anywhere else. Subtle.supports(...) (static) is the only call form.
  • Follow-up filed: Subtle: harden normalizeAlgorithm with WebIDL-style validators #1025 — RNQC's normalizeAlgorithm is permissive (only canonicalizes name), so Subtle.supports('encapsulateKey', 'ML-KEM-768', 'HMAC') returns true here but false in Node (Node rejects HMAC without hash). Hardening normalizeAlgorithm with WebIDL converters has too large a blast radius for this PR.

Test plan

  • bun tsc clean (verified locally on both packages)
  • Run example app subtle.supports suite — composed-op decomposition cases
  • Run example app subtle.sign/verify KMAC suite with outputLength
  • Run example app subtle.digest cSHAKE128/256 with outputLength
  • Run example app subtle.importKey/exportKey KMAC JWK round-trip

Closes #1004
Refs #1025

boorad added 3 commits May 5, 2026 21:40
- Expose `supports` as instance method so `subtle.supports(...)` works,
  in addition to the existing static `Subtle.supports(...)`.
- Add composed-operation decomposition for `wrapKey`, `unwrapKey`,
  `encapsulateKey`, and `decapsulateKey`. `encapsulateKey`/`decapsulateKey`
  reject HMAC/KMAC sharedKeyAlgorithm with non-default length.
- Run per-algorithm length validators for `deriveBits` (HKDF, PBKDF2,
  Argon2) so `supports` returns false for inputs the actual implementation
  would reject.
- Rename KMAC `KmacParams.length` → `KmacParams.outputLength` and
  cSHAKE `CShakeParams.length` → `CShakeParams.outputLength` to match
  the WICG modern-algos spec rename. cSHAKE outputLength is now in
  bits (divided by 8 for the underlying SHAKE).
The jwk round-trip test for KMAC was still passing `length` to subtle.sign,
which now requires `outputLength` per the WICG modern-algos spec rename.
…h op

The WICG webcrypto-modern-algos spec defines `SubtleCrypto.supports` as
static-only; calling `subtle.supports(...)` would throw in Node and any
spec-compliant browser. Remove the instance form and the test that covered
it so RNQC stays portable.

Also pass `'get key length'` (rather than `'importKey'`) to
`normalizeAlgorithm` from the deriveKey decomposition path, mirroring
Node's webcrypto.js:1558. RNQC's `normalizeAlgorithm` ignores the op
argument today, so this is intent-only — but it leaves the call site
correctly wired for #1025 (hardening normalizeAlgorithm with WebIDL
validators).
@boorad boorad self-assigned this May 6, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-native-quick-crypto Ready Ready Preview, Comment May 6, 2026 2:15am

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

🤖 End-to-End Test Results - iOS

Status: ✅ Passed
Platform: iOS
Run: 25412852577

📸 Final Test Screenshot

Maestro Test Results - ios

Screenshot automatically captured from End-to-End tests and will expire in 30 days


This comment is automatically updated on each test run.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

🤖 End-to-End Test Results - Android

Status: ✅ Passed
Platform: Android
Run: 25412852579

📸 Final Test Screenshot

Maestro Test Results - android

Screenshot automatically captured from End-to-End tests and will expire in 30 days


This comment is automatically updated on each test run.

@boorad boorad merged commit dcf78c5 into main May 6, 2026
9 checks passed
@boorad boorad deleted the fix/1004-subtle-supports-improvements branch May 6, 2026 02:30
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.

subtle.supports: expose on instance, decompose composed operations, KMAC outputLength rename

1 participant