Skip to content

fix(ext/crypto): pad JWK to multiple of 8 bytes for AES-KW wrap#35475

Merged
littledivy merged 3 commits into
mainfrom
orch/divybot-584
Jun 25, 2026
Merged

fix(ext/crypto): pad JWK to multiple of 8 bytes for AES-KW wrap#35475
littledivy merged 3 commits into
mainfrom
orch/divybot-584

Conversation

@divybot

@divybot divybot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

SubtleCrypto.wrapKey("jwk", key, wrappingKey, "AES-KW") threw TypeError: Data must be multiple of 8 bytes because the UTF-8 JSON serialization of a JWK is generally not aligned to 8 bytes, which AES-KW requires.

Pad the JWK JSON with ASCII spaces (0x20) to the next multiple of 8 before passing to AES-KW. This matches the de-facto behavior of Node.js, Chrome, and Firefox (the spec is silent here, but every implementation pads). The unwrap path needs no change — JSON.parse accepts the trailing whitespace produced after AES-KW unwrap.

Repro from the issue now matches Node.js output:

const { subtle } = globalThis.crypto;
const [key, wrappingKey] = await Promise.all([
  subtle.generateKey({ name: "HMAC", hash: "SHA-512" }, true, ["sign", "verify"]),
  subtle.generateKey({ name: "AES-KW", length: 256 }, true, ["wrapKey", "unwrapKey"]),
]);
const wrapped = await subtle.wrapKey("jwk", key, wrappingKey, "AES-KW");
const unwrapped = await subtle.unwrapKey(
  "jwk", wrapped, wrappingKey, "AES-KW",
  { name: "HMAC", hash: "SHA-512" }, true, ["sign", "verify"],
);
// wrapped is now a 256-byte ArrayBuffer; unwrapped is a usable HMAC CryptoKey

Fixes #35416.

Test plan

  • cargo test -p unit_tests --test unit -- webcryptowebcrypto_test and webcrypto_mldsa_test pass
  • cargo test -p deno_crypto — all crate tests pass
  • cargo clippy -p deno_crypto — clean
  • Added regression test testWrapUnwrapJwkAesKw covering all four HMAC hashes (SHA-1/256/384/512); verifies wrapped length is a multiple of 8 and that the unwrapped key produces the same MAC as the original
  • Manual repro from the issue now runs without TypeError and matches the Node.js output shape (256-byte ArrayBuffer for HMAC SHA-512)

`SubtleCrypto.wrapKey("jwk", key, wrappingKey, "AES-KW")` threw a
TypeError because the UTF-8 JSON serialization of the JWK is generally
not a multiple of 8 bytes, which AES-KW requires.

Pad with ASCII spaces to the next multiple of 8 — the de-facto behavior
of Node.js, Chrome, and Firefox. JSON.parse on unwrap accepts the
trailing whitespace, so the unwrap path needs no change.

Fixes #35416.
@divybot

divybot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

test node_compat (1/3) release linux-x86_64 failed on test-cluster-concurrent-disconnect.js with Mismatched <anonymous> function calls. Expected exactly 1, actual 0. — this is the known flake tracked in #35453 (labeled flaky), unrelated to the crypto change in this PR. Can a maintainer please rerun the failed job?

@divybot

divybot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Second unrelated infra flake on the same CI run: test node_compat (1/3) debug macos-x86_64 failed on test-http2-respond-with-file-connection-abort.js with Test timed out after 20000ms. Pure network timing flake (HTTP/2 connection abort) — orthogonal to this PR's ext/crypto/subtle_wrap_key.rs change. The PR itself has no code issue to fix; a maintainer rerun would clear both flakes. (divybot cannot rerun: 403 Must have admin rights.)

@littledivy
littledivy enabled auto-merge (squash) June 25, 2026 05:04
@littledivy
littledivy merged commit 4068b5b into main Jun 25, 2026
136 checks passed
@littledivy
littledivy deleted the orch/divybot-584 branch June 25, 2026 05:24
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 throws TypeError when using wrapKey

2 participants