Docs / Packages / @zudojs/crypto
v1.3.0

@zudojs/crypto

Safe defaults for hashing, AES-256-GCM encryption, scrypt password storage, Ed25519 signatures, opaque tokens and secure random values, all backed by node:crypto.

CRYPTOGRAPHY ENCRYPTION HASHING PASSWORDS TOKENS SIGNATURES

OVERVIEW

Node.js already ships a crypto module, but it lets you pick weak algorithms, short keys and bad parameters without complaint. @zudojs/crypto wraps it with one good choice per job and rejects the rest at runtime. You call hashPassword and get scrypt with OWASP parameters; you call encrypt and get AES-256-GCM with a fresh random IV.

Three words come up constantly on this page. Hashing turns data into a fixed-size fingerprint that cannot be turned back into the data. Encryption scrambles data with a key so that only someone holding the same key can read it again. Signing proves that a message came from the holder of a private key and was not changed on the way.

Every function is async and talks to node:crypto through a provider. A provider is just an object that implements the raw operations; the default one is created for you, and you can swap it in tests.

When you need it
  • Storing user passwords and checking them at login
  • Issuing API keys, session or reset tokens and storing only their hash
  • Encrypting a secret before it goes into a database
  • Signing a payload so another service can verify it
  • Random codes, IDs or bytes that must be unpredictable
When you don't
  • You need JWTs or a login flow: use @zudojs/auth, which builds on this package
  • You need bcrypt, Argon2, ChaCha20 or AES-CBC: they are deliberately not implemented
  • You need Math.random()-style values for a game or a shuffle: plain JavaScript is fine

INSTALLATION

Install the package. Its two dependencies, @zudojs/constants and @zudojs/errors, come along automatically. Node.js 24 or newer is required.

$ npm install @zudojs/crypto
Note: These docs follow the framework source. If an export shown here is missing from the version you installed, update to the latest @zudojs release.

QUICK START

This is the package's own smoke test: hash a string, store and check a password, encrypt and decrypt a secret, then mint a session token. Save it as quick.ts and run it.

import { hash, hashPassword, verifyPassword, randomBytesSecure, encryptEnvelope, decryptEnvelope, generateToken, } from "@zudojs/crypto"; // 1. Hash: same input always gives the same fingerprint. const digest = await hash("hello", { algorithm: "sha256", encoding: "hex" }); console.log(digest.encoded); // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 // 2. Password: store `encoded`, never the password itself. const stored = await hashPassword("correct horse battery staple"); const ok = await verifyPassword("correct horse battery staple", stored.encoded); console.log(ok); // true // 3. Encrypt: a 32-byte key, a portable string in, the bytes back out. const key = await randomBytesSecure(32); const envelope = await encryptEnvelope(new TextEncoder().encode("secret"), key); const plaintext = await decryptEnvelope(envelope, key); console.log(new TextDecoder().decode(plaintext)); // secret // 4. Token: 32 random bytes, base64url, with a prefix. const sessionToken = await generateToken({ bytes: 32, prefix: "sess_" }); console.log(sessionToken); // sess_ followed by 43 random characters

The hex digest is always the same for "hello". Everything else (the password hash, the envelope, the token) is different on every run because each one starts from fresh random bytes.

Danger: Three things this package will not let you do, on purpose.
  • Do not invent your own scheme. Only SHA-2, SHA-3, HMAC, AES-256-GCM, scrypt, PBKDF2 and Ed25519/RSA/ECDSA signatures exist here. Ask hash for "md5" or "sha1" and it throws TypeError: Unsupported hash algorithm.
  • Do not reuse an IV. An IV (also called a nonce) is the random 12-byte value that makes each encryption unique. Leave it out and encrypt draws a fresh one every call. Reusing one under the same key leaks your plaintexts; a wrong-sized one is rejected with ERR_CRYPTO_CIPHER.
  • Do not store plain passwords. Store the encoded string that hashPassword returns and check with verifyPassword. A plain sha256 of a password is not a password hash: it is fast enough to brute-force.

HASHING AND HMAC

A hash is a fixed-size fingerprint of some data. The same input always produces the same output, and you cannot recover the input from it. Use it to fingerprint files, deduplicate content, or store a lookup key for a token.

Call hash for the full result, or a shorthand such as sha256 when you only want the encoded string. Both accept a string, a Uint8Array or an ArrayBuffer.

import { hash, sha256, sha512 } from "@zudojs/crypto"; const result = await hash("hello world", { algorithm: "sha256", encoding: "hex" }); console.log(result.algorithm); // sha256 console.log(result.digest.length); // 32 (raw bytes) console.log(result.encoded); // b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 const short = await sha256("hello world"); // same hex string as above const b64 = await sha512("hello world", "base64"); // 88-character base64 string

Supported algorithms are sha256, sha384, sha512, sha3-256, sha3-384 and sha3-512. Encodings are hex (default), base64 and base64url.

HMAC: a hash with a secret

An HMAC is a hash mixed with a secret key. Anyone can compute a plain hash, but only someone holding the key can compute the matching HMAC, so it proves a message was not tampered with. The key must be at least 16 bytes.

import { hmacSha256, randomBytesSecure, timingSafeEqualString } from "@zudojs/crypto"; const key = await randomBytesSecure(32); // keep this secret; 16 bytes minimum const tag = await hmacSha256("order:42:paid", key); console.log(tag.length); // 64 (hex) // Later, on the receiving side, recompute and compare in constant time. const again = await hmacSha256("order:42:paid", key); console.log(timingSafeEqualString(tag, again)); // true
Watch out: Compare hashes and tags with timingSafeEqualString (strings) or timingSafeEqual (bytes), never with ===. A normal comparison stops at the first different character, and that timing difference can be measured by an attacker.

ENCRYPTION

Encryption scrambles data with a key so it can be unscrambled later by anyone holding the same key. This package uses AES-256-GCM, which also detects tampering: if one byte of the ciphertext is changed, decryption fails instead of returning garbage.

The key must be exactly 32 bytes. Generate one with randomBytesSecure(32) and keep it outside your code, for example in an environment variable encoded as hex.

Envelopes: the easy path

An envelope is one string that bundles the IV, the authentication tag and the ciphertext, so you can store it in a single database column. This example encrypts a string and gets it back.

import { encryptEnvelope, decryptEnvelope, randomBytesSecure } from "@zudojs/crypto"; const key = await randomBytesSecure(32); const bytes = new TextEncoder().encode("secret"); const envelope = await encryptEnvelope(bytes, key); console.log(envelope); // v1.aes-256-gcm.nd6CpdgPlb62b7gQ.YvsWCo8Wh5N5O63sAO00dg.KfQcUkfn const plaintext = await decryptEnvelope(envelope, key); console.log(new TextDecoder().decode(plaintext)); // secret

The envelope format is v1.aes-256-gcm.iv.authTag.ciphertext, each binary part in base64url. Your envelope will differ from the one shown because the IV is random every time.

Pieces: when you store fields separately

encryptString returns the three parts as bytes so you can store them in separate columns. decryptString takes them back in the same order.

import { encryptString, decryptString, randomBytesSecure } from "@zudojs/crypto"; const key = await randomBytesSecure(32); const result = await encryptString("hello world", key); console.log(result.algorithm, result.iv.length, result.authTag.length); // aes-256-gcm 12 16 const plain = await decryptString(result.ciphertext, key, result.iv, result.authTag); console.log(plain); // hello world

Use encrypt and decrypt for raw Uint8Array data; they have the same shape. The optional aad option binds extra unencrypted context (such as a user ID) to the ciphertext, so it will not decrypt under a different context.

Common mistake: decrypting with the wrong key, a wrong IV or a tampered envelope all throw a CryptoError with code ERR_CRYPTO_CIPHER and message Decryption failed. Catch it and treat it as "this data is not for this key", not as a bug.

PASSWORD HASHING

A password hash is a deliberately slow hash with a random salt mixed in. Slow means an attacker who steals your database can only try a few guesses per second. The salt means two users with the same password get different hashes.

This package uses scrypt with OWASP defaults (cost 16384, block size 8, parallelization 5, 16-byte salt, 32-byte output; new hashes must use cost ≥ 16384 (PASSWORD_HASH.SCRYPT.MIN_COST, checked by assertNewHashCost), older stored hashes still verify). The result is one self-describing string that starts with v1$scrypt$, so you can raise the cost later and old hashes still verify.

import { hashPassword, verifyPassword } from "@zudojs/crypto"; // At sign-up: hash and store `encoded`. const result = await hashPassword("correct horse battery staple"); console.log(result.encoded); // v1$scrypt$16384$8$5$4P7WMta8PUwwfejUzMN_6w.SL0oONhRA2hbSwz4nKfcb1i4MbDy6mYyKy4KaDAbni0 console.log(result.cost, result.blockSize, result.parallelization); // 16384 8 5 // At login: verify against the stored string. console.log(await verifyPassword("correct horse battery staple", result.encoded)); // true console.log(await verifyPassword("wrong password", result.encoded)); // false console.log(await verifyPassword("anything", "not-a-hash")); // false

verifyPassword never throws over its inputs. A wrong password, a malformed stored string, or a hash with out-of-range parameters all return false. The one exception is configuration: since 1.3.0 it throws a CryptoError if the provider does not declare the passwordHashing capability, rather than reporting a provider that cannot hash as a wrong password. Passwords longer than 1024 characters are also rejected so an attacker cannot make your server grind on huge input.

To make hashing slower, pass options. cost must be a power of two.

const stronger = await hashPassword("correct horse battery staple", { cost: 32768 }); console.log(stronger.encoded.startsWith("v1$scrypt$32768$")); // true
Watch out: isValidPassword(password) only checks length (8 characters by default). It is a convenience for form validation, not a strength meter.

DIGITAL SIGNATURES

A signature proves that a message came from whoever holds a private key and was not altered. Anyone with the matching public key can check it, but nobody can forge it. Use it for webhooks, signed URLs, or any payload that crosses a trust boundary.

The default algorithm is Ed25519. Generate a key pair once, export both halves as PEM text, and keep the private one secret. PEM is the familiar -----BEGIN PRIVATE KEY----- text format.

import { generateEd25519KeyPair, exportPrivateKeyPem, exportPublicKeyPem, signString, verifyString, } from "@zudojs/crypto"; // One-time setup. Store privatePem somewhere secret; publish publicPem. const { privateKey, publicKey } = generateEd25519KeyPair(); const privatePem = exportPrivateKeyPem(privateKey); const publicPem = exportPublicKeyPem(publicKey); console.log(publicPem); // -----BEGIN PUBLIC KEY----- // MCowBQYDK2VwAyEAXEBPyK/UOMLZ9MJfwuCVQ5ZRtx5UMJUqG728xdCKXS8= // -----END PUBLIC KEY----- // Sender: sign the message. const signature = await signString("hello", privatePem); console.log(signature.length); // 64 // Receiver: verify with the public key. console.log(await verifyString("hello", signature, publicPem)); // true console.log(await verifyString("hell0", signature, publicPem)); // false

sign and verify do the same for Uint8Array data. Keys may be PEM text, DER bytes, or a Node KeyObject. RSA (rsa-sha256/384/512) and ECDSA (ecdsa-sha256/384/512) are available through the algorithm option when you already hold such keys; random bytes are never a valid signing key.

Watch out: the algorithm must match the key type. Passing an Ed25519 key with algorithm: "rsa-sha256" throws. A malformed key or signature makes verify return false rather than throw.

OPAQUE TOKENS

An opaque token is a long random string that means nothing by itself; your database maps it to a user or session. API keys, session cookies, password-reset links and CSRF tokens are all opaque tokens. The minimum is 16 random bytes (128 bits); the default is 32.

The typed generators add a recognisable prefix so tokens are easy to spot in logs and secret scanners. Store only the SHA-256 hash of a token; if the database leaks, the attacker still cannot use it.

import { generateApiKey, generateSessionToken, generateOtp, hashToken, verifyTokenHash, } from "@zudojs/crypto"; const apiKey = await generateApiKey(); console.log(apiKey); // lat_n8bvekncI8qxzm4iOavHpMzdp5QC2OKJ9uzNcKu5048 // Give the raw key to the user once; store only its hash. const storedHash = await hashToken(apiKey); console.log(storedHash.length); // 64 (hex SHA-256) // On each request, look up by hash and compare in constant time. console.log(await verifyTokenHash(apiKey, storedHash)); // true console.log(await verifyTokenHash("lat_wrong", storedHash)); // false console.log(await generateSessionToken()); // sess_ followed by 43 random characters console.log(await generateOtp()); // 114575 (6 digits, leading zeros kept)

Other generators follow the same pattern: generateRefreshToken (ref_), generateVerificationToken (verify_), generatePasswordResetToken (reset_) and generateCsrfToken (csrf_). generateToken({ bytes, encoding, prefix }) is the general form.

Tip: TOKEN_TTL exports sensible lifetimes in milliseconds (for example TOKEN_TTL.PASSWORD_RESET_MS is 15 minutes). The package does not track expiry for you; store an expiresAt column next to the hash.

SECURE RANDOM

Math.random() is predictable and must never be used for anything secret. These helpers draw from the operating system's cryptographic random source and are safe for keys, salts, codes and IDs.

import { randomBytesSecure, randomHex, randomInteger, randomUuid, randomNumericCode, randomAlphanumeric, randomChoice, } from "@zudojs/crypto"; const bytes = await randomBytesSecure(32); console.log(bytes.length); // 32 console.log(await randomHex(16)); // 16 hex characters console.log(await randomInteger(1, 7)); // 1, 2, 3, 4, 5 or 6 (max is excluded) console.log(await randomUuid()); // a UUID v4 such as 550e8400-e29b-41d4-a716-446655440000 console.log(await randomNumericCode(6)); // 6 digits, leading zeros kept console.log(await randomAlphanumeric(8)); // 8 letters or digits console.log(await randomChoice(["red", "green", "blue"])); // one of the three

randomInteger(min, max) is uniform (no bias toward low numbers) for ranges up to 248. Character helpers draw each character independently, so leading zeros in numeric codes are kept.

KEY DERIVATION

Key derivation stretches a human-typed passphrase into a fixed-length key you can use for encryption. It is the same slow-hash idea as password hashing, but the output is the key bytes rather than a stored string. If you only need to check a password, use hashPassword instead.

This derives a 32-byte AES key from a passphrase with PBKDF2-SHA256 (600 000 iterations by default). Keep the returned salt: you need the same salt to derive the same key again.

import { derivePbkdf2, encryptEnvelope, timingSafeEqual } from "@zudojs/crypto"; const first = await derivePbkdf2("my passphrase", { keyLength: 32 }); console.log(first.algorithm, first.key.length, first.salt.length); // pbkdf2-sha256 32 16 const envelope = await encryptEnvelope(new TextEncoder().encode("secret"), first.key); // Later: same passphrase + same salt = same key. const again = await derivePbkdf2("my passphrase", { keyLength: 32, salt: first.salt }); console.log(timingSafeEqual(first.key, again.key)); // true

deriveScrypt(password, options) does the same with scrypt, and deriveKey(password, CryptoAlgorithm.SCRYPT, options) picks by enum. Salts must be at least 16 bytes; generateSalt() makes one. Cost, block size, parallelization, iterations and keyLength are capped by PASSWORD_HASH.LIMITS; out-of-range values throw before any derivation runs.

SERVICE AND PROVIDER

The loose functions above are all you need most of the time. Two wrappers exist for apps that prefer one object to pass around.

CryptoService bundles the common operations as methods and turns every failure into a CryptoError. CryptoFactory adds app-wide defaults (password cost, token encoding) on top of a service.

import { createCryptoService, createCryptoFactory, CryptoAlgorithm } from "@zudojs/crypto"; const service = createCryptoService(); const key = await service.generateKey(CryptoAlgorithm.AES_256_GCM); console.log(key.keyId, key.length); // key_ plus 32 hex characters, then 256 console.log(await service.hashHex("hello world")); // b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 const factory = createCryptoFactory({ password: { cost: 32768 }, encoding: "hex" }); const stored = await factory.createPasswordHash("correct horse battery staple"); console.log(stored.cost); // 32768 console.log(await factory.createToken(16, "tmp_")); // tmp_ + 32 hex characters

Swapping the provider in tests

A provider is the object that actually does the work; the default is createNodeCryptoProvider(). Every function accepts a provider option, or you can replace the process-wide default. This subclasses the real provider to count hash calls, then restores the default.

import { NodeCryptoProvider, setDefaultCryptoProvider, resetDefaultCryptoProvider, sha256, } from "@zudojs/crypto"; import type { HashAlgorithm, CryptoInput } from "@zudojs/crypto"; let hashCalls = 0; class CountingProvider extends NodeCryptoProvider { override async hash(algorithm: HashAlgorithm, data: CryptoInput): Promise<Uint8Array> { hashCalls += 1; return super.hash(algorithm, data); } } setDefaultCryptoProvider(new CountingProvider()); await sha256("a"); await sha256("b"); console.log(hashCalls); // 2 resetDefaultCryptoProvider();

Capabilities, and what a provider must implement

Every provider declares a capabilities object with seven boolean flags: hash, hmac, encryption, signing, random, keyDerivation and passwordHashing. Before 1.3.0 nothing read them — a provider declaring signing: false still had its sign called. Each flag is now checked at the operation that needs it, and an operation the configured provider does not declare is refused with a CryptoError naming both the capability and the operation. A capabilities object that is missing or malformed fails the same way a false flag does. A provider that declares every capability it implements is unaffected.

verifyPassword is part of this: it throws rather than reporting an undeclared passwordHashing capability as a wrong password, which would otherwise read as a failed login forever.

setDefaultCryptoProvider now validates the provider before installing it. All twelve methods listed in CRYPTO_PROVIDER_METHODSrandomBytes, randomInt, randomUUID, hash, hmac, encrypt, decrypt, sign, verify, deriveKey, hashPassword, verifyPassword — must be functions, and each of the seven capability flags must be a boolean. Anything else throws a CryptoError from that call and the provider is not installed; a non-object argument throws a TypeError. Previously a partial object such as {} installed cleanly and failed much later, as a bare TypeError from inside whichever operation reached the missing method first.

import { setDefaultCryptoProvider, isCryptoError } from "@zudojs/crypto"; import type { CryptoProvider } from "@zudojs/crypto"; try { setDefaultCryptoProvider({} as CryptoProvider); } catch (error) { if (isCryptoError(error)) { console.log(error.message); // Crypto provider is missing the "randomBytes" method: a provider // must implement all 12 operations. } }

The checks are exported for anyone writing their own provider or wrapper: assertCryptoProvider, assertProviderCapability, and the fixed-operation shorthands assertRandomCapability, assertHashCapability, assertHmacCapability and assertPasswordHashingCapability.

ERRORS

Cryptographic failures throw CryptoError from @zudojs/errors, re-exported here. It carries a stable code such as ERR_CRYPTO_CIPHER, an operation, and the original Node error as cause. Bad arguments (wrong algorithm name, short HMAC key) throw plain TypeError or RangeError instead.

import { decryptEnvelope, isCryptoError } from "@zudojs/crypto"; const wrongKey = new Uint8Array(32); const envelope = "v1.aes-256-gcm.nd6CpdgPlb62b7gQ.YvsWCo8Wh5N5O63sAO00dg.KfQcUkfn"; try { await decryptEnvelope(envelope, wrongKey); } catch (error) { if (isCryptoError(error)) { console.log(error.code, error.operation); // ERR_CRYPTO_CIPHER decrypt } }

The verify-style helpers are the exception: verifyPassword, verifyTokenHash and verify return false for bad input instead of throwing, so login code stays simple. That covers the input only — since 1.3.0 a provider that does not declare the capability an operation needs makes that operation throw a CryptoError, verifyPassword included, so a misconfigured provider is not mistaken for a wrong password.

API REFERENCE

Everything below is exported from @zudojs/crypto. All functions that touch node:crypto return a Promise.

Hashing

NameWhat it doesNotes
hash(input, { algorithm?, encoding?, provider? })Hashes data; returns { algorithm, digest, encoded }Default sha256 / hex. md5 and sha1 throw.
sha256 / sha384 / sha512 / sha3_256 / sha3_384 / sha3_512(input, encoding?)Returns the encoded digest stringEncoding defaults to hex.
hmac(input, key, algorithm?, encoding?)Keyed hashKey is a Uint8Array of 16+ bytes.
hmacSha256 / hmacSha384 / hmacSha512(input, key, encoding?)HMAC shorthandsSame key rule.
timingSafeEqual(a, b), timingSafeEqualString(a, b)Constant-time comparison of bytes or stringsUse instead of ===.

Encryption

NameWhat it doesNotes
encrypt(plaintext, key, { iv?, aad?, provider? })AES-256-GCM; returns { algorithm, ciphertext, iv, authTag }Key 32 bytes. IV 12 bytes, random if omitted.
decrypt(ciphertext, key, iv, authTag, aad?)Reverses encryptThrows ERR_CRYPTO_CIPHER on tampering.
encryptString / decryptStringSame, for UTF-8 strings
encryptEnvelope(plaintext, key, options?)Returns one v1.aes-256-gcm.iv.tag.ct stringBest choice for storage.
decryptEnvelope(envelope, key, aad?)Returns plaintext bytesValidates every field first.

Passwords and key derivation

NameWhat it doesNotes
hashPassword(password, options?)scrypt hash; returns { encoded, salt, hash, cost, blockSize, parallelization }Options: saltBytes, keyBytes, cost, blockSize, parallelization.
verifyPassword(password, encoded)Checks a passwordNever throws; returns false.
isPasswordHash(value), isValidPassword(value, min?)Shape checksisValidPassword is length only.
derivePbkdf2(password, options?), deriveScrypt(password, options?)Turn a passphrase into key bytes; returns { key, salt, algorithm }Pass salt to reproduce a key.
deriveKey(password, CryptoAlgorithm, options?)Picks PBKDF2 or scrypt by enum
generateSalt(length?)Random salt bytesMinimum 16.

Signatures and keys

NameWhat it doesNotes
sign(data, privateKey, { algorithm? })Returns a signature Uint8ArrayDefault ed25519; also rsa-* and ecdsa-*.
verify(data, signature, publicKey, { algorithm? })Returns booleanMalformed input gives false.
signString / verifyStringSame for UTF-8 strings
generateEd25519KeyPair()Returns { privateKey, publicKey } KeyObjectsSynchronous.
exportPrivateKeyPem(key), exportPublicKeyPem(key), derivePublicKey(privateKey)PEM export and public-key recovery
generateCryptoKey(length, { algorithm, usages?, extractable? })Random symmetric key as a CryptoKey objectSymmetric algorithms only.
createCryptoKey(bytes, options), exportCryptoKey(key)Wrap existing bytes; read them backExport requires extractable: true.

Tokens and random

NameWhat it doesNotes
generateToken({ bytes?, encoding?, prefix? })Random opaque token stringDefault 32 bytes base64url; minimum 16.
generateApiKey / generateSessionToken / generateRefreshToken / generateVerificationToken / generatePasswordResetToken / generateCsrfToken()Prefixed tokensPrefixes in TOKEN_PREFIX.
generateOtp(digits?)Numeric one-time code4 to 12 digits, default 6.
hashToken(token), verifyTokenHash(token, storedHash)SHA-256 hex for storage and constant-time checkhashTokenForStorage is an alias.
hasTokenPrefix / removeTokenPrefix(token, prefix), isValidToken(token, min?)String helpers
randomBytesSecure(n), randomHex(chars), randomBase64Url(bytes)Random bytes and strings
randomInteger(min, max), randomIntegerBelow(max), randomUuid()Uniform integers and UUID v4max is excluded.
randomNumericCode(len?), randomAlphanumeric(len), randomFromAlphabet(len, alphabet), randomChoice(array), randomBoolean()Random characters and picks

Encoding, service, provider, errors, constants

NameWhat it doesNotes
encode(bytes, encoding), decode(string, encoding)Convert between bytes and hex / base64 / base64url / utf8Also toHex, fromHex, toBase64Url, fromBase64Url, utf8Encode, utf8Decode.
createCryptoService({ provider? }), cryptoServiceMethod-style facade; wraps failures in CryptoErrorMethods: generateKey, randomBytes, encrypt, decrypt, hash, hashHex, hashPassword, verifyPassword, deriveKey, generateToken, generateOtp, hashToken, verifyToken, encode, decode.
createCryptoFactory({ defaultKeyAlgorithm?, password?, encoding?, provider? }), cryptoFactoryService with app-wide defaultsMethods: createKey, createToken, createApiKey, createSessionToken, createRefreshToken, createVerificationToken, createPasswordResetToken, createCsrfToken, createOtp, createPasswordHash, verifyPassword, encode, decode.
createNodeCryptoProvider(), getDefaultCryptoProvider(), setDefaultCryptoProvider(p), resetDefaultCryptoProvider()Create or swap the backing providerImplement CryptoProvider for a custom one. setDefaultCryptoProvider rejects one missing any of the twelve methods or the seven capability flags.
CryptoError, isCryptoError(value), CryptoOperationError class, guard and operation enumRe-exported from @zudojs/errors.
CryptoAlgorithm, CryptoKeyUsageEnums for algorithm and key-usage namesUse these, not string literals, where an enum is expected.
AES_GCM, PASSWORD_HASH, PASSWORD_POLICY, TOKEN, TOKEN_PREFIX, TOKEN_TTLFrozen default parameterse.g. PASSWORD_HASH.SCRYPT.COST is 16384.

COMMON MISTAKES

  • Hashing a password with sha256. It runs millions of times per second, so a leaked table is cracked in minutes. Fix: hashPassword and verifyPassword.
  • Using new Uint8Array(32) as a real key. That is 32 zero bytes; everyone has that key. Fix: await randomBytesSecure(32) once, then load it from configuration.
  • Passing a 4-byte HMAC key. hmac throws RangeError: HMAC key must be at least 16 bytes. Fix: use 16 to 64 random bytes.
  • Storing the raw API key. A database leak then hands out working credentials. Fix: store hashToken(key) and look up with verifyTokenHash.
  • Passing "aes-256-gcm" where an enum is expected. generateCryptoKey, deriveKey and createCryptoFactory take CryptoAlgorithm; TypeScript rejects the string. Fix: CryptoAlgorithm.AES_256_GCM.
  • Feeding raw 32 bytes to sign. Signing keys are PEM, DER or KeyObject, not random bytes. Fix: generateEd25519KeyPair() and exportPrivateKeyPem.

COMPLETE EXPORT INDEX

Every name @zudojs/crypto exports from its package root at v1.3.0 — 257 in total, generated from the package’s own entry point rather than written by hand. The sections above explain the ones you reach for most; this is the exhaustive list, so nothing shipped is undocumented. Names not covered above are typically internal helpers and supporting types.

Show all 257 exports
Classes (4)
CryptoError CryptoFactory CryptoService NodeCryptoProvider
Functions (165)
arrayBufferToBytes assertBinaryEncoding assertCryptoProvider assertHashCapability assertHmacCapability assertKeyObject assertNewHashCost assertPassword assertPasswordHashingCapability assertProviderCapability assertRandomCapability bytesToArrayBuffer bytesToNumber cloneBytes concatBytes createCryptoError createCryptoFactory createCryptoKey createCryptoService createNodeCryptoProvider cryptoCipherError cryptoHashError cryptoKeyDerivationError cryptoKeyError cryptoKeysEqual cryptoKeyToPrivateKey cryptoSignatureError decode decodeBase64Url decodeDigest decodePasswordHash decrypt decryptEnvelope decryptString defaultKeyLength deriveKey derivePbkdf2 derivePublicKey deriveScrypt encode encodeDigest encodePasswordHash encrypt encryptEnvelope encryptString equalDigests expectedAsymmetricKeyType expectedKeyLength exportCryptoKey exportPrivateKeyPem exportPublicKeyPem fillRandomBytes fromBase64 fromBase64Url fromHex generateApiKey generateCryptoKey generateCsrfToken generateEd25519KeyPair generateEmailVerificationCode generateLoginCode generateOtp generatePasswordResetToken generateRefreshToken generateSalt generateSessionToken generateToken generateVerificationToken getCryptoFactory getCryptoKeyFingerprint getCryptoService getDefaultAesGcmConfig getDefaultCryptoProvider getDefaultPasswordHashConfig getDefaultPasswordHashOptions hash hashPassword hashToken hashTokenBase64Url hashTokenForStorage hasTokenPrefix hmac hmacSha256 hmacSha384 hmacSha512 isAeadAlgorithm isArrayBuffer isBase64 isBase64Url isBase64UrlString isBinaryEncoding isBytes isCryptoAlgorithm isCryptoEncoding isCryptoError isCryptoKey isHashAlgorithm isHashAlgorithmName isHex isHexString isHmacAlgorithmName isKeyDerivationAlgorithm isKeyObject isMacAlgorithm isPasswordHash isPbkdf2Digest isSignatureAlgorithm isSignatureAlgorithmName isSymmetricKeyAlgorithm isValidPassword isValidToken nodeSignatureAlgorithm normalizeText numberToBytes parseCryptoAlgorithm parsePositiveInteger pbkdf2PasswordAlgorithm randomAlphanumeric randomBase64 randomBase64Url randomBoolean randomBytesSecure randomChoice randomFromAlphabet randomHex randomInteger randomIntegerBelow randomNumericCode randomToken randomUuid removeTokenPrefix resetDefaultCryptoProvider secureEqual secureStringEqual setDefaultCryptoProvider sha256 sha3_256 sha3_384 sha3_512 sha384 sha512 sign signString sliceBytes timingSafeEqual timingSafeEqualEncoded timingSafeEqualString toBase64 toBase64Url toBytes toHex toPrivateKey toPublicKey utf8ByteLength utf8Decode utf8Encode validateParameters validatePbkdf2Options validatePbkdf2Parameters validateScryptOptions verify verifyPassword verifyString verifyTokenHash wipe
Interfaces (35)
CipherOptions CipherResult CryptoCapabilities CryptoErrorOptions CryptoFactoryOptions CryptoKey CryptoKeyOptions CryptoProvider CryptoServiceOptions DecryptOptions DerivedKeyResult DeriveKeyOptions EncryptedData EncryptionProvider EncryptOptions HashOptions HashPasswordOptions HashProvider HashResult HmacProvider KeyDerivationProvider PasswordHashOptions PasswordHashProviderOptions PasswordHashResult PasswordProvider Pbkdf2Options Pbkdf2PasswordHashParameters RandomProvider RandomTokenOptions ScryptOptions ScryptPasswordHashParameters SigningProvider SignOptions TokenOptions VerifyOptions
Type aliases (22)
BinaryEncoding BinaryInput CryptoAlgorithmName CryptoEncoding CryptoEncodingName CryptoInput DerivedKeyAlgorithm EncodingFormat EncryptionAlgorithm HashAlgorithm HashEncoding HashInput HmacAlgorithm KeyDerivationAlgorithm KeyMaterial PasswordHashParameters Pbkdf2Digest Pbkdf2PasswordAlgorithm SignatureAlgorithm SignatureOptions TokenEncoding TokenPrefix
Constants (28)
AEAD_ALGORITHMS AES_GCM base64ToBytes base64UrlToBytes bytesToBase64 bytesToBase64Url bytesToHex CRYPTO_ALGORITHM CRYPTO_KEY_FINGERPRINT_LABEL CRYPTO_PROVIDER_METHODS CRYPTO_VERSION cryptoFactory cryptoService ENCODING HASH HASH_ALGORITHMS hexToBytes KEY_DERIVATION_ALGORITHMS KEY_SIZE MAC_ALGORITHMS PASSWORD_FORMAT_VERSION PASSWORD_HASH PASSWORD_POLICY RANDOM SIGNATURE_ALGORITHMS TOKEN TOKEN_PREFIX TOKEN_TTL
Enums (3)
CryptoAlgorithm CryptoKeyUsage CryptoOperation