Context
Discovered while triaging #551 (native S3 client). The sigv4 signing path in @bradenmacdonald/s3-lite-client calls these three SubtleCrypto methods. Same shape every pure-JS AWS / Google / Azure signing lib uses (aws4fetch, jose, oidc-client-ts, web-push, every JWT HS256 signer).
Today these calls hit the #463 strict-API gate as an unimplemented Web API and refuse to compile.
Surface needed
crypto.subtle.digest("SHA-256", data: Uint8Array): Promise<ArrayBuffer>
crypto.subtle.importKey(
"raw",
key: Uint8Array,
algorithm: { name: "HMAC", hash: { name: "SHA-256" } },
extractable: false,
keyUsages: ["sign", "verify"],
): Promise<CryptoKey>
crypto.subtle.sign("HMAC", key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer>
digest and sign return Promise<ArrayBuffer>; importKey returns Promise<CryptoKey>. Consumers wrap the ArrayBuffer with new Uint8Array(buf), so spec-correctness on the return type matters.
Why this matters
- AWS SigV4 — S3, DynamoDB, Lambda invoke, every signed AWS REST request
- Google Cloud signed URLs, Azure SAS tokens
- OAuth signing, OIDC, JWT (HS256 / HS384 / HS512)
- Web Push (VAPID)
Every pure-JS S3 client (s3-lite, aws4fetch, minio-js without lodash) routes through crypto.subtle. Without this, perry.compilePackages can't pull in any of them.
Implementation notes
Thin async wrappers over existing internal SHA-256 / HMAC primitives in crates/perry-runtime/src/ (js_sha256, js_hmac already exist per the bcrypt / @noble/hashes wiring). The async aspect is decorative since these are CPU-bound — resolve synchronously inside the Promise body.
CryptoKey can be an opaque heap object holding the raw key bytes + algorithm name; sign/verify reads it back. No need to honor extractable: false or keyUsages: [...] strictly — Web Crypto enforces those at runtime, but Perry's threat model can treat them as documentation.
Verify: verify("HMAC", ...) is the natural symmetric of sign and worth landing in the same change so JWT validation works.
Out of scope
- Asymmetric algorithms (
RSA-PSS, ECDSA, RSA-OAEP) — those need bigint+EC primitives that aren't in-tree yet
generateKey, wrapKey, unwrapKey, deriveKey
crypto.subtle.encrypt / decrypt
Acceptance
signing.ts:317-330 from @bradenmacdonald/s3-lite-client (the sha256hmac helper) compiles and the resulting bytes match Node's WebCrypto byte-for-byte against the AWS SigV4 test vectors at https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
Refs #551 #463
Context
Discovered while triaging #551 (native S3 client). The sigv4 signing path in
@bradenmacdonald/s3-lite-clientcalls these three SubtleCrypto methods. Same shape every pure-JS AWS / Google / Azure signing lib uses (aws4fetch, jose, oidc-client-ts, web-push, every JWT HS256 signer).Today these calls hit the #463 strict-API gate as an unimplemented Web API and refuse to compile.
Surface needed
digestandsignreturnPromise<ArrayBuffer>;importKeyreturnsPromise<CryptoKey>. Consumers wrap the ArrayBuffer withnew Uint8Array(buf), so spec-correctness on the return type matters.Why this matters
Every pure-JS S3 client (s3-lite, aws4fetch, minio-js without lodash) routes through
crypto.subtle. Without this,perry.compilePackagescan't pull in any of them.Implementation notes
Thin async wrappers over existing internal SHA-256 / HMAC primitives in
crates/perry-runtime/src/(js_sha256,js_hmacalready exist per the bcrypt / @noble/hashes wiring). The async aspect is decorative since these are CPU-bound — resolve synchronously inside the Promise body.CryptoKeycan be an opaque heap object holding the raw key bytes + algorithm name;sign/verifyreads it back. No need to honorextractable: falseorkeyUsages: [...]strictly — Web Crypto enforces those at runtime, but Perry's threat model can treat them as documentation.Verify:
verify("HMAC", ...)is the natural symmetric ofsignand worth landing in the same change so JWT validation works.Out of scope
RSA-PSS,ECDSA,RSA-OAEP) — those need bigint+EC primitives that aren't in-tree yetgenerateKey,wrapKey,unwrapKey,deriveKeycrypto.subtle.encrypt/decryptAcceptance
signing.ts:317-330from@bradenmacdonald/s3-lite-client(thesha256hmachelper) compiles and the resulting bytes match Node's WebCrypto byte-for-byte against the AWS SigV4 test vectors at https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.htmlRefs #551 #463