Skip to content

v2.0.0 - TypeScript rewrite, native `node:crypto` fast paths, security audit fixes

Latest

Choose a tag to compare

@rzcoder rzcoder released this 24 May 01:41
· 4 commits to master since this release

Full TypeScript rewrite of v1 with the same public API. The node bundle now routes RSA primitives through node:crypto whenever possible; the browser bundle defaults to native BigInt.

See CHANGELOG.md for the full list and MIGRATION.md for upgrade guidance.

Highlights

Performance

  • Keygen via crypto.generateKeyPairSync — 2048-bit drops from ~2.3 s to ~50 ms (~45× faster).
  • PKCS#1 v1.5 / PSS sign+verify via crypto.sign/crypto.verify — PSS-SHA256 sign on 2048-bit drops from ~17 ms to sub-millisecond.
  • Browser bundle uses native BigInt — ~4–5× faster than jsbn on PSS sign/verify. Falls back to jsbn on pre-2020 runtimes.

Security fixes (no API change)

  • Constant-time OAEP decode (closes Manger padding-oracle), PKCS#1 v1.5 decode (Bleichenbacher/ROBOT), and PSS verify.
  • Private-key operations are blinded (Kocher / Brumley-Boneh defence).
  • Miller-Rabin uses CSPRNG witnesses with FIPS 186-4 round counts (was Math.random() over a fixed 168-element table).
  • Imported private keys are CRT-consistency-checked — closes a Boneh-DeMillo-Lipton fault-injection vector.
  • Hardened PKCS#8 / OpenSSH parsers; public-exponent and RSA-primitive bounds checks per RFC 8017.
  • generate(B) refuses B < 512 and warns below 2048; Fermat-distance defence on |p − q|.

Breaking changes

  • Min Node.js is now 20.
  • ESM-first with dual ESM/CJS via package.json#exports.
  • Browser default return type is Uint8Array (was a Buffer polyfill); Node still returns Buffer.
  • Browser bundle has zero Node-builtin imports — no Buffer/crypto shims, CI-enforced.
  • Default signing scheme switched from pkcs1 to pss (RFC 8017 / NIST best practice). Pass signingScheme: 'pkcs1' to keep v1 behaviour. Bare sha256 shorthand now resolves to pss-sha256.
  • MD4 is Node-only and provider-gated (OpenSSL 3 no longer loads the legacy provider by default).
  • Native PKCS#1 v1.5 privateDecrypt falls back to JS engine on modern Node (security-deprecated upstream); plaintext is byte-identical.
  • Custom MGF for PSS throws on the node bundlenode:crypto only supports MGF1 with hash equal to signing hash.
  • setOptions({environment}) is a deprecated no-op (still forces JS engine when set to 'browser').
  • asn1 npm dependency removed — replaced by an in-tree ~150-line DER reader/writer; byte-identical output.

Added

  • TypeScript types for every public surface.
  • @noble/hashes runtime dependency (~6 KB gzipped, audited).
  • CI-enforced bundle size budget: browser <100 KB raw / <30 KB gzipped; node <120 KB raw / <35 KB gzipped.

Internal

  • Modern tooling: tsup, vitest, biome, strict TypeScript.
  • 1006 test cases across 27 files; the v1 mocha suite (61 it() blocks) is ported verbatim and runs in both node and browser-emulated vitest projects.