Crypto (加密)#

穩定性:2 - 穩定

原始碼: lib/crypto.js

node:crypto 模組提供了加密功能,其中包括一組對 OpenSSL 的雜湊、HMAC、加密、解密、簽名和驗證函式的封裝。

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

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

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

確定加密支援是否不可用#

Node.js 在構建時可能不包含對 node:crypto 模組的支援。在這種情況下,嘗試從 crypto import 或呼叫 require('node:crypto') 將導致丟擲錯誤。

使用 CommonJS 時,丟擲的錯誤可以使用 try/catch 捕獲。

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

當使用詞法 ESM import 關鍵字時,只有在嘗試載入模組*之前*註冊了 process.on('uncaughtException') 的處理程式(例如,使用預載入模組),才能捕獲該錯誤。

使用 ESM 時,如果程式碼有可能在未啟用加密支援的 Node.js 版本上執行,請考慮使用 import() 函式,而不是詞法 import 關鍵字。

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

非對稱金鑰型別#

下表列出了 KeyObject API 識別的非對稱金鑰型別

金鑰型別描述OID
'dh'Diffie-Hellman1.2.840.113549.1.3.1
'dsa'DSA1.2.840.10040.4.1
'ec'橢圓曲線1.2.840.10045.2.1
'ed25519'Ed255191.3.101.112
'ed448'Ed4481.3.101.113
'ml-dsa-44'1ML-DSA-442.16.840.1.101.3.4.3.17
'ml-dsa-65'1ML-DSA-652.16.840.1.101.3.4.3.18
'ml-dsa-87'1ML-DSA-872.16.840.1.101.3.4.3.19
'ml-kem-512'1ML-KEM-5122.16.840.1.101.3.4.4.1
'ml-kem-768'1ML-KEM-7682.16.840.1.101.3.4.4.2
'ml-kem-1024'1ML-KEM-10242.16.840.1.101.3.4.4.3
'rsa-pss'RSA PSS1.2.840.113549.1.1.10
'rsa'RSA1.2.840.113549.1.1.1
'slh-dsa-sha2-128f'1SLH-DSA-SHA2-128f2.16.840.1.101.3.4.3.21
'slh-dsa-sha2-128s'1SLH-DSA-SHA2-128s2.16.840.1.101.3.4.3.22
'slh-dsa-sha2-192f'1SLH-DSA-SHA2-192f2.16.840.1.101.3.4.3.23
'slh-dsa-sha2-192s'1SLH-DSA-SHA2-192s2.16.840.1.101.3.4.3.24
'slh-dsa-sha2-256f'1SLH-DSA-SHA2-256f2.16.840.1.101.3.4.3.25
'slh-dsa-sha2-256s'1SLH-DSA-SHA2-256s2.16.840.1.101.3.4.3.26
'slh-dsa-shake-128f'1SLH-DSA-SHAKE-128f2.16.840.1.101.3.4.3.27
'slh-dsa-shake-128s'1SLH-DSA-SHAKE-128s2.16.840.1.101.3.4.3.28
'slh-dsa-shake-192f'1SLH-DSA-SHAKE-192f2.16.840.1.101.3.4.3.29
'slh-dsa-shake-192s'1SLH-DSA-SHAKE-192s2.16.840.1.101.3.4.3.30
'slh-dsa-shake-256f'1SLH-DSA-SHAKE-256f2.16.840.1.101.3.4.3.31
'slh-dsa-shake-256s'1SLH-DSA-SHAKE-256s2.16.840.1.101.3.4.3.32
'x25519'X255191.3.101.110
'x448'X4481.3.101.111

類:Certificate#

SPKAC 是一種證書籤名請求機制,最初由 Netscape 實現,並作為 HTML5 keygen 元素的一部分正式指定。

<keygen>HTML 5.2 起已被棄用,新專案不應再使用此元素。

node:crypto 模組提供了 Certificate 類來處理 SPKAC 資料。最常見的用法是處理由 HTML5 <keygen> 元素生成的輸出。Node.js 內部使用 OpenSSL 的 SPKAC 實現

靜態方法:Certificate.exportChallenge(spkac[, encoding])#

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 stringconst { Certificate } = require('node:crypto');
const spkac = getSpkacSomehow();
const challenge = Certificate.exportChallenge(spkac);
console.log(challenge.toString('utf8'));
// Prints: the challenge as a UTF8 string

靜態方法:Certificate.exportPublicKey(spkac[, encoding])#

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 ...>

靜態方法:Certificate.verifySpkac(spkac[, encoding])#

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

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

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

舊版 API#

穩定性: 0 - 廢棄

作為舊版介面,可以建立 crypto.Certificate 類的新例項,如下例所示。

new crypto.Certificate()#

Certificate 類的例項可以使用 new 關鍵字建立,或者透過呼叫 crypto.Certificate() 作為函式來建立。

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])#
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 stringconst { 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])#
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])#
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 falseconst { 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

類:Cipheriv#

Cipheriv 類的例項用於加密資料。該類可以透過以下兩種方式之一使用:

  • 作為可讀可寫的 ,將未加密的純文字資料寫入,以在可讀端產生加密資料,或者
  • 使用 cipher.update()cipher.final() 方法來生成加密資料。

crypto.createCipheriv() 方法用於建立 Cipheriv 例項。不應直接使用 new 關鍵字建立 Cipheriv 物件。

示例:將 Cipheriv 物件用作流

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

示例:使用 Cipheriv 和管道流

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;
    });
  });
});

示例:使用 cipher.update()cipher.final() 方法

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])#

  • outputEncoding <string> 返回值的編碼
  • 返回:<Buffer> | <string> 任何剩餘的加密內容。如果指定了 outputEncoding,則返回一個字串。如果未提供 outputEncoding,則返回一個 Buffer

一旦呼叫了 cipher.final() 方法,Cipheriv 物件就不能再用於加密資料。多次嘗試呼叫 cipher.final() 將導致丟擲錯誤。

cipher.getAuthTag()#

  • 返回:<Buffer> 當使用認證加密模式(目前支援 GCMCCMOCBchacha20-poly1305)時,cipher.getAuthTag() 方法返回一個 Buffer,其中包含從給定資料計算出的*認證標籤*。

cipher.getAuthTag() 方法只應在使用 cipher.final() 方法完成加密後呼叫。

如果在 cipher 例項建立期間設定了 authTagLength 選項,此函式將返回確切的 authTagLength 位元組。

cipher.setAAD(buffer[, options])#

當使用認證加密模式(目前支援 GCMCCMOCBchacha20-poly1305)時,cipher.setAAD() 方法設定用於*附加認證資料*(AAD)輸入引數的值。

對於 GCMOCBplaintextLength 選項是可選的。使用 CCM 時,必須指定 plaintextLength 選項,並且其值必須與明文的位元組長度匹配。請參見 CCM 模式

cipher.setAAD() 方法必須在 cipher.update() 之前呼叫。

cipher.setAutoPadding([autoPadding])#

  • autoPadding <boolean> 預設值: true
  • 返回:<Cipheriv> 同一個 Cipheriv 例項,用於方法鏈式呼叫。

當使用分組加密演算法時,Cipheriv 類會自動向輸入資料新增填充,使其達到適當的分組大小。要停用預設填充,請呼叫 cipher.setAutoPadding(false)

autoPaddingfalse 時,整個輸入資料的長度必須是密碼分組大小的倍數,否則 cipher.final() 會丟擲錯誤。停用自動填充對於非標準填充很有用,例如使用 0x0 而不是 PKCS 填充。

cipher.setAutoPadding() 方法必須在 cipher.final() 之前呼叫。

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

data 更新密碼器。如果給定了 inputEncoding 引數,則 data 引數是使用指定編碼的字串。如果未給定 inputEncoding 引數,data 必須是 BufferTypedArrayDataView。如果 dataBufferTypedArrayDataView,則忽略 inputEncoding

outputEncoding 指定加密資料的輸出格式。如果指定了 outputEncoding,則返回使用指定編碼的字串。如果沒有提供 outputEncoding,則返回一個 Buffer

cipher.update() 方法可以多次呼叫以處理新資料,直到呼叫 cipher.final() 為止。在呼叫 cipher.final() 之後再呼叫 cipher.update() 將導致丟擲錯誤。

類:Decipheriv#

Decipheriv 類的例項用於解密資料。該類可以透過以下兩種方式之一使用:

  • 作為一個可讀可寫的 ,將加密的純文字資料寫入,以在可讀端產生未加密的資料,或者
  • 使用 decipher.update()decipher.final() 方法來生成未加密的資料。

crypto.createDecipheriv() 方法用於建立 Decipheriv 例項。不應直接使用 new 關鍵字建立 Decipheriv 物件。

示例:將 Decipheriv 物件用作流

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

示例:使用 Decipheriv 和管道流

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

示例:使用 decipher.update()decipher.final() 方法

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 dataconst {
  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])#

  • outputEncoding <string> 返回值的編碼
  • 返回:<Buffer> | <string> 任何剩餘的解密內容。如果指定了 outputEncoding,則返回一個字串。如果沒有提供 outputEncoding,則返回一個 Buffer

一旦呼叫了 decipher.final() 方法,Decipheriv 物件就不能再用於解密資料。多次嘗試呼叫 decipher.final() 將導致丟擲錯誤。

decipher.setAAD(buffer[, options])#

當使用認證加密模式(目前支援 GCMCCMOCBchacha20-poly1305)時,decipher.setAAD() 方法設定用於*附加認證資料*(AAD)輸入引數的值。

對於 GCMoptions 引數是可選的。使用 CCM 時,必須指定 plaintextLength 選項,並且其值必須與密文的位元組長度匹配。請參見 CCM 模式

decipher.setAAD() 方法必須在 decipher.update() 之前呼叫。

當將字串作為 buffer 傳遞時,請考慮將字串用作加密 API 輸入的注意事項

decipher.setAuthTag(buffer[, encoding])#

當使用認證加密模式(目前支援 GCMCCMOCBchacha20-poly1305)時,decipher.setAuthTag() 方法用於傳入接收到的*認證標籤*。如果沒有提供標籤,或者密文被篡改,decipher.final() 將會丟擲異常,表明由於認證失敗,應丟棄該密文。如果標籤長度根據 NIST SP 800-38D 無效,或者與 authTagLength 選項的值不匹配,decipher.setAuthTag() 將丟擲錯誤。

對於 CCM 模式,decipher.setAuthTag() 必須在 decipher.update() 之前呼叫;對於 GCMOCB 模式和 chacha20-poly1305,則必須在 decipher.final() 之前呼叫。decipher.setAuthTag() 只能呼叫一次。

當將字串作為認證標籤傳遞時,請考慮將字串用作加密 API 輸入的注意事項

decipher.setAutoPadding([autoPadding])#

  • autoPadding <boolean> 預設值: true
  • 返回:<Decipheriv> 同一個 Decipher 例項,用於方法鏈式呼叫。

當資料在沒有標準塊填充的情況下被加密時,呼叫 decipher.setAutoPadding(false) 將停用自動填充,以防止 decipher.final() 檢查和移除填充。

關閉自動填充僅在輸入資料的長度是密碼器塊大小的倍數時才有效。

decipher.setAutoPadding() 方法必須在 decipher.final() 之前呼叫。

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

data 更新解密器。如果給定了 inputEncoding 引數,則 data 引數是使用指定編碼的字串。如果未給定 inputEncoding 引數,data 必須是 Buffer。如果 dataBuffer,則忽略 inputEncoding

outputEncoding 指定加密資料的輸出格式。如果指定了 outputEncoding,則返回使用指定編碼的字串。如果沒有提供 outputEncoding,則返回一個 Buffer

decipher.update() 方法可以多次呼叫以處理新資料,直到呼叫 decipher.final() 為止。在呼叫 decipher.final() 之後再呼叫 decipher.update() 將導致丟擲錯誤。

即使底層密碼器實現了認證,此函式返回的明文的真實性和完整性此時可能不確定。對於認證加密演算法,真實性通常只有在應用程式呼叫 decipher.final() 時才能確定。

類:DiffieHellman#

DiffieHellman 類是用於建立 Diffie-Hellman 金鑰交換的實用工具。

DiffieHellman 類的例項可以使用 crypto.createDiffieHellman() 函式建立。

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'));const assert = require('node:assert');

const {
  createDiffieHellman,
} = require('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'));

diffieHellman.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])#

使用 otherPublicKey 作為另一方的公鑰計算共享金鑰,並返回計算出的共享金鑰。提供的金鑰使用指定的 inputEncoding 進行解釋,金鑰使用指定的 outputEncoding 進行編碼。如果未提供 inputEncoding,則 otherPublicKey 應為 BufferTypedArrayDataView

如果指定了 outputEncoding,則返回一個字串;否則,返回一個 Buffer

diffieHellman.generateKeys([encoding])#

生成私有和公共 Diffie-Hellman 金鑰值,除非它們已經被生成或計算過,並以指定的 encoding 返回公鑰。此金鑰應傳輸給另一方。如果提供了 encoding,則返回一個字串;否則返回一個 Buffer

此函式是 DH_generate_key() 的一個薄封裝。特別地,一旦生成或設定了私鑰,呼叫此函式僅更新公鑰,而不會生成新的私鑰。

diffieHellman.getGenerator([encoding])#

以指定的 encoding 返回 Diffie-Hellman 生成器。如果提供了 encoding,則返回一個字串;否則返回一個 Buffer

diffieHellman.getPrime([encoding])#

以指定的 encoding 返回 Diffie-Hellman 素數。如果提供了 encoding,則返回一個字串;否則返回一個 Buffer

diffieHellman.getPrivateKey([encoding])#

以指定的 encoding 返回 Diffie-Hellman 私鑰。如果提供了 encoding,則返回一個字串;否則返回一個 Buffer

diffieHellman.getPublicKey([encoding])#

以指定的 encoding 返回 Diffie-Hellman 公鑰。如果提供了 encoding,則返回一個字串;否則返回一個 Buffer

diffieHellman.setPrivateKey(privateKey[, encoding])#

設定 Diffie-Hellman 私鑰。如果提供了 encoding 引數,privateKey 應為一個字串。如果沒有提供 encodingprivateKey 應為一個 BufferTypedArrayDataView

此函式不會自動計算相關的公鑰。可以使用 diffieHellman.setPublicKey()diffieHellman.generateKeys() 來手動提供公鑰或自動推導它。

diffieHellman.setPublicKey(publicKey[, encoding])#

設定 Diffie-Hellman 公鑰。如果提供了 encoding 引數,publicKey 應為一個字串。如果沒有提供 encodingpublicKey 應為一個 BufferTypedArrayDataView

diffieHellman.verifyError#

一個位欄位,包含在 DiffieHellman 物件初始化期間執行檢查時產生的任何警告和/或錯誤。

以下值對此屬性有效(定義在 node:constants 模組中):

  • DH_CHECK_P_NOT_SAFE_PRIME
  • DH_CHECK_P_NOT_PRIME
  • DH_UNABLE_TO_CHECK_GENERATOR
  • DH_NOT_SUITABLE_GENERATOR

類:DiffieHellmanGroup#

DiffieHellmanGroup 類以一個著名的 modp 組作為其引數。它的工作方式與 DiffieHellman 相同,只是不允許在建立後更改其金鑰。換句話說,它沒有實現 setPublicKey()setPrivateKey() 方法。

const { createDiffieHellmanGroup } = await import('node:crypto');
const dh = createDiffieHellmanGroup('modp16');const { createDiffieHellmanGroup } = require('node:crypto');
const dh = createDiffieHellmanGroup('modp16');

支援以下組:

  • 'modp14' (2048 位, RFC 3526 第 3 節)
  • 'modp15' (3072 位, RFC 3526 第 4 節)
  • 'modp16' (4096 位, RFC 3526 第 5 節)
  • 'modp17' (6144 位, RFC 3526 第 6 節)
  • 'modp18' (8192 位, RFC 3526 第 7 節)

以下組仍然支援但已棄用(參見注意事項):

  • 'modp1' (768 位, RFC 2409 第 6.1 節)
  • 'modp2' (1024 位, RFC 2409 第 6.2 節)
  • 'modp5' (1536 位, RFC 3526 第 2 節)

這些已棄用的組可能會在未來版本的 Node.js 中被移除。

類:ECDH#

ECDH 類是用於建立橢圓曲線 Diffie-Hellman (ECDH) 金鑰交換的實用工具。

ECDH 類的例項可以使用 crypto.createECDH() 函式建立。

import assert from 'node:assert';

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

// Generate Alice's keys...
const alice = createECDH('secp521r1');
const aliceKey = alice.generateKeys();

// Generate Bob's keys...
const bob = createECDH('secp521r1');
const bobKey = bob.generateKeys();

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

assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
// OKconst assert = require('node:assert');

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

// Generate Alice's keys...
const alice = createECDH('secp521r1');
const aliceKey = alice.generateKeys();

// Generate Bob's keys...
const bob = createECDH('secp521r1');
const bobKey = bob.generateKeys();

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

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

靜態方法:ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])#

將由 keycurve 指定的 EC Diffie-Hellman 公鑰轉換為由 format 指定的格式。format 引數指定點編碼,可以是 'compressed''uncompressed''hybrid'。提供的金鑰使用指定的 inputEncoding 進行解釋,返回的金鑰使用指定的 outputEncoding 進行編碼。

使用 crypto.getCurves() 獲取可用曲線名稱的列表。在最近的 OpenSSL 版本中,openssl ecparam -list_curves 也會顯示每個可用橢圓曲線的名稱和描述。

如果未指定 format,則點將以 'uncompressed' 格式返回。

如果未提供 inputEncoding,則 key 應為一個 BufferTypedArrayDataView

示例(解壓縮一個金鑰)

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

const ecdh = createECDH('secp256k1');
ecdh.generateKeys();

const compressedKey = ecdh.getPublicKey('hex', 'compressed');

const uncompressedKey = ECDH.convertKey(compressedKey,
                                        'secp256k1',
                                        'hex',
                                        'hex',
                                        'uncompressed');

// The converted key and the uncompressed public key should be the same
console.log(uncompressedKey === ecdh.getPublicKey('hex'));const {
  createECDH,
  ECDH,
} = require('node:crypto');

const ecdh = createECDH('secp256k1');
ecdh.generateKeys();

const compressedKey = ecdh.getPublicKey('hex', 'compressed');

const uncompressedKey = ECDH.convertKey(compressedKey,
                                        'secp256k1',
                                        'hex',
                                        'hex',
                                        'uncompressed');

// The converted key and the uncompressed public key should be the same
console.log(uncompressedKey === ecdh.getPublicKey('hex'));

ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])#

使用 otherPublicKey 作為另一方的公鑰計算共享金鑰,並返回計算出的共享金鑰。提供的金鑰使用指定的 inputEncoding 進行解釋,返回的金鑰使用指定的 outputEncoding 進行編碼。如果未提供 inputEncoding,則 otherPublicKey 應為一個 BufferTypedArrayDataView

如果指定了 outputEncoding,將返回一個字串;否則返回一個 Buffer

otherPublicKey 不在橢圓曲線上時,ecdh.computeSecret 會丟擲 ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY 錯誤。由於 otherPublicKey 通常由遠端使用者透過不安全的網路提供,請務必相應地處理此異常。

ecdh.generateKeys([encoding[, format]])#

生成私有和公共 EC Diffie-Hellman 金鑰值,並以指定的 formatencoding 返回公鑰。此金鑰應傳輸給另一方。

format 引數指定點編碼,可以是 'compressed''uncompressed'。如果未指定 format,則點將以 'uncompressed' 格式返回。

如果提供了 encoding,則返回一個字串;否則返回一個 Buffer

ecdh.getPrivateKey([encoding])#

如果指定了 encoding,則返回一個字串;否則返回一個 Buffer

ecdh.getPublicKey([encoding][, format])#

format 引數指定點編碼,可以是 'compressed''uncompressed'。如果未指定 format,則點將以 'uncompressed' 格式返回。

如果指定了 encoding,則返回一個字串;否則返回一個 Buffer

ecdh.setPrivateKey(privateKey[, encoding])#

設定 EC Diffie-Hellman 私鑰。如果提供了 encoding,則 privateKey 應為一個字串;否則 privateKey 應為一個 BufferTypedArrayDataView

如果 privateKey 對建立 ECDH 物件時指定的曲線無效,則會丟擲錯誤。設定私鑰後,相關的公鑰點(金鑰)也會生成並設定在 ECDH 物件中。

ecdh.setPublicKey(publicKey[, encoding])#

穩定性: 0 - 廢棄

設定 EC Diffie-Hellman 公鑰。如果提供了 encoding,則 publicKey 應為一個字串;否則應為一個 BufferTypedArrayDataView

通常沒有理由呼叫此方法,因為 ECDH 只需要一個私鑰和另一方的公鑰來計算共享金鑰。通常會呼叫 ecdh.generateKeys()ecdh.setPrivateKey()ecdh.setPrivateKey() 方法會嘗試生成與正在設定的私鑰相關的公鑰點/金鑰。

示例(獲取共享金鑰)

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

const alice = createECDH('secp256k1');
const bob = createECDH('secp256k1');

// This is a shortcut way of specifying one of Alice's previous private
// keys. It would be unwise to use such a predictable private key in a real
// application.
alice.setPrivateKey(
  createHash('sha256').update('alice', 'utf8').digest(),
);

// Bob uses a newly generated cryptographically strong
// pseudorandom key pair
bob.generateKeys();

const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex');

// aliceSecret and bobSecret should be the same shared secret value
console.log(aliceSecret === bobSecret);const {
  createECDH,
  createHash,
} = require('node:crypto');

const alice = createECDH('secp256k1');
const bob = createECDH('secp256k1');

// This is a shortcut way of specifying one of Alice's previous private
// keys. It would be unwise to use such a predictable private key in a real
// application.
alice.setPrivateKey(
  createHash('sha256').update('alice', 'utf8').digest(),
);

// Bob uses a newly generated cryptographically strong
// pseudorandom key pair
bob.generateKeys();

const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex');

// aliceSecret and bobSecret should be the same shared secret value
console.log(aliceSecret === bobSecret);

類:Hash#

Hash 類是用於建立資料雜湊摘要的實用工具。它可以透過以下兩種方式之一使用:

  • 作為一個可讀可寫的 ,將資料寫入以在可讀端產生計算出的雜湊摘要,或者
  • 使用 hash.update()hash.digest() 方法來生成計算出的雜湊。

crypto.createHash() 方法用於建立 Hash 例項。不應直接使用 new 關鍵字建立 Hash 物件。

示例:將 Hash 物件用作流

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

const hash = createHash('sha256');

hash.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = hash.read();
  if (data) {
    console.log(data.toString('hex'));
    // Prints:
    //   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
  }
});

hash.write('some data to hash');
hash.end();const {
  createHash,
} = require('node:crypto');

const hash = createHash('sha256');

hash.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = hash.read();
  if (data) {
    console.log(data.toString('hex'));
    // Prints:
    //   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
  }
});

hash.write('some data to hash');
hash.end();

示例:使用 Hash 和管道流

import { createReadStream } from 'node:fs';
import { stdout } from 'node:process';
const { createHash } = await import('node:crypto');

const hash = createHash('sha256');

const input = createReadStream('test.js');
input.pipe(hash).setEncoding('hex').pipe(stdout);const { createReadStream } = require('node:fs');
const { createHash } = require('node:crypto');
const { stdout } = require('node:process');

const hash = createHash('sha256');

const input = createReadStream('test.js');
input.pipe(hash).setEncoding('hex').pipe(stdout);

示例:使用 hash.update()hash.digest() 方法

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

const hash = createHash('sha256');

hash.update('some data to hash');
console.log(hash.digest('hex'));
// Prints:
//   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50const {
  createHash,
} = require('node:crypto');

const hash = createHash('sha256');

hash.update('some data to hash');
console.log(hash.digest('hex'));
// Prints:
//   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50

hash.copy([options])#

建立一個新的 Hash 物件,其中包含當前 Hash 物件內部狀態的深複製。

可選的 options 引數控制流的行為。對於 XOF 雜湊函式(如 'shake256'),可以使用 outputLength 選項來指定所需的輸出長度(以位元組為單位)。

當在其 hash.digest() 方法被呼叫後嘗試複製 Hash 物件時,會丟擲一個錯誤。

// Calculate a rolling hash.
const {
  createHash,
} = await import('node:crypto');

const hash = createHash('sha256');

hash.update('one');
console.log(hash.copy().digest('hex'));

hash.update('two');
console.log(hash.copy().digest('hex'));

hash.update('three');
console.log(hash.copy().digest('hex'));

// Etc.// Calculate a rolling hash.
const {
  createHash,
} = require('node:crypto');

const hash = createHash('sha256');

hash.update('one');
console.log(hash.copy().digest('hex'));

hash.update('two');
console.log(hash.copy().digest('hex'));

hash.update('three');
console.log(hash.copy().digest('hex'));

// Etc.

hash.digest([encoding])#

計算所有被傳入進行雜湊處理的資料的摘要(使用 hash.update() 方法)。如果提供了 encoding,將返回一個字串;否則返回一個 Buffer

hash.digest() 方法被呼叫後,Hash 物件不能再次使用。多次呼叫會引發錯誤。

hash.update(data[, inputEncoding])#

用給定的 data 更新雜湊內容,其編碼在 inputEncoding 中給出。如果未提供 encoding,且 data 是一個字串,則強制使用 'utf8' 編碼。如果 data 是一個 BufferTypedArrayDataView,則忽略 inputEncoding

當新資料以流式傳輸時,可以多次呼叫此方法。

類:Hmac#

Hmac 類是用於建立加密 HMAC 摘要的實用工具。它可以透過以下兩種方式之一使用:

  • 作為一個可讀可寫的 ,將資料寫入以在可讀端產生計算出的 HMAC 摘要,或者
  • 使用 hmac.update()hmac.digest() 方法來生成計算出的 HMAC 摘要。

crypto.createHmac() 方法用於建立 Hmac 例項。不應直接使用 new 關鍵字建立 Hmac 物件。

示例:將 Hmac 物件用作流

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

const hmac = createHmac('sha256', 'a secret');

hmac.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = hmac.read();
  if (data) {
    console.log(data.toString('hex'));
    // Prints:
    //   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
  }
});

hmac.write('some data to hash');
hmac.end();const {
  createHmac,
} = require('node:crypto');

const hmac = createHmac('sha256', 'a secret');

hmac.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = hmac.read();
  if (data) {
    console.log(data.toString('hex'));
    // Prints:
    //   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
  }
});

hmac.write('some data to hash');
hmac.end();

示例:使用 Hmac 和管道流

import { createReadStream } from 'node:fs';
import { stdout } from 'node:process';
const {
  createHmac,
} = await import('node:crypto');

const hmac = createHmac('sha256', 'a secret');

const input = createReadStream('test.js');
input.pipe(hmac).pipe(stdout);const {
  createReadStream,
} = require('node:fs');
const {
  createHmac,
} = require('node:crypto');
const { stdout } = require('node:process');

const hmac = createHmac('sha256', 'a secret');

const input = createReadStream('test.js');
input.pipe(hmac).pipe(stdout);

示例:使用 hmac.update()hmac.digest() 方法

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

const hmac = createHmac('sha256', 'a secret');

hmac.update('some data to hash');
console.log(hmac.digest('hex'));
// Prints:
//   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77econst {
  createHmac,
} = require('node:crypto');

const hmac = createHmac('sha256', 'a secret');

hmac.update('some data to hash');
console.log(hmac.digest('hex'));
// Prints:
//   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e

hmac.digest([encoding])#

計算使用 hmac.update() 傳入的所有資料的 HMAC 摘要。如果提供了 encoding,則返回一個字串;否則返回一個 Buffer

hmac.digest() 被呼叫後,Hmac 物件不能再次使用。多次呼叫 hmac.digest() 將導致丟擲錯誤。

hmac.update(data[, inputEncoding])#

用給定的 data 更新 Hmac 內容,其編碼在 inputEncoding 中給出。如果未提供 encoding,且 data 是一個字串,則強制使用 'utf8' 編碼。如果 data 是一個 BufferTypedArrayDataView,則忽略 inputEncoding

當新資料以流式傳輸時,可以多次呼叫此方法。

類:KeyObject#

Node.js 使用 KeyObject 類來表示對稱或非對稱金鑰,每種金鑰都公開不同的函式。crypto.createSecretKey()crypto.createPublicKey()crypto.createPrivateKey() 方法用於建立 KeyObject 例項。不應直接使用 new 關鍵字建立 KeyObject 物件。

由於具有改進的安全特性,大多數應用程式應考慮使用新的 KeyObject API,而不是將金鑰作為字串或 Buffer 傳遞。

KeyObject 例項可以透過 postMessage() 傳遞給其他執行緒。接收方會獲得一個克隆的 KeyObject,且該 KeyObject 不需要列在 transferList 引數中。

靜態方法:KeyObject.from(key)#

示例:將 CryptoKey 例項轉換為 KeyObject

const { KeyObject } = await import('node:crypto');
const { subtle } = globalThis.crypto;

const key = await subtle.generateKey({
  name: 'HMAC',
  hash: 'SHA-256',
  length: 256,
}, true, ['sign', 'verify']);

const keyObject = KeyObject.from(key);
console.log(keyObject.symmetricKeySize);
// Prints: 32 (symmetric key size in bytes)const { KeyObject } = require('node:crypto');
const { subtle } = globalThis.crypto;

(async function() {
  const key = await subtle.generateKey({
    name: 'HMAC',
    hash: 'SHA-256',
    length: 256,
  }, true, ['sign', 'verify']);

  const keyObject = KeyObject.from(key);
  console.log(keyObject.symmetricKeySize);
  // Prints: 32 (symmetric key size in bytes)
})();

keyObject.asymmetricKeyDetails#

  • 型別:<Object>
    • modulusLength <number> 金鑰大小(以位為單位)(RSA, DSA)。
    • publicExponent <bigint> 公共指數(RSA)。
    • hashAlgorithm <string> 訊息摘要的名稱(RSA-PSS)。
    • mgf1HashAlgorithm <string> MGF1 使用的訊息摘要的名稱(RSA-PSS)。
    • saltLength <number> 最小鹽長度(以位元組為單位)(RSA-PSS)。
    • divisorLength <number> q 的大小(以位為單位)(DSA)。
    • namedCurve <string> 曲線名稱(EC)。

此屬性僅存在於非對稱金鑰上。根據金鑰的型別,此物件包含有關金鑰的資訊。透過此屬性獲得的任何資訊都不能用於唯一標識金鑰或危及金鑰的安全性。

對於 RSA-PSS 金鑰,如果金鑰材料包含 RSASSA-PSS-params 序列,則將設定 hashAlgorithmmgf1HashAlgorithmsaltLength 屬性。

其他金鑰詳細資訊可能會透過此 API 使用其他屬性公開。

keyObject.asymmetricKeyType#

對於非對稱金鑰,此屬性表示金鑰的型別。請參見支援的非對稱金鑰型別

對於無法識別的 KeyObject 型別和對稱金鑰,此屬性為 undefined

keyObject.equals(otherKeyObject)#

根據金鑰是否具有完全相同的型別、值和引數,返回 truefalse。此方法不是時間恆定的

keyObject.export([options])#

對於對稱金鑰,可以使用以下編碼選項:

  • format <string> 必須是 'buffer' (預設) 或 'jwk'

對於公鑰,可以使用以下編碼選項:

  • type <string> 必須是 'pkcs1' (僅限 RSA) 或 'spki' 之一。
  • format <string> 必須是 'pem''der''jwk'

對於私鑰,可以使用以下編碼選項:

  • type <string> 必須是 'pkcs1' (僅限 RSA)、'pkcs8''sec1' (僅限 EC) 之一。
  • format <string> 必須是 'pem''der''jwk'
  • cipher <string> 如果指定,私鑰將使用給定的 cipherpassphrase 透過 PKCS#5 v2.0 基於密碼的加密進行加密。
  • passphrase <string> | <Buffer> 用於加密的密碼短語,參見 cipher

結果型別取決於所選的編碼格式,當為 PEM 時,結果為字串;當為 DER 時,它將是一個包含 DER 編碼資料的緩衝區;當為 JWK 時,它將是一個物件。

當選擇 JWK 編碼格式時,所有其他編碼選項都將被忽略。

PKCS#1、SEC1 和 PKCS#8 型別的金鑰可以透過結合使用 cipherformat 選項來加密。PKCS#8 type 可以與任何 format 一起使用,透過指定 cipher 來加密任何金鑰演算法(RSA、EC 或 DH)。PKCS#1 和 SEC1 只能在指定 cipher 且使用 PEM format 時進行加密。為了獲得最大的相容性,請使用 PKCS#8 來處理加密的私鑰。由於 PKCS#8 定義了自己的加密機制,因此在加密 PKCS#8 金鑰時不支援 PEM 級別的加密。有關 PKCS#8 加密,請參見 RFC 5208;有關 PKCS#1 和 SEC1 加密,請參見 RFC 1421

keyObject.symmetricKeySize#

對於金鑰,此屬性表示金鑰的大小(以位元組為單位)。對於非對稱金鑰,此屬性為 undefined

keyObject.toCryptoKey(algorithm, extractable, keyUsages)#

KeyObject 例項轉換為 CryptoKey

keyObject.type#

根據此 KeyObject 的型別,此屬性對於金鑰(對稱金鑰)為 'secret',對於公鑰(非對稱金鑰)為 'public',或對於私鑰(非對稱金鑰)為 'private'

類:Sign#

Sign 類是用於生成簽名的實用工具。它可以透過以下兩種方式之一使用:

crypto.createSign() 方法用於建立 Sign 例項。引數是所用雜湊函式的字串名稱。不應直接使用 new 關鍵字建立 Sign 物件。

示例:將 SignVerify 物件用作流

const {
  generateKeyPairSync,
  createSign,
  createVerify,
} = await import('node:crypto');

const { privateKey, publicKey } = generateKeyPairSync('ec', {
  namedCurve: 'sect239k1',
});

const sign = createSign('SHA256');
sign.write('some data to sign');
sign.end();
const signature = sign.sign(privateKey, 'hex');

const verify = createVerify('SHA256');
verify.write('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature, 'hex'));
// Prints: trueconst {
  generateKeyPairSync,
  createSign,
  createVerify,
} = require('node:crypto');

const { privateKey, publicKey } = generateKeyPairSync('ec', {
  namedCurve: 'sect239k1',
});

const sign = createSign('SHA256');
sign.write('some data to sign');
sign.end();
const signature = sign.sign(privateKey, 'hex');

const verify = createVerify('SHA256');
verify.write('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature, 'hex'));
// Prints: true

示例:使用 sign.update()verify.update() 方法

const {
  generateKeyPairSync,
  createSign,
  createVerify,
} = await import('node:crypto');

const { privateKey, publicKey } = generateKeyPairSync('rsa', {
  modulusLength: 2048,
});

const sign = createSign('SHA256');
sign.update('some data to sign');
sign.end();
const signature = sign.sign(privateKey);

const verify = createVerify('SHA256');
verify.update('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature));
// Prints: trueconst {
  generateKeyPairSync,
  createSign,
  createVerify,
} = require('node:crypto');

const { privateKey, publicKey } = generateKeyPairSync('rsa', {
  modulusLength: 2048,
});

const sign = createSign('SHA256');
sign.update('some data to sign');
sign.end();
const signature = sign.sign(privateKey);

const verify = createVerify('SHA256');
verify.update('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature));
// Prints: true

sign.sign(privateKey[, outputEncoding])#

計算透過 sign.update()sign.write() 傳入的所有資料的簽名。

如果 privateKey 不是一個 KeyObject,此函式的行為就好像 privateKey 已被傳遞給 crypto.createPrivateKey()。如果它是一個物件,可以傳遞以下附加屬性:

  • dsaEncoding <string> 對於 DSA 和 ECDSA,此選項指定生成簽名的格式。它可以是以下之一:

    • 'der' (預設): DER 編碼的 ASN.1 簽名結構,編碼為 (r, s)
    • 'ieee-p1363':IEEE-P1363 中提議的簽名格式 r || s
  • padding <integer> RSA 的可選填充值,為以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (預設)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

    RSA_PKCS1_PSS_PADDING 將使用 MGF1,其雜湊函式與用於簽署訊息的雜湊函式相同,如 RFC 4055 第 3.1 節所述,除非已根據 RFC 4055 第 3.3 節的規定,在金鑰中指定了 MGF1 雜湊函式。

  • saltLength <integer> 當填充為 RSA_PKCS1_PSS_PADDING 時的鹽長度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 將鹽長度設定為摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN (預設) 將其設定為最大允許值。

如果提供了 outputEncoding,則返回一個字串;否則返回一個 Buffer

sign.sign() 方法被呼叫後,Sign 物件不能再次使用。多次呼叫 sign.sign() 將導致丟擲錯誤。

sign.update(data[, inputEncoding])#

用給定的 data 更新 Sign 內容,其編碼在 inputEncoding 中給出。如果未提供 encoding,且 data 是一個字串,則強制使用 'utf8' 編碼。如果 data 是一個 BufferTypedArrayDataView,則忽略 inputEncoding

當新資料以流式傳輸時,可以多次呼叫此方法。

類:Verify#

Verify 類是用於驗證簽名的實用工具。它可以透過以下兩種方式之一使用:

crypto.createVerify() 方法用於建立 Verify 例項。不應直接使用 new 關鍵字建立 Verify 物件。

有關示例,請參見 Sign

verify.update(data[, inputEncoding])#

用給定的 data 更新 Verify 內容,其編碼在 inputEncoding 中給出。如果未提供 inputEncoding,且 data 是一個字串,則強制使用 'utf8' 編碼。如果 data 是一個 BufferTypedArrayDataView,則忽略 inputEncoding

當新資料以流式傳輸時,可以多次呼叫此方法。

verify.verify(object, signature[, signatureEncoding])#

使用給定的 objectsignature 驗證所提供的資料。

如果 object 不是一個 KeyObject,此函式的行為就好像 object 已被傳遞給 crypto.createPublicKey()。如果它是一個物件,可以傳遞以下附加屬性:

  • dsaEncoding <string> 對於 DSA 和 ECDSA,此選項指定簽名的格式。它可以是以下之一:

    • 'der' (預設): DER 編碼的 ASN.1 簽名結構,編碼為 (r, s)
    • 'ieee-p1363':IEEE-P1363 中提議的簽名格式 r || s
  • padding <integer> RSA 的可選填充值,為以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (預設)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

    RSA_PKCS1_PSS_PADDING 將使用 MGF1,其雜湊函式與用於驗證訊息的雜湊函式相同,如 RFC 4055 第 3.1 節所述,除非已根據 RFC 4055 第 3.3 節的規定,在金鑰中指定了 MGF1 雜湊函式。

  • saltLength <integer> 當填充為 RSA_PKCS1_PSS_PADDING 時的鹽長度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 將鹽長度設定為摘要大小,crypto.constants.RSA_PSS_SALTLEN_AUTO (預設) 使其自動確定。

signature 引數是先前為資料計算的簽名,其編碼為 signatureEncoding。如果指定了 signatureEncoding,則 signature 應為一個字串;否則 signature 應為一個 BufferTypedArrayDataView

verify.verify() 被呼叫後,verify 物件不能再次使用。多次呼叫 verify.verify() 將導致丟擲錯誤。

因為公鑰可以從私鑰派生,所以可以傳遞私鑰來代替公鑰。

類:X509Certificate#

封裝 X509 證書並提供對其資訊的只讀訪問。

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

const x509 = new X509Certificate('{... pem encoded cert ...}');

console.log(x509.subject);const { X509Certificate } = require('node:crypto');

const x509 = new X509Certificate('{... pem encoded cert ...}');

console.log(x509.subject);

new X509Certificate(buffer)#

x509.ca#

  • 型別:<boolean> 如果這是證書頒發機構 (CA) 證書,則為 true

x509.checkEmail(email[, options])#

檢查證書是否與給定的電子郵件地址匹配。

如果 'subject' 選項未定義或設定為 'default',則僅當主題備用名稱擴充套件不存在或不包含任何電子郵件地址時,才會考慮證書主題。

如果 'subject' 選項設定為 'always',並且主題備用名稱擴充套件不存在或不包含匹配的電子郵件地址,則會考慮證書主題。

如果 'subject' 選項設定為 'never',則永遠不會考慮證書主題,即使證書不包含主題備用名稱。

x509.checkHost(name[, options])#

  • name <string>
  • options <Object>
    • subject <string> 'default''always''never'預設值: 'default'
    • wildcards <boolean> 預設值: true
    • partialWildcards <boolean> 預設值: true
    • multiLabelWildcards <boolean> 預設值: false
    • singleLabelSubdomains <boolean> 預設值: false
  • 返回:<string> | <undefined> 返回與 name 匹配的主題名稱,如果沒有主題名稱匹配 name,則返回 undefined

檢查證書是否與給定的主機名匹配。

如果證書與給定的主機名匹配,則返回匹配的主題名稱。返回的名稱可能是精確匹配(例如 foo.example.com),也可能包含萬用字元(例如 *.example.com)。因為主機名比較不區分大小寫,所以返回的主題名稱的大小寫也可能與給定的 name 不同。

如果 'subject' 選項未定義或設定為 'default',則僅當主題備用名稱擴充套件不存在或不包含任何 DNS 名稱時,才會考慮證書主題。此行為與 RFC 2818(“HTTP Over TLS”)一致。

如果 'subject' 選項設定為 'always',並且主題備用名稱擴充套件不存在或不包含匹配的 DNS 名稱,則會考慮證書主題。

如果 'subject' 選項設定為 'never',則永遠不會考慮證書主題,即使證書不包含主題備用名稱。

x509.checkIP(ip)#

檢查證書是否與給定的 IP 地址(IPv4 或 IPv6)匹配。

僅考慮 RFC 5280 iPAddress 主題備用名稱,並且它們必須與給定的 ip 地址完全匹配。證書的其他主題備用名稱以及主題欄位將被忽略。

x509.checkIssued(otherCert)#

透過比較證書元資料,檢查此證書是否可能由給定的 otherCert 頒發。

這對於修剪可能的頒發者證書列表非常有用,這些證書是使用更基本的過濾例程(即僅基於主題和頒發者名稱)選擇的。

最後,要驗證此證書的簽名是由與 otherCert 的公鑰對應的私鑰生成的,請使用 x509.verify(publicKey),其中 otherCert 的公鑰表示為一個 KeyObject,如下所示

if (!x509.verify(otherCert.publicKey)) {
  throw new Error('otherCert did not issue x509');
} 

x509.checkPrivateKey(privateKey)#

檢查此證書的公鑰是否與給定的私鑰一致。

x509.fingerprint#

此證書的 SHA-1 指紋。

由於 SHA-1 在密碼學上已被破解,並且 SHA-1 的安全性明顯低於通常用於簽署證書的演算法,因此請考慮改用 x509.fingerprint256

x509.fingerprint256#

此證書的 SHA-256 指紋。

x509.fingerprint512#

此證書的 SHA-512 指紋。

由於計算 SHA-256 指紋通常更快,並且其大小僅為 SHA-512 指紋的一半,因此 x509.fingerprint256 可能是更好的選擇。雖然 SHA-512 通常被認為提供了更高的安全級別,但 SHA-256 的安全性與大多數常用於簽署證書的演算法相匹配。

x509.infoAccess#

證書的頒發機構資訊訪問擴充套件的文字表示。

這是一個以換行符分隔的訪問描述列表。每行以訪問方法和訪問位置的型別開頭,後跟一個冒號和與訪問位置關聯的值。

在表示訪問方法和訪問位置型別的字首之後,每行剩餘的部分可能會用引號括起來,以表明該值是一個 JSON 字串字面量。為了向後相容,Node.js 僅在為避免歧義而必要時才在此屬性內使用 JSON 字串字面量。第三方程式碼應準備好處理這兩種可能的條目格式。

x509.issuer#

此證書中包含的頒發者標識。

x509.issuerCertificate#

頒發者證書,如果頒發者證書不可用,則為 undefined

x509.keyUsage#

一個詳細說明此證書金鑰擴充套件用途的陣列。

x509.publicKey#

此證書的公鑰 <KeyObject>

x509.raw#

一個包含此證書 DER 編碼的 Buffer

x509.serialNumber#

此證書的序列號。

序列號由證書頒發機構分配,不能唯一標識證書。請考慮改用 x509.fingerprint256 作為唯一識別符號。

x509.subject#

此證書的完整主題。

x509.subjectAltName#

為此證書指定的主題備用名稱。

這是一個以逗號分隔的主題備用名稱列表。每個條目以一個標識主題備用名稱型別的字串開頭,後跟一個冒號和與該條目關聯的值。

早期版本的 Node.js 錯誤地假設在此屬性上按雙字元序列 ', ' 進行分割是安全的(參見 CVE-2021-44532)。然而,無論是惡意證書還是合法證書,在表示為字串時,其主題備用名稱都可能包含此序列。

在表示條目型別的字首之後,每個條目的剩餘部分可能會用引號括起來,以表明該值是一個 JSON 字串字面量。為了向後相容,Node.js 僅在為避免歧義而必要時才在此屬性內使用 JSON 字串字面量。第三方程式碼應準備好處理這兩種可能的條目格式。

x509.toJSON()#

沒有針對 X509 證書的標準 JSON 編碼。toJSON() 方法返回一個包含 PEM 編碼證書的字串。

x509.toLegacyObject()#

使用舊的 證書物件 編碼返回有關此證書的資訊。

x509.toString()#

返回 PEM 編碼的證書。

x509.validFrom#

此證書的有效起始日期/時間。

x509.validFromDate#

此證書的有效起始日期/時間,封裝在一個 Date 物件中。

x509.validTo#

此證書的有效截止日期/時間。

x509.validToDate#

此證書的有效截止日期/時間,封裝在一個 Date 物件中。

x509.signatureAlgorithm#

用於簽署證書的演算法,如果 OpenSSL 不知道該簽名演算法,則為 undefined

x509.signatureAlgorithmOid#

用於簽署證書的演算法的 OID。

x509.verify(publicKey)#

驗證此證書是否由給定的公鑰簽名。不對證書執行任何其他驗證檢查。

node:crypto 模組方法和屬性#

crypto.argon2(algorithm, parameters, callback)#

穩定性:1.2 - 候選釋出

提供一個非同步的 Argon2 實現。Argon2 是一種基於密碼的金鑰派生函式,旨在使計算和記憶體成本高昂,從而使暴力攻擊變得不划算。

nonce 應該儘可能唯一。建議 nonce 是隨機的且至少 16 位元組長。詳情請參閱 NIST SP 800-132

當為 messagenoncesecretassociatedData 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

callback 函式被呼叫時帶有兩個引數:errderivedKey。當金鑰派生失敗時,err 是一個異常物件,否則 errnullderivedKey 作為 Buffer 傳遞給回撥函式。

當任何輸入引數指定了無效的值或型別時,會丟擲異常。

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

const parameters = {
  message: 'password',
  nonce: randomBytes(16),
  parallelism: 4,
  tagLength: 64,
  memory: 65536,
  passes: 3,
};

argon2('argon2id', parameters, (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // 'af91dad...9520f15'
});const { argon2, randomBytes } = require('node:crypto');

const parameters = {
  message: 'password',
  nonce: randomBytes(16),
  parallelism: 4,
  tagLength: 64,
  memory: 65536,
  passes: 3,
};

argon2('argon2id', parameters, (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // 'af91dad...9520f15'
});

crypto.argon2Sync(algorithm, parameters)#

穩定性:1.2 - 候選釋出

  • algorithm <string> Argon2 的變體,為 "argon2d""argon2i""argon2id" 之一。
  • parameters <Object>
    • message <string> | <ArrayBuffer> | <Buffer> | <TypedArray> | <DataView> 必需,這是 Argon2 密碼雜湊應用的密碼。
    • nonce <string> | <ArrayBuffer> | <Buffer> | <TypedArray> | <DataView> 必需,必須至少為 8 位元組長。這是 Argon2 密碼雜湊應用的鹽。
    • parallelism <number> 必需,並行度決定了可以執行多少個計算鏈(通道)。必須大於 1 且小於 2**24-1
    • tagLength <number> 必需,要生成的金鑰長度。必須大於 4 且小於 2**32-1
    • memory <number> 必需,以 1KiB 塊為單位的記憶體成本。必須大於 8 * parallelism 且小於 2**32-1。實際塊數會向下取整到最接近 4 * parallelism 的倍數。
    • passes <number> 必需,傳遞次數(迭代次數)。必須大於 1 且小於 2**32-1
    • secret <string> | <ArrayBuffer> | <Buffer> | <TypedArray> | <DataView> | <undefined> 可選,隨機的附加輸入,類似於鹽,應與派生金鑰一起儲存。這在密碼雜湊應用中被稱為“胡椒”(pepper)。如果使用,長度不得超過 2**32-1 位元組。
    • associatedData <string> | <ArrayBuffer> | <Buffer> | <TypedArray> | <DataView> | <undefined> 可選,要新增到雜湊中的附加資料,功能上等同於鹽或秘密,但用於非隨機資料。如果使用,長度不得超過 2**32-1 位元組。
  • 返回:<Buffer>

提供一個同步的 Argon2 實現。Argon2 是一種基於密碼的金鑰派生函式,旨在使計算和記憶體成本高昂,從而使暴力攻擊變得不划算。

nonce 應該儘可能唯一。建議 nonce 是隨機的且至少 16 位元組長。詳情請參閱 NIST SP 800-132

當為 messagenoncesecretassociatedData 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

當金鑰派生失敗時,會丟擲異常,否則派生的金鑰將作為 Buffer 返回。

當任何輸入引數指定了無效的值或型別時,會丟擲異常。

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

const parameters = {
  message: 'password',
  nonce: randomBytes(16),
  parallelism: 4,
  tagLength: 64,
  memory: 65536,
  passes: 3,
};

const derivedKey = argon2Sync('argon2id', parameters);
console.log(derivedKey.toString('hex'));  // 'af91dad...9520f15'const { argon2Sync, randomBytes } = require('node:crypto');

const parameters = {
  message: 'password',
  nonce: randomBytes(16),
  parallelism: 4,
  tagLength: 64,
  memory: 65536,
  passes: 3,
};

const derivedKey = argon2Sync('argon2id', parameters);
console.log(derivedKey.toString('hex'));  // 'af91dad...9520f15'

crypto.checkPrime(candidate[, options], callback)#

  • candidate <ArrayBuffer> | <SharedArrayBuffer> | <TypedArray> | <Buffer> | <DataView> | <bigint> 一個可能的素數,編碼為任意長度的大端位元組序列。
  • options <Object>
    • checks <number> 要執行的 Miller-Rabin 機率性素性測試的迭代次數。當值為 0(零)時,將使用一定數量的檢查,使得對於隨機輸入,假陽性率最多為 2-64。選擇檢查次數時必須謹慎。有關更多詳細資訊,請參閱 OpenSSL 文件中關於 BN_is_prime_ex 函式的 nchecks 選項。預設值: 0
  • callback <Function>
    • err <Error> 如果在檢查期間發生錯誤,則設定為一個 <Error> 物件。
    • result <boolean> 如果候選數是素數且錯誤機率小於 0.25 ** options.checks,則為 true

檢查 candidate 的素性。

crypto.checkPrimeSync(candidate[, options])#

  • candidate <ArrayBuffer> | <SharedArrayBuffer> | <TypedArray> | <Buffer> | <DataView> | <bigint> 一個可能的素數,編碼為任意長度的大端位元組序列。
  • options <Object>
    • checks <number> 要執行的 Miller-Rabin 機率性素性測試的迭代次數。當值為 0(零)時,將使用一定數量的檢查,使得對於隨機輸入,假陽性率最多為 2-64。選擇檢查次數時必須謹慎。有關更多詳細資訊,請參閱 OpenSSL 文件中關於 BN_is_prime_ex 函式的 nchecks 選項。預設值: 0
  • 返回:<boolean> 如果候選數是素數且錯誤機率小於 0.25 ** options.checks,則為 true

檢查 candidate 的素性。

crypto.constants#

一個包含與加密和安全相關操作常用常量的物件。當前定義的具體常量在 加密常量 中有描述。

crypto.createCipheriv(algorithm, key, iv[, options])#

建立並返回一個 Cipheriv 物件,使用給定的 algorithmkey 和初始化向量 (iv)。

options 引數控制流行為,並且是可選的,除非使用 CCM 或 OCB 模式的密碼(例如 'aes-128-ccm')。在這種情況下,authTagLength 選項是必需的,並指定身份驗證標籤的長度(以位元組為單位),請參閱 CCM 模式。在 GCM 模式下,authTagLength 選項不是必需的,但可用於設定將由 getAuthTag() 返回的身份驗證標籤的長度,預設為 16 位元組。對於 chacha20-poly1305authTagLength 選項預設為 16 位元組。

algorithm 取決於 OpenSSL,例如 'aes192' 等。在最新的 OpenSSL 版本中,openssl list -cipher-algorithms 將顯示可用的密碼演算法。

keyalgorithm 使用的原始金鑰,iv初始化向量。兩個引數都必須是 'utf8' 編碼的字串、BuffersTypedArrayDataViewkey 也可以是型別為 secretKeyObject。如果密碼不需要初始化向量,iv 可以是 null

當為 keyiv 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

初始化向量應該是不可預測且唯一的;理想情況下,它們應該是加密安全的隨機數。它們不必是機密的:IV 通常只是以未加密的形式新增到密文訊息中。某些事物必須是不可預測且唯一的,但又不必是機密的,這聽起來可能有些矛盾;請記住,攻擊者必須不能提前預測出給定的 IV 將是什麼。

crypto.createDecipheriv(algorithm, key, iv[, options])#

建立並返回一個使用給定 algorithmkey 和初始化向量 (iv) 的 Decipheriv 物件。

options 引數控制流行為,並且是可選的,除非使用 CCM 或 OCB 模式的密碼(例如 'aes-128-ccm')。在這種情況下,authTagLength 選項是必需的,並指定身份驗證標籤的長度(以位元組為單位),請參閱 CCM 模式。對於 AES-GCM 和 chacha20-poly1305authTagLength 選項預設為 16 位元組,如果使用不同長度,則必須設定為不同的值。

algorithm 取決於 OpenSSL,例如 'aes192' 等。在最新的 OpenSSL 版本中,openssl list -cipher-algorithms 將顯示可用的密碼演算法。

keyalgorithm 使用的原始金鑰,iv初始化向量。兩個引數都必須是 'utf8' 編碼的字串、BuffersTypedArrayDataViewkey 也可以是型別為 secretKeyObject。如果密碼不需要初始化向量,iv 可以是 null

當為 keyiv 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

初始化向量應該是不可預測且唯一的;理想情況下,它們應該是加密安全的隨機數。它們不必是機密的:IV 通常只是以未加密的形式新增到密文訊息中。某些事物必須是不可預測且唯一的,但又不必是機密的,這聽起來可能有些矛盾;請記住,攻擊者必須不能提前預測出給定的 IV 將是什麼。

crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])#

使用提供的 prime 和一個可選的特定 generator 建立一個 DiffieHellman 金鑰交換物件。

generator 引數可以是一個數字、字串或 Buffer。如果未指定 generator,則使用值 2

如果指定了 primeEncoding,則 prime 應為字串;否則應為 BufferTypedArrayDataView

如果指定了 generatorEncoding,則 generator 應為字串;否則應為數字、BufferTypedArrayDataView

crypto.createDiffieHellman(primeLength[, generator])#

建立一個 DiffieHellman 金鑰交換物件,並使用可選的特定數值 generator 生成一個 primeLength 位的素數。如果未指定 generator,則使用值 2

crypto.createDiffieHellmanGroup(name)#

crypto.getDiffieHellman() 的別名

crypto.createECDH(curveName)#

使用由 curveName 字串指定的預定義曲線建立一個橢圓曲線迪菲-赫爾曼 (ECDH) 金鑰交換物件。使用 crypto.getCurves() 獲取可用曲線名稱的列表。在最新的 OpenSSL 版本中,openssl ecparam -list_curves 也會顯示每個可用橢圓曲線的名稱和描述。

crypto.createHash(algorithm[, options])#

建立並返回一個 Hash 物件,該物件可用於使用給定的 algorithm 生成雜湊摘要。可選的 options 引數控制流行為。對於 XOF 雜湊函式(如 'shake256'),可以使用 outputLength 選項來指定所需的輸出長度(以位元組為單位)。

algorithm 取決於平臺上 OpenSSL 版本支援的可用演算法。例如 'sha256''sha512' 等。在最新的 OpenSSL 版本中,openssl list -digest-algorithms 將顯示可用的摘要演算法。

示例:生成檔案的 sha256 校驗和

import {
  createReadStream,
} from 'node:fs';
import { argv } from 'node:process';
const {
  createHash,
} = await import('node:crypto');

const filename = argv[2];

const hash = createHash('sha256');

const input = createReadStream(filename);
input.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = input.read();
  if (data)
    hash.update(data);
  else {
    console.log(`${hash.digest('hex')} ${filename}`);
  }
});const {
  createReadStream,
} = require('node:fs');
const {
  createHash,
} = require('node:crypto');
const { argv } = require('node:process');

const filename = argv[2];

const hash = createHash('sha256');

const input = createReadStream(filename);
input.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = input.read();
  if (data)
    hash.update(data);
  else {
    console.log(`${hash.digest('hex')} ${filename}`);
  }
});

crypto.createHmac(algorithm, key[, options])#

建立並返回一個使用給定 algorithmkeyHmac 物件。可選的 options 引數控制流行為。

algorithm 取決於平臺上 OpenSSL 版本支援的可用演算法。例如 'sha256''sha512' 等。在最新的 OpenSSL 版本中,openssl list -digest-algorithms 將顯示可用的摘要演算法。

key 是用於生成加密 HMAC 雜湊的 HMAC 金鑰。如果它是一個 KeyObject,其型別必須是 secret。如果它是一個字串,請考慮將字串用作加密 API 輸入時的注意事項。如果它是從加密安全的熵源(如 crypto.randomBytes()crypto.generateKey())獲得的,其長度不應超過 algorithm 的塊大小(例如,對於 SHA-256 為 512 位)。

示例:生成檔案的 sha256 HMAC

import {
  createReadStream,
} from 'node:fs';
import { argv } from 'node:process';
const {
  createHmac,
} = await import('node:crypto');

const filename = argv[2];

const hmac = createHmac('sha256', 'a secret');

const input = createReadStream(filename);
input.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = input.read();
  if (data)
    hmac.update(data);
  else {
    console.log(`${hmac.digest('hex')} ${filename}`);
  }
});const {
  createReadStream,
} = require('node:fs');
const {
  createHmac,
} = require('node:crypto');
const { argv } = require('node:process');

const filename = argv[2];

const hmac = createHmac('sha256', 'a secret');

const input = createReadStream(filename);
input.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = input.read();
  if (data)
    hmac.update(data);
  else {
    console.log(`${hmac.digest('hex')} ${filename}`);
  }
});

crypto.createPrivateKey(key)#

建立並返回一個包含私鑰的新金鑰物件。如果 key 是字串或 Buffer,則假定 format'pem';否則,key 必須是具有上述屬性的物件。

如果私鑰已加密,則必須指定 passphrase。密碼短語的長度限制為 1024 位元組。

crypto.createPublicKey(key)#

建立並返回一個包含公鑰的新金鑰物件。如果 key 是字串或 Buffer,則假定 format'pem';如果 key 是一個型別為 'private'KeyObject,則公鑰從給定的私鑰派生;否則,key 必須是具有上述屬性的物件。

如果格式是 'pem''key' 也可以是 X.509 證書。

因為公鑰可以從私鑰派生,所以可以傳遞私鑰來代替公鑰。在這種情況下,此函式的行為就好像呼叫了 crypto.createPrivateKey() 一樣,只是返回的 KeyObject 的型別將是 'public',並且無法從返回的 KeyObject 中提取私鑰。類似地,如果給定一個型別為 'private'KeyObject,將返回一個型別為 'public' 的新 KeyObject,並且無法從返回的物件中提取私鑰。

crypto.createSecretKey(key[, encoding])#

建立並返回一個包含用於對稱加密或 Hmac 的金鑰的新金鑰物件。

crypto.createSign(algorithm[, options])#

建立並返回一個使用給定 algorithmSign 物件。使用 crypto.getHashes() 獲取可用摘要演算法的名稱。可選的 options 引數控制 stream.Writable 行為。

在某些情況下,可以使用簽名演算法的名稱(如 'RSA-SHA256')來建立 Sign 例項,而不是摘要演算法的名稱。這將使用相應的摘要演算法。但這不適用於所有簽名演算法,例如 'ecdsa-with-SHA256',所以最好總是使用摘要演算法的名稱。

crypto.createVerify(algorithm[, options])#

建立並返回一個使用給定演算法的 Verify 物件。使用 crypto.getHashes() 獲取可用簽名演算法名稱的陣列。可選的 options 引數控制 stream.Writable 行為。

在某些情況下,可以使用簽名演算法的名稱(如 'RSA-SHA256')來建立 Verify 例項,而不是摘要演算法的名稱。這將使用相應的摘要演算法。但這不適用於所有簽名演算法,例如 'ecdsa-with-SHA256',所以最好總是使用摘要演算法的名稱。

crypto.decapsulate(key, ciphertext[, callback])#

穩定性:1.2 - 候選釋出

使用 KEM 演算法和私鑰進行金鑰解封裝。

支援的金鑰型別及其 KEM 演算法如下

  • 'rsa'2 RSA 秘密值封裝
  • 'ec'3 DHKEM(P-256, HKDF-SHA256), DHKEM(P-384, HKDF-SHA256), DHKEM(P-521, HKDF-SHA256)
  • 'x25519'3 DHKEM(X25519, HKDF-SHA256)
  • 'x448'3 DHKEM(X448, HKDF-SHA512)
  • 'ml-kem-512'1 ML-KEM
  • 'ml-kem-768'1 ML-KEM
  • 'ml-kem-1024'1 ML-KEM

如果 key 不是 KeyObject,此函式的行為就好像將 key 傳遞給了 crypto.createPrivateKey() 一樣。

如果提供了 callback 函式,此函式將使用 libuv 的執行緒池。

crypto.diffieHellman(options[, callback])#

根據 privateKeypublicKey 計算 Diffie-Hellman 共享金鑰。兩個金鑰必須具有相同的 asymmetricKeyType,並且必須支援 DH 或 ECDH 操作。

如果提供了 callback 函式,此函式將使用 libuv 的執行緒池。

crypto.encapsulate(key[, callback])#

穩定性:1.2 - 候選釋出

使用 KEM 演算法和公鑰進行金鑰封裝。

支援的金鑰型別及其 KEM 演算法如下

  • 'rsa'2 RSA 秘密值封裝
  • 'ec'3 DHKEM(P-256, HKDF-SHA256), DHKEM(P-384, HKDF-SHA256), DHKEM(P-521, HKDF-SHA256)
  • 'x25519'3 DHKEM(X25519, HKDF-SHA256)
  • 'x448'3 DHKEM(X448, HKDF-SHA512)
  • 'ml-kem-512'1 ML-KEM
  • 'ml-kem-768'1 ML-KEM
  • 'ml-kem-1024'1 ML-KEM

如果 key 不是 KeyObject,此函式的行為就好像將 key 傳遞給了 crypto.createPublicKey() 一樣。

如果提供了 callback 函式,此函式將使用 libuv 的執行緒池。

crypto.fips#

穩定性: 0 - 廢棄

用於檢查和控制當前是否正在使用符合 FIPS 的加密提供程式的屬性。設定為 true 需要 Node.js 的 FIPS 構建版本。

此屬性已棄用。請改用 crypto.setFips()crypto.getFips()

crypto.generateKey(type, options, callback)#

  • type <string> 生成的金鑰的預期用途。當前接受的值是 'hmac''aes'
  • options <Object>
    • length <number> 要生成的金鑰的位長度。此值必須大於 0。
      • 如果 type'hmac',最小值為 8,最大長度為 231-1。如果該值不是 8 的倍數,生成的金鑰將被截斷為 Math.floor(length / 8)
      • 如果 type'aes',長度必須是 128192256 之一。
  • callback <Function>

非同步生成一個給定 length 的新隨機金鑰。type 將決定對 length 執行哪些驗證。

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

generateKey('hmac', { length: 512 }, (err, key) => {
  if (err) throw err;
  console.log(key.export().toString('hex'));  // 46e..........620
});const {
  generateKey,
} = require('node:crypto');

generateKey('hmac', { length: 512 }, (err, key) => {
  if (err) throw err;
  console.log(key.export().toString('hex'));  // 46e..........620
});

生成的 HMAC 金鑰的大小不應超過底層雜湊函式的塊大小。有關更多資訊,請參閱 crypto.createHmac()

crypto.generateKeyPair(type, options, callback)#

生成給定 type 的新非對稱金鑰對。目前支援 RSA、RSA-PSS、DSA、EC、Ed25519、Ed448、X25519、X448 和 DH。

如果指定了 publicKeyEncodingprivateKeyEncoding,此函式的行為就好像在其結果上呼叫了 keyObject.export()。否則,金鑰的相應部分將作為 KeyObject 返回。

建議將公鑰編碼為 'spki',將私鑰編碼為 'pkcs8' 並進行加密以供長期儲存。

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

generateKeyPair('rsa', {
  modulusLength: 4096,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem',
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: 'top secret',
  },
}, (err, publicKey, privateKey) => {
  // Handle errors and use the generated key pair.
});const {
  generateKeyPair,
} = require('node:crypto');

generateKeyPair('rsa', {
  modulusLength: 4096,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem',
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: 'top secret',
  },
}, (err, publicKey, privateKey) => {
  // Handle errors and use the generated key pair.
});

完成後,將呼叫 callback,其中 err 設定為 undefinedpublicKey / privateKey 表示生成的金鑰對。

如果此方法作為其 util.promisify() 版本被呼叫,它將返回一個 Promise,該 Promise 解析為一個具有 publicKeyprivateKey 屬性的物件。

crypto.generateKeyPairSync(type, options)#

生成給定 type 的新非對稱金鑰對。目前支援 RSA、RSA-PSS、DSA、EC、Ed25519、Ed448、X25519、X448、DH 和 ML-DSA1

如果指定了 publicKeyEncodingprivateKeyEncoding,此函式的行為就好像在其結果上呼叫了 keyObject.export()。否則,金鑰的相應部分將作為 KeyObject 返回。

編碼公鑰時,建議使用 'spki'。編碼私鑰時,建議使用 'pkcs8' 和強密碼,並對密碼保密。

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

const {
  publicKey,
  privateKey,
} = generateKeyPairSync('rsa', {
  modulusLength: 4096,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem',
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: 'top secret',
  },
});const {
  generateKeyPairSync,
} = require('node:crypto');

const {
  publicKey,
  privateKey,
} = generateKeyPairSync('rsa', {
  modulusLength: 4096,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem',
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: 'top secret',
  },
});

返回值 { publicKey, privateKey } 表示生成的金鑰對。當選擇 PEM 編碼時,相應的金鑰將是一個字串,否則它將是一個包含 DER 編碼資料的緩衝區。

crypto.generateKeySync(type, options)#

  • type <string> 生成的金鑰的預期用途。當前接受的值是 'hmac''aes'
  • options <Object>
    • length <number> 要生成的金鑰的位長度。
      • 如果 type'hmac',最小值為 8,最大長度為 231-1。如果該值不是 8 的倍數,生成的金鑰將被截斷為 Math.floor(length / 8)
      • 如果 type'aes',長度必須是 128192256 之一。
  • 返回:<KeyObject>

同步生成一個給定 length 的新隨機金鑰。type 將決定對 length 執行哪些驗證。

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

const key = generateKeySync('hmac', { length: 512 });
console.log(key.export().toString('hex'));  // e89..........41econst {
  generateKeySync,
} = require('node:crypto');

const key = generateKeySync('hmac', { length: 512 });
console.log(key.export().toString('hex'));  // e89..........41e

生成的 HMAC 金鑰的大小不應超過底層雜湊函式的塊大小。有關更多資訊,請參閱 crypto.createHmac()

crypto.generatePrime(size[, options], callback)#

生成一個 size 位的偽隨機素數。

如果 options.safetrue,則該素數將是一個安全素數——也就是說,(prime - 1) / 2 也將是一個素數。

options.addoptions.rem 引數可用於強制執行附加要求,例如用於 Diffie-Hellman

  • 如果 options.addoptions.rem 都被設定,素數將滿足條件 prime % add = rem
  • 如果僅設定了 options.addoptions.safe 不為 true,則素數將滿足條件 prime % add = 1
  • 如果僅設定了 options.addoptions.safe 設定為 true,則素數將改為滿足條件 prime % add = 3。這是必要的,因為對於 options.add > 2prime % add = 1 會與 options.safe 強制執行的條件相矛盾。
  • 如果未給出 options.add,則忽略 options.rem

如果 options.addoptions.remArrayBufferSharedArrayBufferTypedArrayBufferDataView 的形式給出,則它們必須編碼為大端序列。

預設情況下,素數被編碼為 <ArrayBuffer> 中的大端八位位元組序列。如果 bigint 選項為 true,則提供一個 <bigint>

素數的 size 會直接影響生成素數所需的時間。size 越大,所需時間越長。因為我們使用 OpenSSL 的 BN_generate_prime_ex 函式,該函式對我們中斷生成過程的能力控制很小,所以不建議生成過大的素數,因為這樣做可能會使程序無響應。

crypto.generatePrimeSync(size[, options])#

生成一個 size 位的偽隨機素數。

如果 options.safetrue,則該素數將是一個安全素數——也就是說,(prime - 1) / 2 也將是一個素數。

options.addoptions.rem 引數可用於強制執行附加要求,例如用於 Diffie-Hellman

  • 如果 options.addoptions.rem 都被設定,素數將滿足條件 prime % add = rem
  • 如果僅設定了 options.addoptions.safe 不為 true,則素數將滿足條件 prime % add = 1
  • 如果僅設定了 options.addoptions.safe 設定為 true,則素數將改為滿足條件 prime % add = 3。這是必要的,因為對於 options.add > 2prime % add = 1 會與 options.safe 強制執行的條件相矛盾。
  • 如果未給出 options.add,則忽略 options.rem

如果 options.addoptions.remArrayBufferSharedArrayBufferTypedArrayBufferDataView 的形式給出,則它們必須編碼為大端序列。

預設情況下,素數被編碼為 <ArrayBuffer> 中的大端八位位元組序列。如果 bigint 選項為 true,則提供一個 <bigint>

素數的 size 會直接影響生成素數所需的時間。size 越大,所需時間越長。因為我們使用 OpenSSL 的 BN_generate_prime_ex 函式,該函式對我們中斷生成過程的能力控制很小,所以不建議生成過大的素數,因為這樣做可能會使程序無響應。

crypto.getCipherInfo(nameOrNid[, options])#

  • nameOrNid <string> | <number> 要查詢的密碼的名稱或 nid。
  • options <Object>
    • keyLength <number> 一個測試金鑰長度。
    • ivLength <number> 一個測試 IV 長度。
  • 返回:<Object>
    • name <string> 密碼的名稱
    • nid <number> 密碼的 nid
    • blockSize <number> 密碼的塊大小(以位元組為單位)。當 mode'stream' 時,此屬性被省略。
    • ivLength <number> 預期的或預設的初始化向量長度(以位元組為單位)。如果密碼不使用初始化向量,則省略此屬性。
    • keyLength <number> 預期的或預設的金鑰長度(以位元組為單位)。
    • mode <string> 密碼模式。為 'cbc''ccm''cfb''ctr''ecb''gcm''ocb''ofb''stream''wrap''xts' 之一。

返回有關給定密碼的資訊。

一些密碼接受可變長度的金鑰和初始化向量。預設情況下,crypto.getCipherInfo() 方法將返回這些密碼的預設值。要測試給定的金鑰長度或 IV 長度是否適用於給定的密碼,請使用 keyLengthivLength 選項。如果給定的值不可接受,將返回 undefined

crypto.getCiphers()#

  • 返回:<string[]> 一個包含支援的密碼演算法名稱的陣列。
const {
  getCiphers,
} = await import('node:crypto');

console.log(getCiphers()); // ['aes-128-cbc', 'aes-128-ccm', ...]const {
  getCiphers,
} = require('node:crypto');

console.log(getCiphers()); // ['aes-128-cbc', 'aes-128-ccm', ...]

crypto.getCurves()#

  • 返回:<string[]> 一個包含支援的橢圓曲線名稱的陣列。
const {
  getCurves,
} = await import('node:crypto');

console.log(getCurves()); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]const {
  getCurves,
} = require('node:crypto');

console.log(getCurves()); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]

crypto.getDiffieHellman(groupName)#

建立一個預定義的 DiffieHellmanGroup 金鑰交換物件。支援的組在 DiffieHellmanGroup 的文件中列出。

返回的物件模仿由 crypto.createDiffieHellman() 建立的物件的介面,但不允許更改金鑰(例如,使用 diffieHellman.setPublicKey())。使用此方法的優點是各方不必事先生成或交換組模數,從而節省了處理器和通訊時間。

示例(獲取共享金鑰)

const {
  getDiffieHellman,
} = await import('node:crypto');
const alice = getDiffieHellman('modp14');
const bob = getDiffieHellman('modp14');

alice.generateKeys();
bob.generateKeys();

const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex');

/* aliceSecret and bobSecret should be the same */
console.log(aliceSecret === bobSecret);const {
  getDiffieHellman,
} = require('node:crypto');

const alice = getDiffieHellman('modp14');
const bob = getDiffieHellman('modp14');

alice.generateKeys();
bob.generateKeys();

const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex');

/* aliceSecret and bobSecret should be the same */
console.log(aliceSecret === bobSecret);

crypto.getFips()#

  • 返回:<number> 當且僅當當前正在使用符合 FIPS 的加密提供程式時返回 1,否則返回 0。未來的 semver-major 版本可能會將此 API 的返回型別更改為 <boolean>

crypto.getHashes()#

  • 返回:<string[]> 一個包含支援的雜湊演算法名稱的陣列,例如 'RSA-SHA256'。雜湊演算法也稱為“摘要”演算法。
const {
  getHashes,
} = await import('node:crypto');

console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]const {
  getHashes,
} = require('node:crypto');

console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]

crypto.getRandomValues(typedArray)#

crypto.webcrypto.getRandomValues() 的一個方便別名。此實現不符合 Web Crypto 規範,要編寫與 Web 相容的程式碼,請改用 crypto.webcrypto.getRandomValues()

crypto.hash(algorithm, data[, options])#

穩定性:1.2 - 候選釋出

  • algorithm <string> | <undefined>
  • data <string> | <Buffer> | <TypedArray> | <DataView>data 是字串時,它將在雜湊前被編碼為 UTF-8。如果希望對字串輸入使用不同的輸入編碼,使用者可以使用 TextEncoderBuffer.from() 將字串編碼為 TypedArray,然後將編碼後的 TypedArray 傳遞給此 API。
  • options <Object> | <string>
    • outputEncoding <string> 用於編碼返回的摘要的編碼預設值: 'hex'
    • outputLength <number> 對於 XOF 雜湊函式(如 'shake256'),可以使用 outputLength 選項來指定所需的輸出長度(以位元組為單位)。
  • 返回:<string> | <Buffer>

一個用於建立資料的一次性雜湊摘要的實用工具。在對較小量(<= 5MB)且已準備好的資料進行雜湊時,它可能比基於物件的 crypto.createHash() 更快。如果資料可能很大或是流式資料,仍建議使用 crypto.createHash()

algorithm 取決於平臺上 OpenSSL 版本支援的可用演算法。例如 'sha256''sha512' 等。在最新的 OpenSSL 版本中,openssl list -digest-algorithms 將顯示可用的摘要演算法。

如果 options 是一個字串,則它指定了 outputEncoding

示例

const crypto = require('node:crypto');
const { Buffer } = require('node:buffer');

// Hashing a string and return the result as a hex-encoded string.
const string = 'Node.js';
// 10b3493287f831e81a438811a1ffba01f8cec4b7
console.log(crypto.hash('sha1', string));

// Encode a base64-encoded string into a Buffer, hash it and return
// the result as a buffer.
const base64 = 'Tm9kZS5qcw==';
// <Buffer 10 b3 49 32 87 f8 31 e8 1a 43 88 11 a1 ff ba 01 f8 ce c4 b7>
console.log(crypto.hash('sha1', Buffer.from(base64, 'base64'), 'buffer'));import crypto from 'node:crypto';
import { Buffer } from 'node:buffer';

// Hashing a string and return the result as a hex-encoded string.
const string = 'Node.js';
// 10b3493287f831e81a438811a1ffba01f8cec4b7
console.log(crypto.hash('sha1', string));

// Encode a base64-encoded string into a Buffer, hash it and return
// the result as a buffer.
const base64 = 'Tm9kZS5qcw==';
// <Buffer 10 b3 49 32 87 f8 31 e8 1a 43 88 11 a1 ff ba 01 f8 ce c4 b7>
console.log(crypto.hash('sha1', Buffer.from(base64, 'base64'), 'buffer'));

crypto.hkdf(digest, ikm, salt, info, keylen, callback)#

HKDF 是 RFC 5869 中定義的一個簡單的金鑰派生函式。給定的 ikmsaltinfodigest 一起用於派生一個長度為 keylen 位元組的金鑰。

提供的 callback 函式被呼叫時帶有兩個引數:errderivedKey。如果在派生金鑰時發生錯誤,err 將被設定;否則 err 將為 null。成功生成的 derivedKey 將作為 <ArrayBuffer> 傳遞給回撥函式。如果任何輸入引數指定了無效的值或型別,將丟擲錯誤。

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

hkdf('sha512', 'key', 'salt', 'info', 64, (err, derivedKey) => {
  if (err) throw err;
  console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'
});const {
  hkdf,
} = require('node:crypto');
const { Buffer } = require('node:buffer');

hkdf('sha512', 'key', 'salt', 'info', 64, (err, derivedKey) => {
  if (err) throw err;
  console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'
});

crypto.hkdfSync(digest, ikm, salt, info, keylen)#

提供一個同步的 HKDF 金鑰派生函式,如 RFC 5869 中定義。給定的 ikmsaltinfodigest 一起用於派生一個長度為 keylen 位元組的金鑰。

成功生成的 derivedKey 將作為 <ArrayBuffer> 返回。

如果任何輸入引數指定了無效的值或型別,或者無法生成派生金鑰,則將丟擲錯誤。

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

const derivedKey = hkdfSync('sha512', 'key', 'salt', 'info', 64);
console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'const {
  hkdfSync,
} = require('node:crypto');
const { Buffer } = require('node:buffer');

const derivedKey = hkdfSync('sha512', 'key', 'salt', 'info', 64);
console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'

crypto.pbkdf2(password, salt, iterations, keylen, digest, callback)#

提供一個非同步的基於密碼的金鑰派生函式 2 (PBKDF2) 的實現。它應用由 digest 指定的 HMAC 摘要演算法,從 passwordsaltiterations 中派生出所需位元組長度 (keylen) 的金鑰。

提供的 callback 函式被呼叫時會帶有兩個引數:errderivedKey。如果在派生金鑰時發生錯誤,err 將被設定;否則 err 將為 null。預設情況下,成功生成的 derivedKey 將作為 Buffer 傳遞給回撥函式。如果任何輸入引數指定了無效的值或型別,則會丟擲錯誤。

iterations 引數必須是一個數字,並且設定得越高越好。迭代次數越多,派生出的金鑰就越安全,但完成所需的時間也越長。

salt 應儘可能唯一。建議 salt 是隨機的,並且長度至少為 16 位元組。詳情請參閱 NIST SP 800-132

當為 passwordsalt 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

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

pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
});const {
  pbkdf2,
} = require('node:crypto');

pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
});

可以使用 crypto.getHashes() 獲取支援的摘要函式陣列。

此 API 使用 libuv 的執行緒池,這可能對某些應用程式產生意想不到的負面性能影響;更多資訊請參閱 UV_THREADPOOL_SIZE 文件。

crypto.pbkdf2Sync(password, salt, iterations, keylen, digest)#

提供一個同步的基於密碼的金鑰派生函式 2 (PBKDF2) 的實現。它應用由 digest 指定的 HMAC 摘要演算法,從 passwordsaltiterations 中派生出所需位元組長度 (keylen) 的金鑰。

如果發生錯誤,將丟擲 Error,否則派生的金鑰將作為 Buffer 返回。

iterations 引數必須是一個數字,並且設定得越高越好。迭代次數越多,派生出的金鑰就越安全,但完成所需的時間也越長。

salt 應儘可能唯一。建議 salt 是隨機的,並且長度至少為 16 位元組。詳情請參閱 NIST SP 800-132

當為 passwordsalt 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

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

const key = pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512');
console.log(key.toString('hex'));  // '3745e48...08d59ae'const {
  pbkdf2Sync,
} = require('node:crypto');

const key = pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512');
console.log(key.toString('hex'));  // '3745e48...08d59ae'

可以使用 crypto.getHashes() 獲取支援的摘要函式陣列。

crypto.privateDecrypt(privateKey, buffer)#

使用 privateKey 解密 bufferbuffer 之前是使用相應的公鑰加密的,例如使用 crypto.publicEncrypt()

如果 privateKey 不是 KeyObject,此函式的行為就如同將 privateKey 傳遞給了 crypto.createPrivateKey()。如果它是一個物件,則可以傳遞 padding 屬性。否則,此函式使用 RSA_PKCS1_OAEP_PADDING

crypto.privateDecrypt() 中使用 crypto.constants.RSA_PKCS1_PADDING 要求 OpenSSL 支援隱式拒絕(rsa_pkcs1_implicit_rejection)。如果 Node.js 使用的 OpenSSL 版本不支援此功能,嘗試使用 RSA_PKCS1_PADDING 將會失敗。

crypto.privateEncrypt(privateKey, buffer)#

使用 privateKey 加密 buffer。返回的資料可以使用相應的公鑰解密,例如使用 crypto.publicDecrypt()

如果 privateKey 不是 KeyObject,此函式的行為就如同將 privateKey 傳遞給了 crypto.createPrivateKey()。如果它是一個物件,則可以傳遞 padding 屬性。否則,此函式使用 RSA_PKCS1_PADDING

crypto.publicDecrypt(key, buffer)#

使用 key 解密 bufferbuffer 之前是使用相應的私鑰加密的,例如使用 crypto.privateEncrypt()

如果 key 不是 KeyObject,此函式的行為就如同將 key 傳遞給了 crypto.createPublicKey()。如果它是一個物件,則可以傳遞 padding 屬性。否則,此函式使用 RSA_PKCS1_PADDING

因為 RSA 公鑰可以從私鑰派生,所以可以傳遞私鑰而不是公鑰。

crypto.publicEncrypt(key, buffer)#

使用 key 加密 buffer 的內容,並返回一個包含加密內容的新 Buffer。返回的資料可以使用相應的私鑰解密,例如使用 crypto.privateDecrypt()

如果 key 不是 KeyObject,此函式的行為就如同將 key 傳遞給了 crypto.createPublicKey()。如果它是一個物件,則可以傳遞 padding 屬性。否則,此函式使用 RSA_PKCS1_OAEP_PADDING

因為 RSA 公鑰可以從私鑰派生,所以可以傳遞私鑰而不是公鑰。

crypto.randomBytes(size[, callback])#

生成密碼學上強偽隨機資料。size 引數是一個數字,指示要生成的位元組數。

如果提供了 callback 函式,則位元組會非同步生成,並且 callback 函式會被呼叫並帶有兩個引數:errbuf。如果發生錯誤,err 將是一個 Error 物件;否則為 nullbuf 引數是一個包含所生成位元組的 Buffer

// Asynchronous
const {
  randomBytes,
} = await import('node:crypto');

randomBytes(256, (err, buf) => {
  if (err) throw err;
  console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`);
});// Asynchronous
const {
  randomBytes,
} = require('node:crypto');

randomBytes(256, (err, buf) => {
  if (err) throw err;
  console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`);
});

如果沒有提供 callback 函式,則隨機位元組會同步生成並作為 Buffer 返回。如果在生成位元組時出現問題,將丟擲錯誤。

// Synchronous
const {
  randomBytes,
} = await import('node:crypto');

const buf = randomBytes(256);
console.log(
  `${buf.length} bytes of random data: ${buf.toString('hex')}`);// Synchronous
const {
  randomBytes,
} = require('node:crypto');

const buf = randomBytes(256);
console.log(
  `${buf.length} bytes of random data: ${buf.toString('hex')}`);

crypto.randomBytes() 方法直到有足夠的可用熵時才會完成。這通常不應超過幾毫秒。唯一可能導致生成隨機位元組阻塞較長時間的情況是在系統啟動後不久,此時整個系統熵較低。

此 API 使用 libuv 的執行緒池,這可能對某些應用程式產生意想不到的負面性能影響;更多資訊請參閱 UV_THREADPOOL_SIZE 文件。

crypto.randomBytes() 的非同步版本在一個執行緒池請求中執行。為了最小化執行緒池任務長度的變化,在作為滿足客戶端請求的一部分執行此操作時,請將大的 randomBytes 請求進行分割槽。

crypto.randomFill(buffer[, offset][, size], callback)#

此函式類似於 crypto.randomBytes(),但要求第一個引數是一個將被填充的 Buffer。它還要求傳入一個回撥函式。

如果沒有提供 callback 函式,將丟擲錯誤。

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

const buf = Buffer.alloc(10);
randomFill(buf, (err, buf) => {
  if (err) throw err;
  console.log(buf.toString('hex'));
});

randomFill(buf, 5, (err, buf) => {
  if (err) throw err;
  console.log(buf.toString('hex'));
});

// The above is equivalent to the following:
randomFill(buf, 5, 5, (err, buf) => {
  if (err) throw err;
  console.log(buf.toString('hex'));
});const { randomFill } = require('node:crypto');
const { Buffer } = require('node:buffer');

const buf = Buffer.alloc(10);
randomFill(buf, (err, buf) => {
  if (err) throw err;
  console.log(buf.toString('hex'));
});

randomFill(buf, 5, (err, buf) => {
  if (err) throw err;
  console.log(buf.toString('hex'));
});

// The above is equivalent to the following:
randomFill(buf, 5, 5, (err, buf) => {
  if (err) throw err;
  console.log(buf.toString('hex'));
});

任何 ArrayBufferTypedArrayDataView 例項都可以作為 buffer 傳遞。

雖然這包括 Float32ArrayFloat64Array 的例項,但不應使用此函式生成隨機浮點數。結果可能包含 +Infinity-InfinityNaN,即使陣列僅包含有限的數字,它們也不是從均勻隨機分佈中抽取的,並且沒有有意義的下限或上限。

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

const a = new Uint32Array(10);
randomFill(a, (err, buf) => {
  if (err) throw err;
  console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
    .toString('hex'));
});

const b = new DataView(new ArrayBuffer(10));
randomFill(b, (err, buf) => {
  if (err) throw err;
  console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
    .toString('hex'));
});

const c = new ArrayBuffer(10);
randomFill(c, (err, buf) => {
  if (err) throw err;
  console.log(Buffer.from(buf).toString('hex'));
});const { randomFill } = require('node:crypto');
const { Buffer } = require('node:buffer');

const a = new Uint32Array(10);
randomFill(a, (err, buf) => {
  if (err) throw err;
  console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
    .toString('hex'));
});

const b = new DataView(new ArrayBuffer(10));
randomFill(b, (err, buf) => {
  if (err) throw err;
  console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
    .toString('hex'));
});

const c = new ArrayBuffer(10);
randomFill(c, (err, buf) => {
  if (err) throw err;
  console.log(Buffer.from(buf).toString('hex'));
});

此 API 使用 libuv 的執行緒池,這可能對某些應用程式產生意想不到的負面性能影響;更多資訊請參閱 UV_THREADPOOL_SIZE 文件。

crypto.randomFill() 的非同步版本在一個執行緒池請求中執行。為了最小化執行緒池任務長度的變化,在作為滿足客戶端請求的一部分執行此操作時,請將大的 randomFill 請求進行分割槽。

crypto.randomFillSync(buffer[, offset][, size])#

crypto.randomFill() 的同步版本。

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

const buf = Buffer.alloc(10);
console.log(randomFillSync(buf).toString('hex'));

randomFillSync(buf, 5);
console.log(buf.toString('hex'));

// The above is equivalent to the following:
randomFillSync(buf, 5, 5);
console.log(buf.toString('hex'));const { randomFillSync } = require('node:crypto');
const { Buffer } = require('node:buffer');

const buf = Buffer.alloc(10);
console.log(randomFillSync(buf).toString('hex'));

randomFillSync(buf, 5);
console.log(buf.toString('hex'));

// The above is equivalent to the following:
randomFillSync(buf, 5, 5);
console.log(buf.toString('hex'));

任何 ArrayBufferTypedArrayDataView 例項都可以作為 buffer 傳遞。

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

const a = new Uint32Array(10);
console.log(Buffer.from(randomFillSync(a).buffer,
                        a.byteOffset, a.byteLength).toString('hex'));

const b = new DataView(new ArrayBuffer(10));
console.log(Buffer.from(randomFillSync(b).buffer,
                        b.byteOffset, b.byteLength).toString('hex'));

const c = new ArrayBuffer(10);
console.log(Buffer.from(randomFillSync(c)).toString('hex'));const { randomFillSync } = require('node:crypto');
const { Buffer } = require('node:buffer');

const a = new Uint32Array(10);
console.log(Buffer.from(randomFillSync(a).buffer,
                        a.byteOffset, a.byteLength).toString('hex'));

const b = new DataView(new ArrayBuffer(10));
console.log(Buffer.from(randomFillSync(b).buffer,
                        b.byteOffset, b.byteLength).toString('hex'));

const c = new ArrayBuffer(10);
console.log(Buffer.from(randomFillSync(c)).toString('hex'));

crypto.randomInt([min, ]max[, callback])#

  • min <integer> 隨機範圍的起始值(包含)。預設值: 0
  • max <integer> 隨機範圍的結束值(不包含)。
  • callback <Function> function(err, n) {}

返回一個隨機整數 n,使得 min <= n < max。此實現避免了模偏差

範圍 (max - min) 必須小於 248minmax 必須是安全整數

如果沒有提供 callback 函式,則隨機整數會同步生成。

// Asynchronous
const {
  randomInt,
} = await import('node:crypto');

randomInt(3, (err, n) => {
  if (err) throw err;
  console.log(`Random number chosen from (0, 1, 2): ${n}`);
});// Asynchronous
const {
  randomInt,
} = require('node:crypto');

randomInt(3, (err, n) => {
  if (err) throw err;
  console.log(`Random number chosen from (0, 1, 2): ${n}`);
});
// Synchronous
const {
  randomInt,
} = await import('node:crypto');

const n = randomInt(3);
console.log(`Random number chosen from (0, 1, 2): ${n}`);// Synchronous
const {
  randomInt,
} = require('node:crypto');

const n = randomInt(3);
console.log(`Random number chosen from (0, 1, 2): ${n}`);
// With `min` argument
const {
  randomInt,
} = await import('node:crypto');

const n = randomInt(1, 7);
console.log(`The dice rolled: ${n}`);// With `min` argument
const {
  randomInt,
} = require('node:crypto');

const n = randomInt(1, 7);
console.log(`The dice rolled: ${n}`);

crypto.randomUUID([options])#

  • options <Object>
    • disableEntropyCache <boolean> 預設情況下,為提高效能,Node.js 會生成並快取足夠的隨機資料,以生成多達 128 個隨機 UUID。要生成一個不使用快取的 UUID,請將 disableEntropyCache 設定為 true預設值: false
  • 返回: <string>

生成一個隨機的 RFC 4122 版本 4 UUID。該 UUID 使用密碼學偽隨機數生成器生成。

crypto.scrypt(password, salt, keylen[, options], callback)#

提供一個非同步的 scrypt 實現。Scrypt 是一種基於密碼的金鑰派生函式,其設計旨在計算和記憶體上都非常昂貴,以使暴力攻擊得不償失。

salt 應儘可能唯一。建議 salt 是隨機的,並且長度至少為 16 位元組。詳情請參閱 NIST SP 800-132

當為 passwordsalt 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

callback 函式被呼叫時帶有兩個引數:errderivedKey。當金鑰派生失敗時,err 是一個異常物件,否則 errnullderivedKey 作為 Buffer 傳遞給回撥函式。

當任何輸入引數指定了無效的值或型別時,會丟擲異常。

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

// Using the factory defaults.
scrypt('password', 'salt', 64, (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
});
// Using a custom N parameter. Must be a power of two.
scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // '3745e48...aa39b34'
});const {
  scrypt,
} = require('node:crypto');

// Using the factory defaults.
scrypt('password', 'salt', 64, (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
});
// Using a custom N parameter. Must be a power of two.
scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // '3745e48...aa39b34'
});

crypto.scryptSync(password, salt, keylen[, options])#

提供一個同步的 scrypt 實現。Scrypt 是一種基於密碼的金鑰派生函式,其設計旨在計算和記憶體上都非常昂貴,以使暴力攻擊得不償失。

salt 應儘可能唯一。建議 salt 是隨機的,並且長度至少為 16 位元組。詳情請參閱 NIST SP 800-132

當為 passwordsalt 傳遞字串時,請考慮將字串用作加密 API 輸入時的注意事項

當金鑰派生失敗時,會丟擲異常,否則派生的金鑰將作為 Buffer 返回。

當任何輸入引數指定了無效的值或型別時,會丟擲異常。

const {
  scryptSync,
} = await import('node:crypto');
// Using the factory defaults.

const key1 = scryptSync('password', 'salt', 64);
console.log(key1.toString('hex'));  // '3745e48...08d59ae'
// Using a custom N parameter. Must be a power of two.
const key2 = scryptSync('password', 'salt', 64, { N: 1024 });
console.log(key2.toString('hex'));  // '3745e48...aa39b34'const {
  scryptSync,
} = require('node:crypto');
// Using the factory defaults.

const key1 = scryptSync('password', 'salt', 64);
console.log(key1.toString('hex'));  // '3745e48...08d59ae'
// Using a custom N parameter. Must be a power of two.
const key2 = scryptSync('password', 'salt', 64, { N: 1024 });
console.log(key2.toString('hex'));  // '3745e48...aa39b34'

crypto.secureHeapUsed()#

  • 返回:<Object>
    • total <number> 使用 --secure-heap=n 命令列標誌指定的已分配安全堆的總大小。
    • min <number> 使用 --secure-heap-min 命令列標誌指定的安全堆的最小分配量。
    • used <number> 當前從安全堆中分配的總位元組數。
    • utilization <number> usedtotal 已分配位元組數的計算比率。

crypto.setEngine(engine[, flags])#

為部分或全部 OpenSSL 函式(由標誌選擇)載入並設定 engine。OpenSSL 3 起已棄用對自定義引擎的支援。

engine 可以是引擎的 id 或其共享庫的路徑。

可選的 flags 引數預設使用 ENGINE_METHOD_ALLflags 是一個位欄位,可以接受以下一個或多個標誌的組合(定義在 crypto.constants 中):

  • crypto.constants.ENGINE_METHOD_RSA
  • crypto.constants.ENGINE_METHOD_DSA
  • crypto.constants.ENGINE_METHOD_DH
  • crypto.constants.ENGINE_METHOD_RAND
  • crypto.constants.ENGINE_METHOD_EC
  • crypto.constants.ENGINE_METHOD_CIPHERS
  • crypto.constants.ENGINE_METHOD_DIGESTS
  • crypto.constants.ENGINE_METHOD_PKEY_METHS
  • crypto.constants.ENGINE_METHOD_PKEY_ASN1_METHS
  • crypto.constants.ENGINE_METHOD_ALL
  • crypto.constants.ENGINE_METHOD_NONE

crypto.setFips(bool)#

  • bool <boolean> true 表示啟用 FIPS 模式。

在一個啟用了 FIPS 的 Node.js 構建中,啟用符合 FIPS 的加密提供程式。如果 FIPS 模式不可用,則丟擲錯誤。

crypto.sign(algorithm, data, key[, callback])#

使用給定的私鑰和演算法計算並返回 data 的簽名。如果 algorithmnullundefined,則演算法依賴於金鑰型別。

對於 Ed25519、Ed448 和 ML-DSA,algorithm 必須為 nullundefined

如果 key 不是 KeyObject,此函式的行為就如同將 key 傳遞給了 crypto.createPrivateKey()。如果它是一個物件,可以傳遞以下附加屬性:

  • dsaEncoding <string> 對於 DSA 和 ECDSA,此選項指定生成簽名的格式。它可以是以下之一:

    • 'der' (預設): DER 編碼的 ASN.1 簽名結構,編碼為 (r, s)
    • 'ieee-p1363':IEEE-P1363 中提議的簽名格式 r || s
  • padding <integer> RSA 的可選填充值,為以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (預設)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

    RSA_PKCS1_PSS_PADDING 將使用 MGF1,其雜湊函式與 RFC 4055 第 3.1 節中指定的用於簽署訊息的雜湊函式相同。

  • saltLength <integer> 當填充為 RSA_PKCS1_PSS_PADDING 時的鹽長度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 將鹽長度設定為摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN (預設) 將其設定為最大允許值。

  • context <ArrayBuffer> | <Buffer> | <TypedArray> | <DataView> 對於 Ed448、ML-DSA 和 SLH-DSA,此選項指定可選的上下文,以區分使用相同金鑰為不同目的生成的簽名。

如果提供了 callback 函式,此函式將使用 libuv 的執行緒池。

crypto.subtle#

crypto.webcrypto.subtle 的一個方便別名。

crypto.timingSafeEqual(a, b)#

此函式使用恆定時間演算法比較表示給定 ArrayBufferTypedArrayDataView 例項的底層位元組。

此函式不會洩露計時資訊,從而避免攻擊者猜測其中一個值。這適用於比較 HMAC 摘要或機密值,如身份驗證 Cookie 或能力 URL

ab 必須都是 BufferTypedArrayDataView,並且它們必須具有相同的位元組長度。如果 ab 的位元組長度不同,則會丟擲錯誤。

如果 ab 中至少有一個是每個條目超過一個位元組的 TypedArray(例如 Uint16Array),則結果將使用平臺位元組序進行計算。

當兩個輸入都是 Float32ArrayFloat64Array 時,由於 IEEE 754 浮點數編碼,此函式可能會返回意外結果。特別是,x === yObject.is(x, y) 都不意味著兩個浮點數 xy 的位元組表示是相等的。

使用 crypto.timingSafeEqual 並不能保證*周邊*程式碼是時間安全的。應注意確保周邊程式碼不會引入時間漏洞。

crypto.verify(algorithm, data, key, signature[, callback])#

使用給定的金鑰和演算法驗證 data 的簽名。如果 algorithmnullundefined,則演算法依賴於金鑰型別。

對於 Ed25519、Ed448 和 ML-DSA,algorithm 必須為 nullundefined

如果 key 不是 KeyObject,此函式的行為就如同將 key 傳遞給了 crypto.createPublicKey()。如果它是一個物件,可以傳遞以下附加屬性:

  • dsaEncoding <string> 對於 DSA 和 ECDSA,此選項指定簽名的格式。它可以是以下之一:

    • 'der' (預設): DER 編碼的 ASN.1 簽名結構,編碼為 (r, s)
    • 'ieee-p1363':IEEE-P1363 中提議的簽名格式 r || s
  • padding <integer> RSA 的可選填充值,為以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (預設)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

    RSA_PKCS1_PSS_PADDING 將使用 MGF1,其雜湊函式與 RFC 4055 第 3.1 節中指定的用於簽署訊息的雜湊函式相同。

  • saltLength <integer> 當填充為 RSA_PKCS1_PSS_PADDING 時的鹽長度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 將鹽長度設定為摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN (預設) 將其設定為最大允許值。

  • context <ArrayBuffer> | <Buffer> | <TypedArray> | <DataView> 對於 Ed448、ML-DSA 和 SLH-DSA,此選項指定可選的上下文,以區分使用相同金鑰為不同目的生成的簽名。

signature 引數是先前為 data 計算的簽名。

由於公鑰可以從私鑰派生,因此可以為 key 傳遞私鑰或公鑰。

如果提供了 callback 函式,此函式將使用 libuv 的執行緒池。

crypto.webcrypto#

型別: <Crypto> Web Crypto API 標準的實現。

詳情請參閱 Web Crypto API 文件

注意事項#

將字串用作加密 API 的輸入#

由於歷史原因,Node.js 提供的許多加密 API 接受字串作為輸入,而底層加密演算法處理的是位元組序列。這些情況包括明文、密文、對稱金鑰、初始化向量、密碼短語、鹽值、認證標籤和附加認證資料。

將字串傳遞給加密 API 時,請考慮以下因素。

  • 並非所有位元組序列都是有效的 UTF-8 字串。因此,當從字串派生出長度為 n 的位元組序列時,其熵通常低於隨機或偽隨機 n 位元組序列的熵。例如,沒有 UTF-8 字串會產生位元組序列 c0 af。金鑰幾乎都應該是隨機或偽隨機的位元組序列。

  • 同樣,當將隨機或偽隨機位元組序列轉換為 UTF-8 字串時,不代表有效碼點的子序列可能會被 Unicode 替換字元 (U+FFFD) 替換。因此,生成的 Unicode 字串的位元組表示可能不等於建立該字串的位元組序列。

    const original = [0xc0, 0xaf];
    const bytesAsString = Buffer.from(original).toString('utf8');
    const stringAsBytes = Buffer.from(bytesAsString, 'utf8');
    console.log(stringAsBytes);
    // Prints '<Buffer ef bf bd ef bf bd>'. 

    密碼、雜湊函式、簽名演算法和金鑰派生函式的輸出是偽隨機位元組序列,不應作為 Unicode 字串使用。

  • 當從使用者輸入中獲取字串時,一些 Unicode 字元可以用多種等效方式表示,從而導致不同的位元組序列。例如,當將使用者密碼短語傳遞給金鑰派生函式(如 PBKDF2 或 scrypt)時,金鑰派生函式的結果取決於字串是使用組合字元還是分解字元。Node.js 不會規範化字元表示。開發者應考慮在將使用者輸入傳遞給加密 API 之前使用 String.prototype.normalize()

舊版流 API(Node.js 0.10 之前)#

Crypto 模組是在統一的 Stream API 概念出現之前以及在用於處理二進位制資料的 Buffer 物件出現之前新增到 Node.js 中的。因此,許多 crypto 類具有通常在其他實現 streams API 的 Node.js 類中找不到的方法(例如 update()final()digest())。此外,許多方法預設接受並返回 'latin1' 編碼的字串,而不是 Buffer。這個預設值在 Node.js v0.8 之後被更改為預設使用 Buffer 物件。

對弱演算法或已受損演算法的支援#

node:crypto 模組仍然支援一些已經受到威脅且不推薦使用的演算法。該 API 還允許使用金鑰大小過小、安全性不足的密碼和雜湊。

使用者應根據其安全需求,對選擇加密演算法和金鑰大小負全部責任。

根據 NIST SP 800-131A 的建議

  • 在需要抗碰撞性的場合(如數字簽名),MD5 和 SHA-1 已不再可接受。
  • 建議與 RSA、DSA 和 DH 演算法一起使用的金鑰至少有 2048 位,而 ECDSA 和 ECDH 的曲線至少有 224 位,以便在未來幾年內安全使用。
  • modp1modp2modp5 的 DH 組的金鑰大小小於 2048 位,不推薦使用。

有關其他建議和詳細資訊,請參閱參考文獻。

一些已知存在弱點且在實踐中關聯性不大的演算法只能透過舊版提供程式獲得,該提供程式預設不啟用。

CCM 模式#

CCM 是受支援的AEAD 演算法之一。使用此模式的應用程式在使用 cipher API 時必須遵守某些限制:

  • 身份驗證標籤的長度必須在建立密碼時透過設定 authTagLength 選項來指定,並且必須是 4、6、8、10、12、14 或 16 位元組之一。
  • 初始化向量 (nonce) N 的長度必須在 7 到 13 位元組之間 (7 ≤ N ≤ 13)。
  • 明文的長度限制為 2 ** (8 * (15 - N)) 位元組。
  • 解密時,必須在呼叫 update() 之前透過 setAuthTag() 設定身份驗證標籤。否則,解密將失敗,並且 final() 將根據 RFC 3610 第 2.6 節丟擲錯誤。
  • 在 CCM 模式下使用流方法(如 write(data)end(data)pipe())可能會失敗,因為 CCM 每個例項只能處理一個數據塊。
  • 當傳遞附加認證資料 (AAD) 時,實際訊息的位元組長度必須透過 plaintextLength 選項傳遞給 setAAD()。許多加密庫將身份驗證標籤包含在密文中,這意味著它們生成的密文長度為 plaintextLength + authTagLength。Node.js 不包含身份驗證標籤,所以密文長度始終為 plaintextLength。如果未使用 AAD,則此項不是必需的。
  • 由於 CCM 一次處理整個訊息,update() 必須只調用一次。
  • 儘管呼叫 update() 足以加密/解密訊息,但應用程式*必須*呼叫 final() 來計算或驗證身份驗證標籤。
import { Buffer } from 'node:buffer';
const {
  createCipheriv,
  createDecipheriv,
  randomBytes,
} = await import('node:crypto');

const key = 'keykeykeykeykeykeykeykey';
const nonce = randomBytes(12);

const aad = Buffer.from('0123456789', 'hex');

const cipher = createCipheriv('aes-192-ccm', key, nonce, {
  authTagLength: 16,
});
const plaintext = 'Hello world';
cipher.setAAD(aad, {
  plaintextLength: Buffer.byteLength(plaintext),
});
const ciphertext = cipher.update(plaintext, 'utf8');
cipher.final();
const tag = cipher.getAuthTag();

// Now transmit { ciphertext, nonce, tag }.

const decipher = createDecipheriv('aes-192-ccm', key, nonce, {
  authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(aad, {
  plaintextLength: ciphertext.length,
});
const receivedPlaintext = decipher.update(ciphertext, null, 'utf8');

try {
  decipher.final();
} catch (err) {
  throw new Error('Authentication failed!', { cause: err });
}

console.log(receivedPlaintext);const { Buffer } = require('node:buffer');
const {
  createCipheriv,
  createDecipheriv,
  randomBytes,
} = require('node:crypto');

const key = 'keykeykeykeykeykeykeykey';
const nonce = randomBytes(12);

const aad = Buffer.from('0123456789', 'hex');

const cipher = createCipheriv('aes-192-ccm', key, nonce, {
  authTagLength: 16,
});
const plaintext = 'Hello world';
cipher.setAAD(aad, {
  plaintextLength: Buffer.byteLength(plaintext),
});
const ciphertext = cipher.update(plaintext, 'utf8');
cipher.final();
const tag = cipher.getAuthTag();

// Now transmit { ciphertext, nonce, tag }.

const decipher = createDecipheriv('aes-192-ccm', key, nonce, {
  authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(aad, {
  plaintextLength: ciphertext.length,
});
const receivedPlaintext = decipher.update(ciphertext, null, 'utf8');

try {
  decipher.final();
} catch (err) {
  throw new Error('Authentication failed!', { cause: err });
}

console.log(receivedPlaintext);

FIPS 模式#

當使用 OpenSSL 3 時,Node.js 在與適當的 OpenSSL 3 提供程式(例如來自 OpenSSL 3 的 FIPS 提供程式)一起使用時支援 FIPS 140-2,該提供程式可以按照 OpenSSL 的 FIPS README 檔案中的說明進行安裝。

要在 Node.js 中支援 FIPS,您需要:

  • 一個正確安裝的 OpenSSL 3 FIPS 提供程式。
  • 一個 OpenSSL 3 FIPS 模組配置檔案
  • 一個引用 FIPS 模組配置檔案的 OpenSSL 3 配置檔案。

Node.js 需要使用一個指向 FIPS 提供程式的 OpenSSL 配置檔案進行配置。一個示例配置檔案如下:

nodejs_conf = nodejs_init

.include /<absolute path>/fipsmodule.cnf

[nodejs_init]
providers = provider_sect

[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
fips = fips_sect

[default_sect]
activate = 1 

其中 fipsmodule.cnf 是從 FIPS 提供程式安裝步驟生成的 FIPS 模組配置檔案:

openssl fipsinstall 

OPENSSL_CONF 環境變數設定為指向您的配置檔案,並將 OPENSSL_MODULES 設定為 FIPS 提供程式動態庫的位置。例如:

export OPENSSL_CONF=/<path to configuration file>/nodejs.cnf
export OPENSSL_MODULES=/<path to openssl lib>/ossl-modules 

然後可以透過以下方式在 Node.js 中啟用 FIPS 模式:

  • 使用 --enable-fips--force-fips 命令列標誌啟動 Node.js。
  • 以程式設計方式呼叫 crypto.setFips(true)

或者,可以透過 OpenSSL 配置檔案在 Node.js 中啟用 FIPS 模式。例如:

nodejs_conf = nodejs_init

.include /<absolute path>/fipsmodule.cnf

[nodejs_init]
providers = provider_sect
alg_section = algorithm_sect

[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
fips = fips_sect

[default_sect]
activate = 1

[algorithm_sect]
default_properties = fips=yes 

加密常量#

crypto.constants 匯出的以下常量適用於 node:cryptonode:tlsnode:https 模組的各種用途,並且通常特定於 OpenSSL。

OpenSSL 選項#

詳情請參閱 SSL OP 標誌列表

常量 描述
SSL_OP_ALL 在 OpenSSL 中應用多個錯誤修復。詳情請參閱 https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_options.html
SSL_OP_ALLOW_NO_DHE_KEX 指示 OpenSSL 允許為 TLS v1.3 使用非 [EC]DHE 的金鑰交換模式。
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 允許 OpenSSL 與未打補丁的客戶端或伺服器之間進行舊版不安全的重新協商。請參閱 https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_options.html
SSL_OP_CIPHER_SERVER_PREFERENCE 在選擇密碼時,嘗試使用伺服器的偏好而不是客戶端的。行為取決於協議版本。請參閱 https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_options.html
SSL_OP_CISCO_ANYCONNECT 指示 OpenSSL 使用思科版本的 DTLS_BAD_VER 識別符號。
SSL_OP_COOKIE_EXCHANGE 指示 OpenSSL 開啟 cookie 交換。
SSL_OP_CRYPTOPRO_TLSEXT_BUG 指示 OpenSSL 新增來自早期版本 cryptopro 草案的 server-hello 擴充套件。
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 指示 OpenSSL 停用 OpenSSL 0.9.6d 中新增的 SSL 3.0/TLS 1.0 漏洞修復。
SSL_OP_LEGACY_SERVER_CONNECT 允許初始連線到不支援 RI 的伺服器。
SSL_OP_NO_COMPRESSION 指示 OpenSSL 停用對 SSL/TLS 壓縮的支援。
SSL_OP_NO_ENCRYPT_THEN_MAC 指示 OpenSSL 停用 encrypt-then-MAC。
SSL_OP_NO_QUERY_MTU
SSL_OP_NO_RENEGOTIATION 指示 OpenSSL 停用重新協商。
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 指示 OpenSSL 在執行重新協商時總是啟動一個新會話。
SSL_OP_NO_SSLv2 指示 OpenSSL 關閉 SSL v2
SSL_OP_NO_SSLv3 指示 OpenSSL 關閉 SSL v3
SSL_OP_NO_TICKET 指示 OpenSSL 停用 RFC4507bis 票據的使用。
SSL_OP_NO_TLSv1 指示 OpenSSL 關閉 TLS v1
SSL_OP_NO_TLSv1_1 指示 OpenSSL 關閉 TLS v1.1
SSL_OP_NO_TLSv1_2 指示 OpenSSL 關閉 TLS v1.2
SSL_OP_NO_TLSv1_3 指示 OpenSSL 關閉 TLS v1.3
SSL_OP_PRIORITIZE_CHACHA 指示 OpenSSL 伺服器在客戶端也這樣做時優先選擇 ChaCha20-Poly1305。如果未啟用 SSL_OP_CIPHER_SERVER_PREFERENCE,此選項無效。
SSL_OP_TLS_ROLLBACK_BUG 指示 OpenSSL 停用版本回滾攻擊檢測。

OpenSSL 引擎常量#

常量 描述
ENGINE_METHOD_RSA 限制引擎使用 RSA
ENGINE_METHOD_DSA 限制引擎使用 DSA
ENGINE_METHOD_DH 限制引擎使用 DH
ENGINE_METHOD_RAND 限制引擎使用 RAND
ENGINE_METHOD_EC 限制引擎使用 EC
ENGINE_METHOD_CIPHERS 限制引擎使用 CIPHERS
ENGINE_METHOD_DIGESTS 限制引擎使用 DIGESTS
ENGINE_METHOD_PKEY_METHS 限制引擎使用 PKEY_METHS
ENGINE_METHOD_PKEY_ASN1_METHS 限制引擎使用 PKEY_ASN1_METHS
ENGINE_METHOD_ALL
ENGINE_METHOD_NONE

其他 OpenSSL 常量#

常量 描述
DH_CHECK_P_NOT_SAFE_PRIME
DH_CHECK_P_NOT_PRIME
DH_UNABLE_TO_CHECK_GENERATOR
DH_NOT_SUITABLE_GENERATOR
RSA_PKCS1_PADDING
RSA_SSLV23_PADDING
RSA_NO_PADDING
RSA_PKCS1_OAEP_PADDING
RSA_X931_PADDING
RSA_PKCS1_PSS_PADDING
RSA_PSS_SALTLEN_DIGEST 在簽名或驗證時,將 RSA_PKCS1_PSS_PADDING 的鹽長度設定為摘要大小。
RSA_PSS_SALTLEN_MAX_SIGN 在簽署資料時,將 RSA_PKCS1_PSS_PADDING 的鹽長度設定為最大允許值。
RSA_PSS_SALTLEN_AUTO 在驗證簽名時,使 RSA_PKCS1_PSS_PADDING 的鹽長度自動確定。
POINT_CONVERSION_COMPRESSED
POINT_CONVERSION_UNCOMPRESSED
POINT_CONVERSION_HYBRID

Node.js 加密常量#

常量 描述
defaultCoreCipherList 指定 Node.js 使用的內建預設密碼列表。
defaultCipherList 指定當前 Node.js 程序使用的活動預設密碼列表。

腳註

  1. 需要 OpenSSL >= 3.5 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

  2. 需要 OpenSSL >= 3.0 2

  3. 需要 OpenSSL >= 3.2 2 3 4 5 6