Crypto

<!--introduced_in=v0.3.6-->

Stability: 2 - Stable

<!-- source_link=lib/crypto.js -->

The node:crypto module provides cryptographic functionality that includes a set of wrappers for OpenSSL's hash, message authentication code (MAC), cipher, decipher, sign, verify, and key encapsulation mechanism (KEM) functions.

const { createHmac } = await import('node:crypto');

const secret = 'abcdefg';
const hash = createHmac('sha256', secret)
               .update('I love cupcakes')
               .digest('hex');
console.log(hash);
// Prints:
//   c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e
const { createHmac } = require('node:crypto');

const secret = 'abcdefg';
const hash = createHmac('sha256', secret)
               .update('I love cupcakes')
               .digest('hex');
console.log(hash);
// Prints:
//   c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e

Determining if crypto support is unavailable

It is possible for Node.js to be built without including support for the node:crypto module. In such cases, attempting to import from crypto or calling require('node:crypto') will result in an error being thrown.

When using CommonJS, the error thrown can be caught using try/catch:

<!-- eslint-disable no-global-assign -->

let crypto;
try {
  crypto = require('node:crypto');
} catch (err) {
  console.error('crypto support is disabled!');
}

When using the lexical ESM import keyword, the error can only be caught if a handler for process.on('uncaughtException') is registered before any attempt to load the module is made (using, for instance, a preload module).

When using ESM, if there is a chance that the code may be run on a build of Node.js where crypto support is not enabled, consider using the [import()][] function instead of the lexical import keyword:

let crypto;
try {
  crypto = await import('node:crypto');
} catch (err) {
  console.error('crypto support is disabled!');
}

Asymmetric key types

The following lists group the asymmetric key types recognized by the [KeyObject][] API by the complete set of formats supported for importing and exporting each type.

Formats: 'pem', 'der'

  • 'dh' (Diffie-Hellman) — OID 1.2.840.113549.1.3.1
  • 'dsa' — OID 1.2.840.10040.4.1
  • 'rsa-pss' — OID 1.2.840.113549.1.1.10

Formats: 'pem', 'der', 'jwk'

  • 'rsa' — OID 1.2.840.113549.1.1.1

Formats: 'pem', 'der', 'jwk', 'raw-public', 'raw-private'

  • 'ec' (Elliptic curve) — OID 1.2.840.10045.2.1
  • 'ed25519' — OID 1.3.101.112
  • 'ed448' — OID 1.3.101.113
  • 'slh-dsa-sha2-128f'[^openssl35] — OID 2.16.840.1.101.3.4.3.21
  • 'slh-dsa-sha2-128s'[^openssl35] — OID 2.16.840.1.101.3.4.3.20
  • 'slh-dsa-sha2-192f'[^openssl35] — OID 2.16.840.1.101.3.4.3.23
  • 'slh-dsa-sha2-192s'[^openssl35] — OID 2.16.840.1.101.3.4.3.22
  • 'slh-dsa-sha2-256f'[^openssl35] — OID 2.16.840.1.101.3.4.3.25
  • 'slh-dsa-sha2-256s'[^openssl35] — OID 2.16.840.1.101.3.4.3.24
  • 'slh-dsa-shake-128f'[^openssl35] — OID 2.16.840.1.101.3.4.3.27
  • 'slh-dsa-shake-128s'[^openssl35] — OID 2.16.840.1.101.3.4.3.26
  • 'slh-dsa-shake-192f'[^openssl35] — OID 2.16.840.1.101.3.4.3.29
  • 'slh-dsa-shake-192s'[^openssl35] — OID 2.16.840.1.101.3.4.3.28
  • 'slh-dsa-shake-256f'[^openssl35] — OID 2.16.840.1.101.3.4.3.31
  • 'slh-dsa-shake-256s'[^openssl35] — OID 2.16.840.1.101.3.4.3.30
  • 'x25519' — OID 1.3.101.110
  • 'x448' — OID 1.3.101.111

Formats: 'pem', 'der', 'jwk', 'raw-public', 'raw-seed'

  • 'ml-dsa-44'[^openssl35] — OID 2.16.840.1.101.3.4.3.17
  • 'ml-dsa-65'[^openssl35] — OID 2.16.840.1.101.3.4.3.18
  • 'ml-dsa-87'[^openssl35] — OID 2.16.840.1.101.3.4.3.19
  • 'ml-kem-512'[^openssl35] — OID 2.16.840.1.101.3.4.4.1
  • 'ml-kem-768'[^openssl35] — OID 2.16.840.1.101.3.4.4.2
  • 'ml-kem-1024'[^openssl35] — OID 2.16.840.1.101.3.4.4.3

Key formats

Asymmetric keys can be represented in several formats. The recommended approach is to import key material into a [KeyObject][] once and reuse it for all subsequent operations, as this avoids repeated parsing and delivers the best performance.

When a [KeyObject][] is not practical - for example, when key material arrives in a protocol message and is used only once - most cryptographic functions also accept a PEM string or an object specifying the format and key material directly. See [crypto.createPublicKey()][], [crypto.createPrivateKey()][], and [keyObject.export()][] for the full options accepted by each format.

KeyObject

A [KeyObject][] is the in-memory representation of a parsed key. It is created by [crypto.createPublicKey()][], [crypto.createPrivateKey()][], [crypto.createSecretKey()][], or key generation functions such as [crypto.generateKeyPair()][]. The first cryptographic operation with a given [KeyObject][] may be slower than subsequent ones because OpenSSL lazily initializes internal caches on first use.

PEM and DER

PEM and DER are the traditional encoding formats for asymmetric keys based on ASN.1 structures.

  • PEM is a text encoding that wraps Base64-encoded DER data between header and footer lines (e.g. -----BEGIN PUBLIC KEY-----). PEM strings can be passed directly to most cryptographic operations.
  • DER is the binary encoding of the same ASN.1 structures. When providing DER input, the type (typically 'spki' or 'pkcs8') must be specified explicitly.

JSON Web Key (JWK)

JSON Web Key (JWK) is a JSON-based key representation defined in [RFC 7517][]. JWK encodes each key component as an individual Base64url-encoded value inside a JSON object. For RSA keys, JWK avoids ASN.1 parsing overhead and is the fastest serialized import format.

Raw key formats

Stability: 1.1 - Active development

The 'raw-public', 'raw-private', and 'raw-seed' key formats allow importing and exporting raw key material without any encoding wrapper. See [keyObject.export()][], [crypto.createPublicKey()][], and [crypto.createPrivateKey()][] for usage details.

'raw-public' is generally the fastest way to import a public key. 'raw-private' and 'raw-seed' are not always faster than other formats because they only contain the private scalar or seed - importing them requires deriving the public key component (e.g. elliptic curve point multiplication or seed expansion), which can be expensive. Other formats include both private and public components, avoiding that computation.

Choosing a key format

Always prefer a [KeyObject][] - create one from whatever format you have and reuse it. The guidance below applies only when choosing between serialization formats, either for importing into a [KeyObject][] or for passing key material inline when a [KeyObject][] is not practical.

Importing keys

When creating a [KeyObject][] for repeated use, the import cost is paid once, so choosing a faster format reduces startup latency.

The import cost breaks down into two parts: parsing overhead (decoding the serialization wrapper) and key computation (any mathematical work needed to reconstruct the full key, such as deriving a public key from a private scalar or expanding a seed). Which part dominates depends on the key type. For example:

  • Public keys - 'raw-public' is the fastest serialized format because the raw format skips all ASN.1 and Base64 decoding.
  • EC private keys - 'raw-private' is faster than PEM or DER because it avoids ASN.1 parsing. However, for larger curves (e.g. P-384, P-521) the required derivation of the public point from the private scalar becomes expensive, reducing the advantage.
  • RSA keys - 'jwk' is the fastest serialized format. JWK represents RSA key components as individual Base64url-encoded integers, avoiding the overhead of ASN.1 parsing entirely.

Inline key material in operations

When a [KeyObject][] cannot be reused (e.g. the key arrives as raw bytes in a protocol message and is used only once), most cryptographic functions also accept a PEM string or an object specifying the format and key material directly. In this case the total cost is the sum of key import and the cryptographic computation itself.

For operations where the cryptographic computation dominates - such as signing with RSA or ECDH key agreement with P-384 or P-521 - the serialization format has negligible impact on overall throughput, so choose whichever format is most convenient. For lightweight operations like Ed25519 signing or verification, the import cost is a larger fraction of the total, so a faster format like 'raw-public' or 'raw-private' can meaningfully improve throughput.

Even if the same key material is used only a few times, it is worth importing it into a [KeyObject][] rather than passing the raw or PEM representation repeatedly.

Examples

Example: Reusing a [KeyObject][] across sign and verify operations:

import { promisify } from 'node:util';
const { generateKeyPair, sign, verify } = await import('node:crypto');

const { publicKey, privateKey } = await promisify(generateKeyPair)('ed25519');

// A KeyObject holds the parsed key in memory and can be reused
// across multiple operations without re-parsing.
const data = new TextEncoder().encode('message to sign');
const signature = sign(null, data, privateKey);
verify(null, data, publicKey, signature);

Example: Importing keys of various formats into [KeyObject][]s:

import { promisify } from 'node:util';
const {
  createPrivateKey, createPublicKey, generateKeyPair,
} = await import('node:crypto');

const generated = await promisify(generateKeyPair)('ed25519');

// PEM
const privatePem = generated.privateKey.export({ format: 'pem', type: 'pkcs8' });
const publicPem = generated.publicKey.export({ format: 'pem', type: 'spki' });
createPrivateKey(privatePem);
createPublicKey(publicPem);

// DER - requires explicit type
const privateDer = generated.privateKey.export({ format: 'der', type: 'pkcs8' });
const publicDer = generated.publicKey.export({ format: 'der', type: 'spki' });
createPrivateKey({ key: privateDer, format: 'der', type: 'pkcs8' });
createPublicKey({ key: publicDer, format: 'der', type: 'spki' });

// JWK
const privateJwk = generated.privateKey.export({ format: 'jwk' });
const publicJwk = generated.publicKey.export({ format: 'jwk' });
createPrivateKey({ key: privateJwk, format: 'jwk' });
createPublicKey({ key: publicJwk, format: 'jwk' });

// Raw
const rawPriv = generated.privateKey.export({ format: 'raw-private' });
const rawPub = generated.publicKey.export({ format: 'raw-public' });
createPrivateKey({ key: rawPriv, format: 'raw-private', asymmetricKeyType: 'ed25519' });
createPublicKey({ key: rawPub, format: 'raw-public', asymmetricKeyType: 'ed25519' });

Example: Passing key material directly to [crypto.sign()][] and [crypto.verify()][] without creating a [KeyObject][] first:

import { promisify } from 'node:util';
const { generateKeyPair, sign, verify } = await import('node:crypto');

const generated = await promisify(generateKeyPair)('ed25519');

const data = new TextEncoder().encode('message to sign');

// PEM strings
const privatePem = generated.privateKey.export({ format: 'pem', type: 'pkcs8' });
const publicPem = generated.publicKey.export({ format: 'pem', type: 'spki' });
const sig1 = sign(null, data, privatePem);
verify(null, data, publicPem, sig1);

// JWK objects
const privateJwk = generated.privateKey.export({ format: 'jwk' });
const publicJwk = generated.publicKey.export({ format: 'jwk' });
const sig2 = sign(null, data, { key: privateJwk, format: 'jwk' });
verify(null, data, { key: publicJwk, format: 'jwk' }, sig2);

// Raw key bytes
const rawPriv = generated.privateKey.export({ format: 'raw-private' });
const rawPub = generated.publicKey.export({ format: 'raw-public' });
const sig3 = sign(null, data, {
  key: rawPriv, format: 'raw-private', asymmetricKeyType: 'ed25519',
});
verify(null, data, {
  key: rawPub, format: 'raw-public', asymmetricKeyType: 'ed25519',
}, sig3);

Example: For EC keys, the namedCurve option is required when importing raw keys:

import { promisify } from 'node:util';
const {
  createPrivateKey, createPublicKey, generateKeyPair, sign, verify,
} = await import('node:crypto');

const generated = await promisify(generateKeyPair)('ec', {
  namedCurve: 'P-256',
});

// Export the raw EC public key (uncompressed by default).
const rawPublicKey = generated.publicKey.export({ format: 'raw-public' });

// The following is equivalent.
const rawPublicKeyUncompressed = generated.publicKey.export({
  format: 'raw-public',
  type: 'uncompressed',
});

// Export compressed point format.
const rawPublicKeyCompressed = generated.publicKey.export({
  format: 'raw-public',
  type: 'compressed',
});

// Export the raw EC private key.
const rawPrivateKey = generated.privateKey.export({ format: 'raw-private' });

// Import the raw EC keys.
// Both compressed and uncompressed point formats are accepted.
const publicKey = createPublicKey({
  key: rawPublicKey,
  format: 'raw-public',
  asymmetricKeyType: 'ec',
  namedCurve: 'P-256',
});
const privateKey = createPrivateKey({
  key: rawPrivateKey,
  format: 'raw-private',
  asymmetricKeyType: 'ec',
  namedCurve: 'P-256',
});

const data = new TextEncoder().encode('message to sign');
const signature = sign('sha256', data, privateKey);
verify('sha256', data, publicKey, signature);

Example: Exporting raw seeds and importing them:

import { promisify } from 'node:util';
const {
  createPrivateKey, decapsulate, encapsulate, generateKeyPair,
} = await import('node:crypto');

const generated = await promisify(generateKeyPair)('ml-kem-768');

// Export the raw seed (64 bytes for ML-KEM).
const seed = generated.privateKey.export({ format: 'raw-seed' });

// Import the raw seed.
const privateKey = createPrivateKey({
  key: seed,
  format: 'raw-seed',
  asymmetricKeyType: 'ml-kem-768',
});

const { ciphertext } = encapsulate(generated.publicKey);
decapsulate(privateKey, ciphertext);

Class: Certificate

<!-- YAML added: v0.11.8 -->

SPKAC is a Certificate Signing Request mechanism originally implemented by Netscape and was specified formally as part of HTML5's keygen element.

<keygen> is deprecated since [HTML 5.2][] and new projects should not use this element anymore.

The node:crypto module provides the Certificate class for working with SPKAC data. The most common usage is handling output generated by the HTML5 <keygen> element. Node.js uses [OpenSSL's SPKAC implementation][] internally.

Static method: Certificate.exportChallenge(spkac[, encoding])

<!-- YAML added: v9.0.0 changes: - version: v15.0.0 pr-url: https://github.com/nodejs/node/pull/35093 description: The spkac argument can be an ArrayBuffer. Limited the size of the spkac argument to a maximum of 2**31 - 1 bytes. -->

  • spkac {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • encoding {string} The [encoding][] of the spkac string.
  • Returns: {Buffer} The challenge component of the spkac data structure, which includes a public key and a challenge.
const { Certificate } = await import('node:crypto');
const spkac = getSpkacSomehow();
const challenge = Certificate.exportChallenge(spkac);
console.log(challenge.toString('utf8'));
// Prints: the challenge as a UTF8 string
const { Certificate } = require('node:crypto');
const spkac = getSpkacSomehow();
const challenge = Certificate.exportChallenge(spkac);
console.log(challenge.toString('utf8'));
// Prints: the challenge as a UTF8 string

Static method: Certificate.exportPublicKey(spkac[, encoding])

<!-- YAML added: v9.0.0 changes: - version: v15.0.0 pr-url: https://github.com/nodejs/node/pull/35093 description: The spkac argument can be an ArrayBuffer. Limited the size of the spkac argument to a maximum of 2**31 - 1 bytes. -->

  • spkac {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • encoding {string} The [encoding][] of the spkac string.
  • Returns: {Buffer} The public key component of the spkac data structure, which includes a public key and a challenge.
const { Certificate } = await import('node:crypto');
const spkac = getSpkacSomehow();
const publicKey = Certificate.exportPublicKey(spkac);
console.log(publicKey);
// Prints: the public key as <Buffer ...>
const { Certificate } = require('node:crypto');
const spkac = getSpkacSomehow();
const publicKey = Certificate.exportPublicKey(spkac);
console.log(publicKey);
// Prints: the public key as <Buffer ...>

Static method: Certificate.verifySpkac(spkac[, encoding])

<!-- YAML added: v9.0.0 changes: - version: v15.0.0 pr-url: https://github.com/nodejs/node/pull/35093 description: The spkac argument can be an ArrayBuffer. Added encoding. Limited the size of the spkac argument to a maximum of 2**31 - 1 bytes. -->

  • spkac {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • encoding {string} The [encoding][] of the spkac string.
  • Returns: {boolean} true if the given spkac data structure is valid, false otherwise.
import { Buffer } from 'node:buffer';
const { Certificate } = await import('node:crypto');

const spkac = getSpkacSomehow();
console.log(Certificate.verifySpkac(Buffer.from(spkac)));
// Prints: true or false
const { Buffer } = require('node:buffer');
const { Certificate } = require('node:crypto');

const spkac = getSpkacSomehow();
console.log(Certificate.verifySpkac(Buffer.from(spkac)));
// Prints: true or false

Legacy API

Stability: 0 - Deprecated

As a legacy interface, it is possible to create new instances of the crypto.Certificate class as illustrated in the examples below.

new crypto.Certificate()

Instances of the Certificate class can be created using the new keyword or by calling crypto.Certificate() as a function:

const { Certificate } = await import('node:crypto');

const cert1 = new Certificate();
const cert2 = Certificate();
const { Certificate } = require('node:crypto');

const cert1 = new Certificate();
const cert2 = Certificate();

certificate.exportChallenge(spkac[, encoding])

<!-- YAML added: v0.11.8 -->

  • spkac {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • encoding {string} The [encoding][] of the spkac string.
  • Returns: {Buffer} The challenge component of the spkac data structure, which includes a public key and a challenge.
const { Certificate } = await import('node:crypto');
const cert = Certificate();
const spkac = getSpkacSomehow();
const challenge = cert.exportChallenge(spkac);
console.log(challenge.toString('utf8'));
// Prints: the challenge as a UTF8 string
const { Certificate } = require('node:crypto');
const cert = Certificate();
const spkac = getSpkacSomehow();
const challenge = cert.exportChallenge(spkac);
console.log(challenge.toString('utf8'));
// Prints: the challenge as a UTF8 string

certificate.exportPublicKey(spkac[, encoding])

<!-- YAML added: v0.11.8 -->

  • spkac {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • encoding {string} The [encoding][] of the spkac string.
  • Returns: {Buffer} The public key component of the spkac data structure, which includes a public key and a challenge.
const { Certificate } = await import('node:crypto');
const cert = Certificate();
const spkac = getSpkacSomehow();
const publicKey = cert.exportPublicKey(spkac);
console.log(publicKey);
// Prints: the public key as <Buffer ...>
const { Certificate } = require('node:crypto');
const cert = Certificate();
const spkac = getSpkacSomehow();
const publicKey = cert.exportPublicKey(spkac);
console.log(publicKey);
// Prints: the public key as <Buffer ...>

certificate.verifySpkac(spkac[, encoding])

<!-- YAML added: v0.11.8 -->

  • spkac {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • encoding {string} The [encoding][] of the spkac string.
  • Returns: {boolean} true if the given spkac data structure is valid, false otherwise.
import { Buffer } from 'node:buffer';
const { Certificate } = await import('node:crypto');

const cert = Certificate();
const spkac = getSpkacSomehow();
console.log(cert.verifySpkac(Buffer.from(spkac)));
// Prints: true or false
const { Buffer } = require('node:buffer');
const { Certificate } = require('node:crypto');

const cert = Certificate();
const spkac = getSpkacSomehow();
console.log(cert.verifySpkac(Buffer.from(spkac)));
// Prints: true or false

Class: Cipheriv

<!-- YAML added: v0.1.94 -->

  • Extends: {stream.Transform}

Instances of the Cipheriv class are used to encrypt data. The class can be used in one of two ways:

  • As a [stream][] that is both readable and writable, where plain unencrypted data is written to produce encrypted data on the readable side, or
  • Using the [cipher.update()][] and [cipher.final()][] methods to produce the encrypted data.

The [crypto.createCipheriv()][] method is used to create Cipheriv instances. Cipheriv objects are not to be created directly using the new keyword.

The selected algorithm may impose additional restrictions on streaming and calls to [cipher.update()][]. See [CCM mode][], [CBC-CTS mode][], [XTS mode][], [AES key wrap modes][], and [SIV and GCM-SIV modes][].

Example: Using Cipheriv objects as streams:

const {
  scrypt,
  randomFill,
  createCipheriv,
} = await import('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';

// First, we'll generate the key. The key length is dependent on the algorithm.
// In this case for aes192, it is 24 bytes (192 bits).
scrypt(password, 'salt', 24, (err, key) => {
  if (err) throw err;
  // Then, we'll generate a random initialization vector
  randomFill(new Uint8Array(16), (err, iv) => {
    if (err) throw err;

    // Once we have the key and iv, we can create and use the cipher...
    const cipher = createCipheriv(algorithm, key, iv);

    let encrypted = '';
    cipher.setEncoding('hex');

    cipher.on('data', (chunk) => encrypted += chunk);
    cipher.on('end', () => console.log(encrypted));

    cipher.write('some clear text data');
    cipher.end();
  });
});
const {
  scrypt,
  randomFill,
  createCipheriv,
} = require('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';

// First, we'll generate the key. The key length is dependent on the algorithm.
// In this case for aes192, it is 24 bytes (192 bits).
scrypt(password, 'salt', 24, (err, key) => {
  if (err) throw err;
  // Then, we'll generate a random initialization vector
  randomFill(new Uint8Array(16), (err, iv) => {
    if (err) throw err;

    // Once we have the key and iv, we can create and use the cipher...
    const cipher = createCipheriv(algorithm, key, iv);

    let encrypted = '';
    cipher.setEncoding('hex');

    cipher.on('data', (chunk) => encrypted += chunk);
    cipher.on('end', () => console.log(encrypted));

    cipher.write('some clear text data');
    cipher.end();
  });
});

Example: Using Cipheriv and piped streams:

import {
  createReadStream,
  createWriteStream,
} from 'node:fs';

import {
  pipeline,
} from 'node:stream';

const {
  scrypt,
  randomFill,
  createCipheriv,
} = await import('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';

// First, we'll generate the key. The key length is dependent on the algorithm.
// In this case for aes192, it is 24 bytes (192 bits).
scrypt(password, 'salt', 24, (err, key) => {
  if (err) throw err;
  // Then, we'll generate a random initialization vector
  randomFill(new Uint8Array(16), (err, iv) => {
    if (err) throw err;

    const cipher = createCipheriv(algorithm, key, iv);

    const input = createReadStream('test.js');
    const output = createWriteStream('test.enc');

    pipeline(input, cipher, output, (err) => {
      if (err) throw err;
    });
  });
});
const {
  createReadStream,
  createWriteStream,
} = require('node:fs');

const {
  pipeline,
} = require('node:stream');

const {
  scrypt,
  randomFill,
  createCipheriv,
} = require('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';

// First, we'll generate the key. The key length is dependent on the algorithm.
// In this case for aes192, it is 24 bytes (192 bits).
scrypt(password, 'salt', 24, (err, key) => {
  if (err) throw err;
  // Then, we'll generate a random initialization vector
  randomFill(new Uint8Array(16), (err, iv) => {
    if (err) throw err;

    const cipher = createCipheriv(algorithm, key, iv);

    const input = createReadStream('test.js');
    const output = createWriteStream('test.enc');

    pipeline(input, cipher, output, (err) => {
      if (err) throw err;
    });
  });
});

Example: Using the [cipher.update()][] and [cipher.final()][] methods:

const {
  scrypt,
  randomFill,
  createCipheriv,
} = await import('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';

// First, we'll generate the key. The key length is dependent on the algorithm.
// In this case for aes192, it is 24 bytes (192 bits).
scrypt(password, 'salt', 24, (err, key) => {
  if (err) throw err;
  // Then, we'll generate a random initialization vector
  randomFill(new Uint8Array(16), (err, iv) => {
    if (err) throw err;

    const cipher = createCipheriv(algorithm, key, iv);

    let encrypted = cipher.update('some clear text data', 'utf8', 'hex');
    encrypted += cipher.final('hex');
    console.log(encrypted);
  });
});
const {
  scrypt,
  randomFill,
  createCipheriv,
} = require('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';

// First, we'll generate the key. The key length is dependent on the algorithm.
// In this case for aes192, it is 24 bytes (192 bits).
scrypt(password, 'salt', 24, (err, key) => {
  if (err) throw err;
  // Then, we'll generate a random initialization vector
  randomFill(new Uint8Array(16), (err, iv) => {
    if (err) throw err;

    const cipher = createCipheriv(algorithm, key, iv);

    let encrypted = cipher.update('some clear text data', 'utf8', 'hex');
    encrypted += cipher.final('hex');
    console.log(encrypted);
  });
});

cipher.final([outputEncoding])

<!-- YAML added: v0.1.94 -->

  • outputEncoding {string} The [encoding][] of the return value.
  • Returns: {Buffer | string} Any remaining enciphered contents. If outputEncoding is specified, a string is returned. If an outputEncoding is not provided, a [Buffer][] is returned.

If an output encoding was specified in a previous call to [cipher.update()][], outputEncoding must use the same encoding.

Once the cipher.final() method has been called, the Cipheriv object can no longer be used to encrypt data. Attempts to call cipher.final() more than once will result in an error being thrown.

cipher.getAuthTag()

<!-- YAML added: v1.0.0 -->

  • Returns: {Buffer} When using an authenticated encryption mode (GCM, CCM, OCB, SIV, GCM-SIV, and chacha20-poly1305 are currently supported), the cipher.getAuthTag() method returns a [Buffer][] containing the authentication tag that has been computed from the given data.

The cipher.getAuthTag() method should only be called after encryption has been completed using the [cipher.final()][] method.

If the authTagLength option was set during the cipher instance's creation, this function will return exactly authTagLength bytes.

cipher.setAAD(buffer[, options])

<!-- YAML added: v1.0.0 -->

  • buffer {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • options {Object} [stream.transform options][]
  • plaintextLength {number}
  • encoding {string} The string encoding to use when buffer is a string.
  • Returns: {Cipheriv} The same Cipheriv instance for method chaining.

When using an authenticated encryption mode (GCM, CCM, OCB, SIV, GCM-SIV, and chacha20-poly1305 are currently supported), the cipher.setAAD() method sets the value used for the additional authenticated data (AAD) input parameter.

The plaintextLength option is optional for GCM, OCB, SIV, and GCM-SIV. When using CCM, the plaintextLength option must be specified and its value must match the length of the plaintext in bytes. See [CCM mode][].

The cipher.setAAD() method must be called before [cipher.update()][].

cipher.setAutoPadding([autoPadding])

<!-- YAML added: v0.7.1 -->

  • autoPadding {boolean} Default: true
  • Returns: {Cipheriv} The same Cipheriv instance for method chaining.

When using block ciphers that use standard block padding, the Cipheriv class will automatically add padding to the input data to the appropriate block size. To disable the default padding call cipher.setAutoPadding(false).

For block ciphers that use standard block padding, when autoPadding is false, the length of the entire input data must be a multiple of the cipher's block size or [cipher.final()][] will throw an error. Disabling automatic padding is useful for non-standard padding, for instance using 0x0 instead of PKCS padding.

The cipher.setAutoPadding() method must be called before [cipher.final()][].

cipher.update(data[, inputEncoding][, outputEncoding])

<!-- YAML added: v0.1.94 changes: - version: v6.0.0 pr-url: https://github.com/nodejs/node/pull/5522 description: The default inputEncoding changed from binary to utf8. -->

  • data {string|Buffer|TypedArray|DataView}
  • inputEncoding {string} The [encoding][] of the data.
  • outputEncoding {string} The [encoding][] of the return value.
  • Returns: {Buffer | string}

Updates the cipher with data. If the inputEncoding argument is given, the data argument is a string using the specified encoding. If the inputEncoding argument is not given, data must be a [Buffer][], TypedArray, or DataView. If data is a [Buffer][], TypedArray, or DataView, then inputEncoding is ignored.

The outputEncoding specifies the output format of the enciphered data. If the outputEncoding is specified, a string using the specified encoding is returned. If no outputEncoding is provided, a [Buffer][] is returned. When outputEncoding is specified, it must use the same encoding as previous calls to cipher.update().

For most algorithms, cipher.update() can be called multiple times with new data until [cipher.final()][] is called. Some algorithms restrict calls to cipher.update(). For example, [CCM mode][], [CBC-CTS mode][], [XTS mode][], [AES key wrap modes][], and [SIV and GCM-SIV modes][] require the whole message in a single call. Calling cipher.update() after [cipher.final()][] will result in an error being thrown.

Class: Decipheriv

<!-- YAML added: v0.1.94 -->

  • Extends: {stream.Transform}

Instances of the Decipheriv class are used to decrypt data. The class can be used in one of two ways:

  • As a [stream][] that is both readable and writable, where plain encrypted data is written to produce unencrypted data on the readable side, or
  • Using the [decipher.update()][] and [decipher.final()][] methods to produce the unencrypted data.

The [crypto.createDecipheriv()][] method is used to create Decipheriv instances. Decipheriv objects are not to be created directly using the new keyword.

The selected algorithm may impose additional restrictions on streaming and calls to [decipher.update()][]. See [CCM mode][], [CBC-CTS mode][], [XTS mode][], [AES key wrap modes][], and [SIV and GCM-SIV modes][].

Example: Using Decipheriv objects as streams:

import { Buffer } from 'node:buffer';
const {
  scryptSync,
  createDecipheriv,
} = await import('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Key length is dependent on the algorithm. In this case for aes192, it is
// 24 bytes (192 bits).
// Use the async `crypto.scrypt()` instead.
const key = scryptSync(password, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const decipher = createDecipheriv(algorithm, key, iv);

let decrypted = '';
decipher.on('readable', () => {
  let chunk;
  while (null !== (chunk = decipher.read())) {
    decrypted += chunk.toString('utf8');
  }
});
decipher.on('end', () => {
  console.log(decrypted);
  // Prints: some clear text data
});

// Encrypted with same algorithm, key and iv.
const encrypted =
  'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa';
decipher.write(encrypted, 'hex');
decipher.end();
const {
  scryptSync,
  createDecipheriv,
} = require('node:crypto');
const { Buffer } = require('node:buffer');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Key length is dependent on the algorithm. In this case for aes192, it is
// 24 bytes (192 bits).
// Use the async `crypto.scrypt()` instead.
const key = scryptSync(password, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const decipher = createDecipheriv(algorithm, key, iv);

let decrypted = '';
decipher.on('readable', () => {
  let chunk;
  while (null !== (chunk = decipher.read())) {
    decrypted += chunk.toString('utf8');
  }
});
decipher.on('end', () => {
  console.log(decrypted);
  // Prints: some clear text data
});

// Encrypted with same algorithm, key and iv.
const encrypted =
  'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa';
decipher.write(encrypted, 'hex');
decipher.end();

Example: Using Decipheriv and piped streams:

import {
  createReadStream,
  createWriteStream,
} from 'node:fs';
import { Buffer } from 'node:buffer';
const {
  scryptSync,
  createDecipheriv,
} = await import('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Use the async `crypto.scrypt()` instead.
const key = scryptSync(password, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const decipher = createDecipheriv(algorithm, key, iv);

const input = createReadStream('test.enc');
const output = createWriteStream('test.js');

input.pipe(decipher).pipe(output);
const {
  createReadStream,
  createWriteStream,
} = require('node:fs');
const {
  scryptSync,
  createDecipheriv,
} = require('node:crypto');
const { Buffer } = require('node:buffer');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Use the async `crypto.scrypt()` instead.
const key = scryptSync(password, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const decipher = createDecipheriv(algorithm, key, iv);

const input = createReadStream('test.enc');
const output = createWriteStream('test.js');

input.pipe(decipher).pipe(output);

Example: Using the [decipher.update()][] and [decipher.final()][] methods:

import { Buffer } from 'node:buffer';
const {
  scryptSync,
  createDecipheriv,
} = await import('node:crypto');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Use the async `crypto.scrypt()` instead.
const key = scryptSync(password, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const decipher = createDecipheriv(algorithm, key, iv);

// Encrypted using same algorithm, key and iv.
const encrypted =
  'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa';
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
// Prints: some clear text data
const {
  scryptSync,
  createDecipheriv,
} = require('node:crypto');
const { Buffer } = require('node:buffer');

const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Use the async `crypto.scrypt()` instead.
const key = scryptSync(password, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.

const decipher = createDecipheriv(algorithm, key, iv);

// Encrypted using same algorithm, key and iv.
const encrypted =
  'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa';
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
// Prints: some clear text data

decipher.final([outputEncoding])

<!-- YAML added: v0.1.94 -->

  • outputEncoding {string} The [encoding][] of the return value.
  • Returns: {Buffer | string} Any remaining deciphered contents. If outputEncoding is specified, a string is returned. If an outputEncoding is not provided, a [Buffer][] is returned.

If an output encoding was specified in a previous call to [decipher.update()][], outputEncoding must use the same encoding.

Once the decipher.final() method has been called, the Decipheriv object can no longer be used to decrypt data. Attempts to call decipher.final() more than once will result in an error being thrown.

decipher.setAAD(buffer[, options])

<!-- YAML added: v1.0.0 changes: - version: v15.0.0 pr-url: https://github.com/nodejs/node/pull/35093 description: The buffer argument can be a string or ArrayBuffer and is limited to no more than 2 ** 31 - 1 bytes. - version: v7.2.0 pr-url: https://github.com/nodejs/node/pull/9398 description: This method now returns a reference to decipher. -->

  • buffer {string|ArrayBuffer|Buffer|TypedArray|DataView}
  • options {Object} [stream.transform options][]
  • plaintextLength {number}
  • encoding {string} String encoding to use when buffer is a string.
  • Returns: {Decipheriv} The same Decipheriv instance for method chaining.

When using an authenticated encryption mode (GCM, CCM, OCB, SIV, GCM-SIV, and chacha20-poly1305 are currently supported), the decipher.setAAD() method sets the value used for the additional authenticated data (AAD) input parameter.

The options argument is optional for GCM, OCB, SIV, and GCM-SIV. When using CCM, the plaintextLength option must be specified and its value must match the length of the ciphertext in bytes. See [CCM mode][].

The decipher.setAAD() method must be called before [decipher.update()][].

When passing a string as the buffer, please consider [caveats when using strings as inputs to cryptographic APIs][].

decipher.setAuthTag(buffer[, encoding])

<!-- YAML added: v1.0.0 changes: - version: v26.0.0 pr-url: https://github.com/nodejs/node/pull/61084 description: Using GCM tag lengths other than 128 bits without specifying the authTagLength option when creating decipher is not allowed anymore. - version: - v22.0.0 - v20.13.0 pr-url: https://github.com/nodejs/node/pull/52345 description: Using GCM tag lengths other than 128 bits without specifying the authTagLength option when creating decipher is deprecated. - version: v15.0.0 pr-url: https://github.com/nodejs/node/pull/35093 description: The buffer argument can be a string or ArrayBuffer and is limited to no more than 2 ** 31 - 1 bytes. - version: v11.0.0 pr-url: https://github.com/nodejs/node/pull/17825 description: This method now throws if the GCM tag length is invalid. - version: v7.2.0 pr-url: https://github.com/nodejs/node/pull/9398 description: This method now returns a reference to decipher. -->

  • buffer {string|Buffer|ArrayBuffer|TypedArray|DataView}
  • encoding {string} String encoding to use when buffer is a string.
  • Returns: {Decipheriv} The same Decipheriv instance for method chaining.

When using an authenticated encryption mode (GCM, CCM, OCB, SIV, GCM-SIV, and chacha20-poly1305 are currently supported), the decipher.setAuthTag() method is used to pass in the received authentication tag. If no tag is provided, or if the cipher text has been tampered with, [decipher.final()][] will throw, indicating that the cipher text should be discarded due to failed authentication. If the tag length is invalid according to [NIST SP 800-38D][] or does not match the value of the authTagLength option, decipher.setAuthTag() will throw an error.

The decipher.setAuthTag() method must be called before [decipher.update()][] for CCM, SIV, and GCM-SIV modes or before [decipher.final()][] for GCM and OCB modes and chacha20-poly1305. decipher.setAuthTag() can only be called once.

When passing a string as the authentication tag, please consider [caveats when using strings as inputs to cryptographic APIs][].

decipher.setAutoPadding([autoPadding])

<!-- YAML added: v0.7.1 -->

  • autoPadding {boolean} Default: true
  • Returns: {Decipheriv} The same Decipheriv instance for method chaining.

When data has been encrypted without standard block padding, calling decipher.setAutoPadding(false) will disable automatic padding to prevent [decipher.final()][] from checking for and removing padding.

For block ciphers that use standard block padding, disabling it requires the input data's length to be a multiple of the cipher's block size.

The decipher.setAutoPadding() method must be called before [decipher.final()][].

decipher.update(data[, inputEncoding][, outputEncoding])

<!-- YAML added: v0.1.94 changes: - version: v6.0.0 pr-url: https://github.com/nodejs/node/pull/5522 description: The default inputEncoding changed from binary to utf8. -->

  • data {string|Buffer|TypedArray|DataView}
  • inputEncoding {string} The [encoding][] of the data string.
  • outputEncoding {string} The [encoding][] of the return value.
  • Returns: {Buffer | string}

Updates the decipher with data. If the inputEncoding argument is given, the data argument is a string using the specified encoding. If the inputEncoding argument is not given, data must be a [Buffer][], TypedArray, or DataView. If data is a [Buffer][], TypedArray, or DataView, then inputEncoding is ignored.

The outputEncoding specifies the output format of the deciphered data. If the outputEncoding is specified, a string using the specified encoding is returned. If no outputEncoding is provided, a [Buffer][] is returned. When outputEncoding is specified, it must use the same encoding as previous calls to decipher.update().

For most algorithms, decipher.update() can be called multiple times with new data until [decipher.final()][] is called. Some algorithms restrict calls to decipher.update(). For example, [CCM mode][], [CBC-CTS mode][], [XTS mode][], [AES key wrap modes][], and [SIV and GCM-SIV modes][] require the whole message in a single call. Calling decipher.update() after [decipher.final()][] will result in an error being thrown.

Even if the underlying cipher implements authentication, the authenticity and integrity of the plaintext returned from this function may be uncertain at this time. For authenticated encryption algorithms, authenticity is generally only established when the application calls [decipher.final()][].

Class: DiffieHellman

<!-- YAML added: v0.5.0 -->

The DiffieHellman class is a utility for creating Diffie-Hellman key exchanges.

Instances of the DiffieHellman class can be created using the [crypto.createDiffieHellman()][] function.

import assert from 'node:assert';

const {
  createDiffieHellman,
} = await import('node:crypto');

// Generate Alice's keys...
const alice = createDiffieHellman(2048);
const aliceKey = alice.generateKeys();

// Generate Bob's keys...
const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator());
const bobKey = bob.generateKeys();

// Exchange and generate the secret...
const aliceSecret = alice.computeSecret(bobKey);
const bobSecret = bob.computeSecret(aliceKey);

// OK
assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));

```cjs const assert = require('node:assert');

const { createDiffieHellman, } = require('node:crypto');

// Generate Alice's keys

(本文超出站点单文档体积上限,已截断)