Skip to content

1.7.0 Update#25

Merged
ljoy913 merged 42 commits into
masterfrom
ljoy/update-build-dependencies
Jun 28, 2026
Merged

1.7.0 Update#25
ljoy913 merged 42 commits into
masterfrom
ljoy/update-build-dependencies

Conversation

@ljoy913

@ljoy913 ljoy913 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

MSR JavaScript Crypto 1.7.0

A spec-alignment, packaging, and test-coverage release that moves the
SubtleCrypto surface closer to the W3C Web Crypto contract while keeping
IE8+ compatibility.

Highlights

  • Spec-compliant errors — invalid input and unsupported algorithms now
    produce rejected promises (not synchronous throws) as real DOMExceptions
    with spec names (NotSupportedError, OperationError, DataError,
    TypeError, …), falling back to a named Error on engines without
    DOMException (IE8).
  • String AlgorithmIdentifier support — accepts "SHA-256" as well as
    { name: "SHA-256" }.
  • TypeScript declarations rewritten to describe the real MsrCrypto surface
    and resolve for the @microsoft/msrcrypto import specifier.

Changed

  • getRandomValues throws QuotaExceededError past 65,536 bytes and
    TypeMismatchError for floating-point typed arrays.
  • Library version is injected from package.json at build time, ending bundle
    drift.
  • Repository layout: lib/dist/, definitions/types/, sources under
    src/. Installs by package name are unaffected; only deep import paths change.
  • Internal Promise rewritten so rejections propagate through then() calls that
    omit a rejection handler to a trailing catch().

Fixed

  • RSA generateKey now honors requested key usages (e.g. RSA-OAEP with
    ["wrapKey", "unwrapKey"]).
  • HMAC generateKey honors length correctly (bits, not bytes); AES
    generateKey rejects lengths other than 128/192/256.
  • Removed dead/unreachable code and a stray console.log during wrapKey;
  • fixed a worker path that wrote to read-only
    DOMException.code.

Testing & tooling

  • New Errors, Wrap Key, Promises, and CryptoKey test modules; IE8-safe
    auto-scroll in the test harness.
  • npm packaging metadata, prepublishOnly build guard, and a dormant
    provenance-publishing release workflow.

Compatibility

  • Still targets IE8+.
  • Potentially breaking: callers relying on synchronous throws, plain Error
    objects, or deep lib//definitions/ paths must adjust.

ljoy913

This comment was marked as outdated.

Comment thread package.json
Comment thread build.mjs Outdated
Comment thread build.mjs
ljoy913 added 25 commits June 17, 2026 14:17
… pre-cromium IE's leading-zeros-trimmed variable lengths
- HMAC generateKey: honor the optional length parameter in bits and zero the unused trailing bits of the final byte so exported keys match native WebCrypto for non-byte-aligned lengths.

- AES generateKey (CBC/GCM/KW): reject key lengths other than 128, 192, or 256 bits instead of accepting any multiple of 8.

- Add HMAC optional-length QUnit test (IE8-safe: plain for-loop and testShared.toArray instead of forEach/Uint8Array).
- Add IE8-safe utilities.indexOf (Array.prototype.indexOf is IE9+).

- Target IE=8 document mode via X-UA-Compatible meta in SubtleTests.html.

- Remove dead commented-out code in jwk.js.
- package.json: add keywords, author, homepage, bugs, exports map, sideEffects, publishConfig.access=public, and a prepublishOnly build guard.

- build.mjs: inject the version from package.json into the bundle so msrCryptoVersion can't drift from the published version.

- Add dormant tagged-release GitHub Actions workflow that builds, verifies the package, and publishes to npm with provenance.

- Add CHANGELOG.md and move the version history out of README into it.
- Inline the scripts/subtle/* files directly into the full bundle list instead of pre-concatenating them into an intermediate scripts/subtle.js. The msrcryptoSubtle IIFE scope is preserved by concatenation order (head.js ... tail.js); build output is byte-identical.

- Remove the now-unused generated scripts/subtle.js (was erroneously tracked) and its .gitignore entry.

- Tidy .gitignore: drop the Local History (.history) ignore, fix the outdated gulp comment, and broaden .DS_Store.
- Move library source from scripts/ to src/ (the conventional source folder).

- Move QUnit test files into the root tests/ folder alongside the HTML harnesses.

- Move test vectors into the root testVectors/ folder.

- Move the vendored QUnit library to tests/vendor/.

- Update build.mjs, the three test HTML harnesses, and README build docs to the new paths. Build output is byte-identical; SubtleTests.html runs green.
- Remove src/kdf.js: an unreferenced older copy of the Concat KDF (NIST SP 800-56A); the shipped implementation is src/concat.js.

- Fix concat.js header comment that wrongly cited RFC 5869 (HKDF); it implements the NIST SP 800-56A Concat KDF.
Unreferenced superseded copy; the active curve definitions are in src/curves_NUMS.js.
src/testInterface.js was never included in the build and not loaded by any test page; its only consumer was a debug-block guard in bundleTail.js (stripped from the bundle). Removed both.
- definitions/msrcrypto.intellisense.js: legacy Visual Studio JS IntelliSense artifact, superseded by msrCrypto.d.ts (was being published).

- tests/CryptoECCTests.html and tests/CryptoMathTests.html: non-functional harnesses referencing CryptoTest.*.js files that no longer exist.
Built files are lib/msrcrypto.js and lib/msrcrypto.min.js (lowercase), not msrCrypto.*.
Shorter folder name; updated the test vector paths in SubtleTests.html. All 16 vector files moved via git mv (history preserved).
types/ is the conventional folder name for .d.ts files. Updated the types, exports, and files fields in package.json.
- vectors/ -> tests/vectors/ (test fixtures belong with the test harness; not published)

- lib/ -> dist/ (conventional name for the bundled distributable)

Updated paths in package.json (main/exports/sideEffects/files), build.mjs output constants, README, and SubtleTests.html.
- msrCrypto.d.ts: make the package entry a real module (top-level 'export ='), so 'import ... from "@microsoft/msrcrypto"' resolves; keep the Crypto/StreamObject augmentations global via 'declare global'.

- Use primitive 'string' instead of boxed 'String' for bytesToText.

- Return concrete number[] (not ArrayLike<number>) from fromBase64/textToBytes.

- IE11PromiseWrapper.d.ts: fix identifier typo (ieE11PromiseWrapper -> ie11PromiseWrapper) and missing semicolon.
- Describe the library's own object shape (MsrCrypto) instead of augmenting the global Crypto interface, so importing no longer pollutes platform crypto types.

- Type the full public surface that was previously missing: subtle, getRandomValues, asn1, url, version, useWebWorkers, Promise, CryptoKey.

- Wire up StreamObject: encrypt/decrypt/sign/verify/digest have streaming overloads (data omitted -> Promise<StreamObject>).

- Add MsrAlgorithm covering the custom params (iv, salt, namedCurve, additionalData, tagLength, info, iterations, stream, ...) with array-friendly ByteSource inputs.

- Type asn1 (parse/encode/toString) and export the helper types via the namespace merge. Verified with tsc --strict.
The W3C AlgorithmIdentifier is (object or DOMString), so subtle.digest("SHA-256", data) is valid in the platform API. buildParameterCollection now normalizes a string top-level algorithm to { name } (mirroring the existing normalization of the nested hash field) before the type check.

Types: algorithm params widened to MsrAlgorithmIdentifier (string | MsrAlgorithm).

Verified: digest("SHA-256","abc") returns the correct hash and matches the object form; SHA2 suite 892/892.
- Wrap executeOperation setup so parameter/algorithm errors are surfaced as a
  rejected promise, matching the WebCrypto contract (subtle methods never throw
  synchronously); fixes subtle.encrypt(...).catch(...) style error handling.

- Remove a stray console.log that leaked exported key material on every wrapKey.
- utils.error now returns a DOMException with the spec name (Error+name/code
  fallback where no DOMException constructor exists, e.g. IE8).

- Route subtle/module error sites to spec names: NotSupportedError,
  InvalidAccessError, DataError, OperationError; argument errors throw TypeError.

- getRandomValues throws QuotaExceededError past 65,536 bytes and
  TypeMismatchError for floating-point typed arrays.

- Fix worker error path that threw assigning the read-only DOMException.code.
- New Errors module asserts subtle methods reject (never throw synchronously)
  with the correct DOMException names: NotSupportedError, OperationError,
  InvalidAccessError, DataError, plus TypeError for missing arguments.

- Covers getRandomValues QuotaExceededError / TypeMismatchError and the
  valid fill-in-place path. Wired Test.Errors.js into SubtleTests.html.
The CryptoKey test module existed but was never loaded, so its 6 tests
never ran. Include it after Test.Encoding.js.
ljoy913 added 8 commits June 25, 2026 13:40
Explain that 1.23.1 is the last QUnit version supporting IE8 and must not be upgraded, and why it is committed rather than loaded from a CDN.
Bump version to 1.7.0 and record this release's changes in the changelog: string AlgorithmIdentifier support, reject-not-throw, DOMException error parity, getRandomValues quota/type checks, the type-declarations rewrite, repository layout moves, and the new error/CryptoKey tests.
Regenerate dist/msrcrypto.js and dist/msrcrypto.min.js from src with the 1.7.0 version stamp and all WebCrypto-parity changes.
Use the singular test/ directory name and update the lone path reference in the publish workflow comment. All references inside the harness are relative and unaffected.
Drop three unused 'msrcryptoKdfInstance'/'msrcryptoConcatKdfInstance = null' assignments and several non-debug commented-out code snippets (jwk findUsage, rsa-base old modExp, hkdf-ctr label guard). Rename jwk keyToJwkOld to keyToJwkBytes to reflect that it returns a serialized JWK byte array (distinct from keyToJwk, which returns an object) rather than implying it is an outdated version.
- Delete the unreachable msrcryptoWrapKey module (src/wrapKey.js): its
  operations.register("wrapKey"/"unwrapKey") handlers were never dispatched,
  since executeOperation is only ever called with encrypt/decrypt/sign/verify/
  digest/generateKey/deriveBits/importKey/exportKey.

- Public subtle.wrapKey/unwrapKey remain fully functional via the standard
  exportKey+encrypt / decrypt+importKey composition in subtleInterface.js.

- Drop src/wrapKey.js from the build.mjs fullBuild list.

- Remove the now-orphaned keyToJwkBytes serializer and its stringToArray
  helper from src/jwk.js (keyToJwk/jwkToKey are unaffected).

- Remove the dead wrapKey/unwrapKey entries from subtleParametersSets and the
  dead operationName === "wrapKey" branch in executeOperation.
- msrcryptoRsa.generateKeyPair previously ignored the caller's requested
  usages (the usages: null || ... was a dead no-op) and forced a fixed pair,
  unlike AES/ECDH/ECDSA and RSA importKey which preserve p.usages.

- It now filters the requested usages into the half each applies to:
  verify/sign for RSASSA-PKCS1-v1_5 and RSA-PSS; encrypt/wrapKey (public) and
  decrypt/unwrapKey (private) for RSA-OAEP/RSAES. Defaults to all valid usages
  when none are requested.

- Fixes generating an RSA-OAEP key with ["wrapKey","unwrapKey"] producing a
  key that could not be used with subtle.wrapKey (rejected InvalidAccessError).
- Auto-run tests on load so QUnit's native UI (and module picker) render

- Inject a Stop button into QUnit's toolbar next to the native module picker

- Stop aborts the in-progress run by clearing QUnit's task queue, leaving the native UI in place to select and run a specific module

- Stop is enabled only while a run is in progress
@ljoy913 ljoy913 changed the title Update build scripts and dependencies 1.7.0 Update Jun 25, 2026
ljoy913 added 2 commits June 25, 2026 21:40
- Rewrite Promise implementation (promises.js) to a single state-machine queue so rejections propagate through then() calls without a rejection handler to a trailing catch()
- RSA key usage filtering uses IE8-safe loops and msrcryptoUtilities.indexOf instead of Array.prototype.filter/indexOf
- Add modern Wrap Key QUnit module (AES-KW, AES-CBC, AES-GCM raw/jwk, RSA-OAEP round-trips) replacing the legacy IE11-only interop file
- Add Test.Promise.js coverage
- getRandomValues error tests guard TypedArray usage with regular-array fallbacks for IE8
- Add IE8-safe 'tail -f' auto-scroll to SubtleTests.html runner
- Rebuild dist bundles
- Validate dynamic operation/algorithm dispatch in the worker using own-property (hasOwnProperty) and function-type checks so user-controlled names cannot reach inherited Object.prototype members (resolves CodeQL unvalidated dynamic method call).
- Replace the stack-trace parsing regex in global.js with a non-backtracking pattern (resolves CodeQL ReDoS).
- Remove dead code and add fs.watch recursive fallback in build.mjs.
- Bump publish workflow to actions/checkout@v5, setup-node@v5, Node 22.
@ljoy913 ljoy913 force-pushed the ljoy/update-build-dependencies branch from b8c7e7d to 3bce2b1 Compare June 26, 2026 16:10
@ljoy913 ljoy913 requested a review from zaverucha June 27, 2026 14:02
ljoy913 added 2 commits June 27, 2026 07:03
The e.data guard used a falsy check, so a legitimate falsy result (verify
posts boolean false on signature mismatch) was treated as an empty message
and dropped, leaving the operation promise unsettled. Use a null/undefined
check so falsy-but-valid results still complete the operation.
Compute the fixed-window width for modExp from a precomputed threshold
table instead of an iterative cost-minimization loop. The previous model
omitted the constant-time getTableEntry scan term and so over-sized the
window (selecting 5/6/6 for RSA-1024/2048/4096 signing); the corrected
cost model now picks 3/4/5. Thresholds are documented with the model
they were derived from and verified against RSA-1024/2048/4096 signing.

@zaverucha zaverucha left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I made a PR against this branch to fix an issue I spotted, if that looks good to you please merge it.

Otherwise than that this PR looks good.

@ljoy913 ljoy913 merged commit 65d3b12 into master Jun 28, 2026
3 checks passed
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.

3 participants