Standard library / crypto · on the one-page reference

crypto

Stable — pure computation throughout (an entropy source and a hash implementation, no syscalls involved), so unlike os and process.pid() this works identically on the native and WebAssembly targets.

A practical subset of Node's crypto module: mostly static one-shot functions, plus (spec 060) two real streaming builder objects, createHash/createHmac, for hashing data incrementally without holding it all in memory at once.

crypto.randomBytes(n)

int → string — n random bytes, hex-encoded (a 2n-character string). Kept as-is (not changed to return Buffer) now that Buffer exists — see randomBytesBuffer below for the raw-bytes form.

const token: string = crypto.randomBytes(16);
console.log(token.length); // 32
crypto.randomUUID()

→ string — a v4 UUID (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx).

console.log(crypto.randomUUID());
crypto.sha256(data)

string → string — hex digest of the SHA-256 hash of data's bytes.

console.log(crypto.sha256("hello"));
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
crypto.randomBytesBuffer(n) Experimental

int → Buffer — the same entropy source as randomBytes, without the hex encoding. Additive, not a replacement: randomBytes keeps returning a hex string, since that's an already-shipped contract other code relies on.

const raw = crypto.randomBytesBuffer(16);
console.log(raw.length); // 16
crypto.hmacSync(key, data) Experimental

(Buffer, Buffer) → Buffer — HMAC-SHA256, a 32-byte MAC. One fixed algorithm, no name parameter — the same "one well-chosen option" shape as sha256 itself.

const key = Buffer.from("key");
const data = Buffer.from("The quick brown fox jumps over the lazy dog");
console.log(crypto.hmacSync(key, data).toString("hex"));
// f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
crypto.encryptSync(key, iv, data) Experimental

(Buffer, Buffer, Buffer) → Buffer — AES-256-GCM authenticated encryption. key must be exactly 32 bytes and iv exactly 12 bytes (GCM's standard nonce length); either wrong-length input returns an empty Buffer rather than crashing. The result is ciphertext followed by a 16-byte authentication tag, concatenated into one Buffer — the simplest single-value shape, since decryptSync re-splits it internally.

const key = Buffer.alloc(32);  // in real use, crypto.randomBytesBuffer(32)
const iv = Buffer.alloc(12);   // in real use, a fresh nonce per message
const ct = crypto.encryptSync(key, iv, Buffer.from("attack at dawn"));
console.log(ct.length); // 30 -- 14-byte message + 16-byte tag
crypto.decryptSync(key, iv, data) Experimental

(Buffer, Buffer, Buffer) → Buffer — inverse of encryptSync. Deviation from Node: on a wrong-length key/iv, a too-short data, or a failed authentication check (tampered ciphertext or tag), returns an empty Buffer rather than throwing — the same fallback-don't-crash shape every other fallible builtin here uses.

const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);
const ct = crypto.encryptSync(key, iv, Buffer.from("attack at dawn"));
const pt = crypto.decryptSync(key, iv, ct);
console.log(pt.toString("utf8")); // attack at dawn

const tampered = Buffer.alloc(ct.length);
console.log(crypto.decryptSync(key, iv, tampered).length); // 0 -- auth failed
crypto.createHash(algorithm) Experimental

string → Hash — a stateful hash builder. algorithm is a runtime string, matching Node's own real createHash('sha256') API: "md5" | "sha1" | "sha256" | "sha512"; an unrecognized name falls back to "sha256" rather than throwing (the same "fallback, don't crash" shape as Buffer.from(s, encoding)'s unrecognized encoding). Hash.update(data) (Buffer → Hash) feeds bytes in, any number of times, and returns self for chaining; Hash.digest() (() → Buffer) finalizes once. Deviation from Node: digest() returns a raw Buffer, not a string with an encoding argument — call .toString("hex")/ .toString("base64") on the result, which composes with every other Buffer-returning API here instead of reimplementing encoding a second time.

const h = crypto.createHash("sha256");
h.update(Buffer.from("ab"));
h.update(Buffer.from("c"));
console.log(h.digest().toString("hex"));
// ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad -- same as sha256("abc")
crypto.createHmac(algorithm, key) Experimental

(string, Buffer) → Hmac — the streaming, algorithm-selectable counterpart to hmacSync (which stays fixed at HMAC-SHA256). Same four algorithms and unrecognized-name fallback as createHash. Hmac.update(data)/Hmac.digest() have the identical shape and the same Buffer-return design as Hash's.

const key = Buffer.from("key");
const mac = crypto.createHmac("sha256", key);
mac.update(Buffer.from("The quick brown fox jumps over the lazy dog"));
console.log(mac.digest().toString("hex"));
// f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8 -- same as hmacSync
crypto.pbkdf2Sync(password, salt, iterations, keylen) Experimental

(Buffer, Buffer, int, int) → Buffer — PBKDF2-HMAC-SHA256 key derivation. One fixed PRF, no algorithm parameter, matching hmacSync's own "one well-chosen option" shape. iterations < 1 or keylen <= 0 returns an empty Buffer rather than throwing.

const key = crypto.pbkdf2Sync(Buffer.from("password"), Buffer.from("salt"), 4096, 20);
console.log(key.toString("hex"));
// c5e478d59288c841aa530db6845c4c8d962893a0
crypto.scryptSync(password, salt, keylen) Experimental

(Buffer, Buffer, int) → Buffer — scrypt key derivation with fixed cost parameters (N=16384, r=8, p=1, Node's own crypto.scrypt default). Cost parameters aren't exposed as an option in v1. keylen <= 0 returns an empty Buffer.

const key = crypto.scryptSync(Buffer.from("password"), Buffer.from("salt"), 32);
console.log(key.length); // 32
crypto.timingSafeEqual(a, b) Experimental

(Buffer, Buffer) → bool — constant-time byte comparison, for checking secrets (MACs, tokens) without leaking timing information about where two values first differ. Deviation from Node: a length mismatch returns false instead of throwing — lengths aren't secret, so this leaks nothing a length-mismatch throw wouldn't already reveal.

const a = Buffer.from("secret");
const b = Buffer.from("secret");
console.log(crypto.timingSafeEqual(a, b)); // true