Перейти к содержанию

Криптография

Стабильность: 2 — Стабильная

Модуль node:crypto предоставляет криптографические возможности, включая обёртки над функциями OpenSSL для хэшей, HMAC, шифрования и расшифрования, подписи и проверки.

1
2
3
4
5
6
7
8
9
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
1
2
3
4
5
6
7
8
9
const { createHmac } = require('node:crypto');

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

Когда поддержка crypto недоступна

Node.js может быть собран без модуля node:crypto. Тогда import из crypto или вызов require('node:crypto') приведут к ошибке.

В CommonJS ошибку можно перехватить через try/catch:

1
2
3
4
5
6
let crypto;
try {
  crypto = require('node:crypto');
} catch (err) {
  console.error('crypto support is disabled!');
}

При лексическом import в ESM ошибку можно перехватить только если обработчик process.on('uncaughtException') зарегистрирован до любой попытки загрузить модуль (например через preload).

Если код может выполняться в сборке Node.js без crypto, вместо лексического import используйте динамический [import()][import()]:

1
2
3
4
5
6
let crypto;
try {
  crypto = await import('node:crypto');
} catch (err) {
  console.error('crypto support is disabled!');
}

Типы асимметричных ключей

В таблице — типы асимметричных ключей, которые распознаёт API [KeyObject][KeyObject], и поддерживаемые форматы импорта/экспорта.

Тип ключа Описание OID 'pem' 'der' 'jwk' 'raw-public' 'raw-private' 'raw-seed'
'dh' Diffie-Hellman 1.2.840.113549.1.3.1
'dsa' DSA 1.2.840.10040.4.1
'ec' Elliptic curve 1.2.840.10045.2.1
'ed25519' Ed25519 1.3.101.112
'ed448' Ed448 1.3.101.113
'ml-dsa-44'3 ML-DSA-44 2.16.840.1.101.3.4.3.17
'ml-dsa-65'3 ML-DSA-65 2.16.840.1.101.3.4.3.18
'ml-dsa-87'3 ML-DSA-87 2.16.840.1.101.3.4.3.19
'ml-kem-512'3 ML-KEM-512 2.16.840.1.101.3.4.4.1
'ml-kem-768'3 ML-KEM-768 2.16.840.1.101.3.4.4.2
'ml-kem-1024'3 ML-KEM-1024 2.16.840.1.101.3.4.4.3
'rsa-pss' RSA PSS 1.2.840.113549.1.1.10
'rsa' RSA 1.2.840.113549.1.1.1
'slh-dsa-sha2-128f'3 SLH-DSA-SHA2-128f 2.16.840.1.101.3.4.3.21
'slh-dsa-sha2-128s'3 SLH-DSA-SHA2-128s 2.16.840.1.101.3.4.3.20
'slh-dsa-sha2-192f'3 SLH-DSA-SHA2-192f 2.16.840.1.101.3.4.3.23
'slh-dsa-sha2-192s'3 SLH-DSA-SHA2-192s 2.16.840.1.101.3.4.3.22
'slh-dsa-sha2-256f'3 SLH-DSA-SHA2-256f 2.16.840.1.101.3.4.3.25
'slh-dsa-sha2-256s'3 SLH-DSA-SHA2-256s 2.16.840.1.101.3.4.3.24
'slh-dsa-shake-128f'3 SLH-DSA-SHAKE-128f 2.16.840.1.101.3.4.3.27
'slh-dsa-shake-128s'3 SLH-DSA-SHAKE-128s 2.16.840.1.101.3.4.3.26
'slh-dsa-shake-192f'3 SLH-DSA-SHAKE-192f 2.16.840.1.101.3.4.3.29
'slh-dsa-shake-192s'3 SLH-DSA-SHAKE-192s 2.16.840.1.101.3.4.3.28
'slh-dsa-shake-256f'3 SLH-DSA-SHAKE-256f 2.16.840.1.101.3.4.3.31
'slh-dsa-shake-256s'3 SLH-DSA-SHAKE-256s 2.16.840.1.101.3.4.3.30
'x25519' X25519 1.3.101.110
'x448' X448 1.3.101.111

Форматы ключей

Асимметричные ключи можно представить в нескольких форматах. Рекомендуется один раз импортировать материал ключа в [KeyObject][KeyObject] и переиспользовать его для всех дальнейших операций — так не повторяется разбор и достигается лучшая производительность.

Если [KeyObject][KeyObject] неудобен (например ключ приходит в сообщении протокола и используется один раз), большинство криптографических функций принимают строку PEM или объект с форматом и материалом ключа. Полный набор опций — в [crypto.createPublicKey()][crypto.createPublicKey()], [crypto.createPrivateKey()][crypto.createPrivateKey()] и [keyObject.export()][keyObject.export()].

KeyObject

[KeyObject][KeyObject] — представление разобранного ключа в памяти. Создаётся через [crypto.createPublicKey()][crypto.createPublicKey()], [crypto.createPrivateKey()][crypto.createPrivateKey()], [crypto.createSecretKey()][crypto.createSecretKey()] или функции генерации, например [crypto.generateKeyPair()][crypto.generateKeyPair()]. Первая криптографическая операция с данным [KeyObject][KeyObject] может быть медленнее последующих: OpenSSL лениво инициализирует внутренние кэши при первом использовании.

PEM и DER

PEM и DER — традиционные кодировки асимметричных ключей на базе структур ASN.1.

  • PEM — текстовая кодировка: DER в Base64 между строками заголовка и подвала (например -----BEGIN PUBLIC KEY-----). Строки PEM можно передавать напрямую во многие операции.
  • DER — двоичная кодировка тех же структур ASN.1. Для входа DER нужно явно указать type (обычно 'spki' или 'pkcs8').

JSON Web Key (JWK)

JSON Web Key (JWK) — представление ключа в JSON по RFC 7517. Компоненты кодируются в Base64url внутри объекта. Для RSA JWK снижает накладные расходы разбора ASN.1 и часто даёт самый быстрый импорт из сериализованных форматов.

«Сырые» форматы ключей

Стабильность: 1.1 — Активная разработка

Форматы 'raw-public', 'raw-private' и 'raw-seed' позволяют импортировать и экспортировать сырой материал ключа без обёртки. Подробности — [keyObject.export()][keyObject.export()], [crypto.createPublicKey()][crypto.createPublicKey()], [crypto.createPrivateKey()][crypto.createPrivateKey()].

'raw-public' обычно самый быстрый способ импорта открытого ключа. 'raw-private' и 'raw-seed' не всегда быстрее других форматов: в них только скаляр/seed закрытого ключа — для использования часто нужно вычислить открытую часть (умножение на кривой, развёртывание seed), что дорого. В других форматах уже есть обе части ключа.

Выбор формата ключа

По возможности используйте [KeyObject][KeyObject] — создайте из любого доступного формата и переиспользуйте. Ниже — про выбор формата сериализации при импорте в [KeyObject][KeyObject] или при передаче материала inline, когда [KeyObject][KeyObject] не подходит.

Импорт ключей

Если [KeyObject][KeyObject] создаётся для многократного использования, стоимость импорта платится один раз, и более быстрый формат снижает задержку старта.

Импорт состоит из разбора обёртки и вычислений по ключу (восстановление полного ключа: открытый ключ из закрытого скаляра, развёртывание seed и т. д.). Что доминирует, зависит от типа ключа. Например:

  • Открытые ключи — 'raw-public' обычно быстрее всех сериализованных форматов: нет разбора ASN.1 и Base64.
  • Закрытые EC — 'raw-private' быстрее PEM/DER (меньше ASN.1). На больших кривых (P-384, P-521) вычисление открытой точки дорого, выигрыш меньше.
  • RSA — 'jwk' часто самый быстрый сериализованный формат: компоненты как целые в Base64url без ASN.1.

Материал ключа inline в операциях

Если [KeyObject][KeyObject] нельзя переиспользовать (ключ пришёл как сырые байты в сообщении и используется один раз), функции обычно принимают PEM или объект с форматом и материалом. Полная стоимость — импорт плюс сама криптооперация.

Если доминирует тяжёлая операция (подпись RSA, ECDH на P-384/P-521), формат сериализации почти не влияет на пропускную способность — выбирайте удобный. Для лёгких операций (Ed25519) импорт заметнее, и быстрые 'raw-public' / 'raw-private' дают выигрыш.

Даже при нескольких использованиях одного материала лучше импортировать в [KeyObject][KeyObject], чем снова передавать сырой или PEM.

Примеры

Переиспользование [KeyObject][KeyObject] для подписи и проверки:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { promisify } from 'node:util';
const { generateKeyPair, sign, verify } = await import('node:crypto');

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

// KeyObject хранит разобранный ключ в памяти и переиспользуется
// без повторного разбора.
const data = new TextEncoder().encode('message to sign');
const signature = sign(null, data, privateKey);
verify(null, data, publicKey, signature);

Пример: импорт ключей разных форматов в [KeyObject][KeyObject]:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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 — нужен явный 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' });

Пример: передача материала ключа напрямую в [crypto.sign()][crypto.sign()] и [crypto.verify()][crypto.verify()] без предварительного [KeyObject][KeyObject]:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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);

Пример: для ключей EC при импорте сырых ключей нужна опция namedCurve:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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);

Пример: экспорт и импорт сырых seed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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

SPKAC — механизм запроса на подпись сертификата, изначально в Netscape и формально вошедший в элемент HTML5 keygen.

<keygen> устарел с HTML 5.2; в новых проектах элемент не используют.

Модуль node:crypto предоставляет класс Certificate для работы с данными SPKAC. Чаще всего это вывод элемента <keygen>. Внутри Node.js использует реализацию SPKAC в OpenSSL.

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

Добавлено в: v9.0.0

История
Версия Изменения
v15.0.0 Аргументом spkac может быть ArrayBuffer. Ограничен размер аргумента spkac максимум до 2**31–1 байта.
  • spkac | | | |
  • encoding кодировка строки spkac
  • Возвращает: компонент challenge структуры spkac (открытый ключ и challenge)
1
2
3
4
5
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
1
2
3
4
5
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])

Добавлено в: v9.0.0

История
Версия Изменения
v15.0.0 Аргументом spkac может быть ArrayBuffer. Ограничен размер аргумента spkac максимум до 2**31–1 байта.
  • spkac | | | |
  • encoding кодировка строки spkac
  • Возвращает: компонент открытого ключа структуры spkac (открытый ключ и challenge)
1
2
3
4
5
const { Certificate } = await import('node:crypto');
const spkac = getSpkacSomehow();
const publicKey = Certificate.exportPublicKey(spkac);
console.log(publicKey);
// Prints: the public key as <Buffer ...>
1
2
3
4
5
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])

Добавлено в: v9.0.0

История
Версия Изменения
v15.0.0 Аргументом spkac может быть ArrayBuffer. Добавлена ​​кодировка. Ограничен размер аргумента spkac максимум до 2**31–1 байта.
  • spkac | | | |
  • encoding кодировка строки spkac
  • Возвращает: true, если структура spkac допустима, иначе false
1
2
3
4
5
6
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
1
2
3
4
5
6
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:

1
2
3
4
const { Certificate } = await import('node:crypto');

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

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

certificate.exportChallenge(spkac[, encoding])

  • spkac | | | |
  • encoding The encoding of the spkac string.
  • Returns: The challenge component of the spkac data structure, which includes a public key and a challenge.
1
2
3
4
5
6
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
1
2
3
4
5
6
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])

  • spkac | | | |
  • encoding The encoding of the spkac string.
  • Returns: The public key component of the spkac data structure, which includes a public key and a challenge.
1
2
3
4
5
6
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 ...>
1
2
3
4
5
6
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])

  • spkac | | | |
  • encoding The encoding of the spkac string.
  • Returns: true if the given spkac data structure is valid, false otherwise.
1
2
3
4
5
6
7
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
1
2
3
4
5
6
7
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

  • Extends:

Экземпляры Cipheriv используются для шифрования данных. Два варианта использования:

  • как поток Transform: в пишущую сторону подаётся открытый текст, со стороны чтения — шифротекст;
  • через [cipher.update()][cipher.update()] и [cipher.final()][cipher.final()].

[crypto.createCipheriv()][crypto.createCipheriv()] создаёт экземпляры Cipheriv; конструктор new не используют.

Пример: Cipheriv как поток:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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();
  });
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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();
  });
});

Пример: Cipheriv и pipeline:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;
    });
  });
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;
    });
  });
});

Пример: методы [cipher.update()][cipher.update()] и [cipher.final()][cipher.final()]:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
  });
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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])

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

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()

  • Возвращает: В режимах с аутентификацией (GCM, CCM, OCB, chacha20-poly1305) метод cipher.getAuthTag() возвращает [Buffer][Buffer] с тегом аутентификации, вычисленным по данным.

cipher.getAuthTag() вызывают только после завершения шифрования через [cipher.final()][cipher.final()].

Если при создании cipher была задана опция authTagLength, вернётся ровно столько байт.

cipher.setAAD(buffer[, options])

Комментарии