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