Hand-rolled wrappers around node:crypto. Most Node services need a small subset — encrypt-at-rest, sign webhooks, generate API tokens — and most reinvent the wrappers. This package provides them, audited, tested, and byte-for-byte compatible with the Go counterpart.
You can. But Node's Cipher API is mutable-builder-pattern, which has a notorious foot-gun: forgetting to concatenate update() and final() outputs. The buggy aitoolscrypt.ts sibling that motivated this package made exactly that mistake. The clean wrapper API removes the foot-gun.
No, this targets Node.js (node:crypto only). A browser/WebCrypto build is on the future roadmap. For now, decrypt server-side and send plaintext over HTTPS.
Not directly — those runtimes don't ship node:crypto. They use WebCrypto, which has a different API. Use the package on the Node side; if you need Edge crypto, use WebCrypto directly.
Vercel Serverless functions (Node.js runtime) work fine. AWS Lambda Node runtime works fine.
Password hashing belongs server-side, and "server-side" in our typical setup means the Go service. If a Node service genuinely needs to hash passwords, pull in the argon2 npm package directly. We don't ship it under this brand because we want a single, well-tuned implementation in Go.
JWT has well-documented foot-guns: alg=none, algorithm confusion. Our examples/session-token shows the same stateless-token shape (small payload + expiry) using seal directly — no JOSE header, no algorithm negotiation. If you need real JWT, use @panva/jose.
You lose the data. There is no recovery. Operationally:
- Store keys in a secrets manager (AWS Secrets Manager, Vercel env vars marked Sensitive, etc.).
- Have a rotation policy so any single key loss doesn't lose all data.
- Don't store keys in source-controlled
.envfiles.
Yes. All public functions accept Buffer | Uint8Array for keys, AAD, and binary plaintext. Buffer is preferred internally for ergonomics; the function will convert if needed.
Failed signature isn't an exceptional condition — it's a normal outcome the caller is checking for. if (!verify(...)) abort is cleaner than try { verify() } catch. open does throw because it has multiple distinct failure modes.
See BENCHMARKS.md for real numbers. Short version: AEAD seal/open at 150-300k ops/sec, sign/verify at 350-400k ops/sec. Network/DB will bottleneck your service before crypto.
The class binds the key once at construction; the free function takes the key per call. Use Sealer in long-running services, free functions in scripts and one-shots.
Up to a few hundred MB with the buffer-based approach in examples/encrypted-file. Streaming AEAD for arbitrary-size files is on the v1.2 roadmap.
The legacy subpath holds backward-compat shims for AES-CBC ciphertext. The two-import-path pattern makes it easy to grep @ubgo/crypt/legacy to find every site that needs to be migrated to AEAD.
Inject a Sealer constructed with a fixed test key:
import { Sealer } from "@ubgo/crypt"
const sealer = new Sealer(Buffer.alloc(32, 0x01)) // deterministic test key
const svc = new Service(sealer)The package itself has no I/O; nothing to mock. Just call the real functions.
Yes. We compile under strict: true, noUncheckedIndexedAccess: true, and other strict flags. All public types are non-any.
Yes. We ship dual ESM + CJS via tsup. Both import { seal } from "@ubgo/crypt" (ESM) and const { seal } = require("@ubgo/crypt") (CJS) work.
Bun: yes, fully compatible with node:crypto.
Deno: works under the Node compatibility layer (npm:@ubgo/crypt). Native Deno crypto has a different API; we're not yet a first-class Deno package.
Yes. That's the entire point. Both sides target the same wire format, validated by shared test vectors in CI.
// Decrypt something Go's crypt.Seal produced:
import { open } from "@ubgo/crypt"
const pt = open(sharedKey, ciphertextFromGo)Open a private GitHub security advisory: https://github.com/ubgo/crypt-ts/security/advisories/new
We aim to acknowledge within 48 hours and patch P0 issues within 7 days.
The Go counterpart has SECURITY.md, WIRE_FORMAT.md, and USAGE.md covering the design in depth. They apply equally to this package. Read github.com/ubgo/crypt for the long form.