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

類別: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

類別:Cipher#

Cipher 類別的執行個體用於加密資料。此類別可以用兩種方式之一使用

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

crypto.createCipher()crypto.createCipheriv() 方法用於建立 Cipher 執行個體。Cipher 物件不能使用 new 關鍵字直接建立。

範例:將 Cipher 物件用作串流

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

範例:使用 Cipher 和管道串流

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 <字串> 回傳值的 編碼
  • 傳回:<Buffer> | <字串> 任何剩餘的加密內容。如果指定 outputEncoding,會傳回字串。如果未提供 outputEncoding,會傳回 Buffer

呼叫 cipher.final() 方法後,Cipher 物件便無法再用於加密資料。嘗試呼叫 cipher.final() 超過一次將會導致擲回錯誤。

cipher.getAuthTag()#

  • 傳回:<Buffer> 當使用經過驗證的加密模式(目前支援 GCMCCMOCBchacha20-poly1305)時,cipher.getAuthTag() 方法會傳回包含從給定資料計算而來的驗證標記Buffer

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

如果在建立 cipher 執行個體時設定了 authTagLength 選項,此函式將會傳回剛好 authTagLength 個位元組。

cipher.setAAD(buffer[, options])#

使用經過驗證的加密模式時(目前支援 GCMCCMOCBchacha20-poly1305),cipher.setAAD() 方法會設定用於 其他驗證資料 (AAD) 輸入參數的值。

plaintextLength 選項對 GCMOCB 為選用。使用 CCM 時,必須指定 plaintextLength 選項,其值必須與純文字的長度(以位元組為單位)相符。請參閱 CCM 模式

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

cipher.setAutoPadding([autoPadding])#

  • autoPadding <布林值> 預設: true
  • 傳回:<Cipher> 相同的 Cipher 實例,用於方法串接。

使用區塊加密演算法時,Cipher 類別會自動將輸入資料加上適當區塊大小的填補。若要停用預設填補,請呼叫 cipher.setAutoPadding(false)

autoPaddingfalse 時,整個輸入資料的長度必須為密碼區塊大小的倍數,否則 cipher.final() 會擲回錯誤。停用自動填補對非標準填補很有用,例如使用 0x0 取代 PKCS 填補。

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

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() 會導致發生錯誤。

類別:Decipher#

Decipher 類別的執行個體用於解密資料。類別可以用兩種方式之一使用

  • 作為可讀寫的 串流,其中會將純文字加密資料寫入,以在可讀取端產生未加密的資料,或
  • 使用 decipher.update()decipher.final() 方法來產生未加密的資料。

方法 crypto.createDecipher()crypto.createDecipheriv() 用於建立 Decipher 實例。Decipher 物件不能使用 new 關鍵字直接建立。

範例:將 Decipher 物件用作串流

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

範例:使用 Decipher 和管線串流

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 <字串> 回傳值的 編碼
  • 傳回:<Buffer> | <string> 任何剩餘的解密內容。如果指定 outputEncoding,傳回字串。如果未提供 outputEncoding,傳回 Buffer

呼叫 decipher.final() 方法後,Decipher 物件就無法再用於解密資料。嘗試呼叫 decipher.final() 超過一次會導致擲回錯誤。

decipher.setAAD(buffer[, options])#

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

options 參數對 GCM 而言是可選的。使用 CCM 時,必須指定 plaintextLength 選項,且其值必須與密文長度(以位元組為單位)相符。請參閱 CCM 模式

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

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

decipher.setAuthTag(buffer[, encoding])#

使用經過驗證的加密模式(目前支援 GCMCCMOCBchacha20-poly1305)時,decipher.setAuthTag() 方法用於傳入接收到的驗證標籤。如果未提供標籤,或密文文字遭到竄改,decipher.final() 會擲回例外,表示應捨棄密文文字,因為驗證失敗。如果標籤長度根據 NIST SP 800-38D 無效,或與 authTagLength 選項的值不符,decipher.setAuthTag() 會擲回錯誤。

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

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

decipher.setAutoPadding([autoPadding])#

當資料在沒有標準區塊填充的情況下加密時,呼叫 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() 會導致擲回錯誤。

類別:DiffieHellman#

DiffieHellman 類別是一個用於建立 Diffie-Hellman 金鑰交換的工具程式。

可以使用 crypto.createDiffieHellman() 函數建立 DiffieHellman 類別的執行個體。

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,則預期 otherPublicKeyBufferTypedArrayDataView

如果 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 為字串。如果未提供 encoding,則預期 privateKeyBufferTypedArrayDataView

此函式不會自動計算相關的公開金鑰。可以使用 diffieHellman.setPublicKey()diffieHellman.generateKeys() 手動提供公開金鑰或自動衍生公開金鑰。

diffieHellman.setPublicKey(publicKey[, encoding])#

設定 Diffie-Hellman 公開金鑰。如果提供 encoding 參數,則預期 publicKey 為字串。如果未提供 encoding,則預期 publicKeyBufferTypedArrayDataView

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) 金鑰交換的公用程式。

可以使用 crypto.createECDH() 函數來建立 ECDH 類別的執行個體。

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

金鑰曲線 指定的 EC Diffie-Hellman 公開金鑰轉換成 格式 指定的格式。格式 參數指定點編碼,可以是 'compressed''uncompressed''hybrid'。提供的金鑰會使用指定的 輸入編碼 進行詮釋,而傳回的金鑰會使用指定的 輸出編碼 進行編碼。

使用 crypto.getCurves() 取得可用的曲線名稱清單。在最近的 OpenSSL 版本中,openssl ecparam -list_curves 也會顯示每個可用的橢圓曲線的名稱和說明。

如果未指定 格式,點會以 'uncompressed' 格式傳回。

如果未提供 輸入編碼,則預期 金鑰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,則預期 otherPublicKeyBufferTypedArrayDataView

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

如果指定 編碼,會傳回字串;否則會傳回 Buffer

ecdh.getPublicKey([編碼][, 格式])#

格式 參數指定點編碼,可以是 'compressed''uncompressed'。如果未指定 格式,點會以 'uncompressed' 格式傳回。

如果指定 編碼,會傳回字串;否則會傳回 Buffer

ecdh.setPrivateKey(privateKey[, 編碼])#

設定 EC Diffie-Hellman 私密金鑰。如果提供 編碼privateKey 預期為字串;否則 privateKey 預期為 BufferTypedArrayDataView

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

ecdh.setPublicKey(publicKey[, 編碼])#

穩定性:0 - 已棄用

設定 EC Diffie-Hellman 公開金鑰。如果提供 編碼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 執行個體。Hash 物件不能直接使用 new 關鍵字建立。

範例:將 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 物件的 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' 編碼。如果 dataBufferTypedArrayDataView,則會忽略 inputEncoding

當資料串流時,可以使用新資料呼叫此方法多次。

類別:Hmac#

Hmac 類別是建立密碼 HMAC 摘要的公用程式。它可以用兩種方式之一使用

  • 作為可讀寫的 串流,其中資料寫入以在可讀取端產生計算的 HMAC 摘要,或
  • 使用 hmac.update()hmac.digest() 方法來產生計算的 HMAC 摘要。

crypto.createHmac() 方法用於建立 Hmac 執行個體。Hmac 物件不得使用 new 關鍵字直接建立。

範例:將 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([編碼])#

計算使用 hmac.update() 傳遞的所有資料的 HMAC 摘要。如果提供 編碼,則會傳回字串;否則會傳回 Buffer

在呼叫 hmac.digest() 之後,Hmac 物件無法再次使用。多次呼叫 hmac.digest() 會導致擲回錯誤。

hmac.update(資料[, 輸入編碼])#

使用給定的 資料 更新 Hmac 內容,其編碼在 輸入編碼 中給出。如果未提供 編碼,且 資料 為字串,則強制執行 'utf8' 編碼。如果 資料BufferTypedArrayDataView,則會忽略 輸入編碼

當資料串流時,可以使用新資料呼叫此方法多次。

類別:KeyObject#

Node.js 使用 KeyObject 類別來表示對稱或非對稱金鑰,且每種類型的金鑰都會公開不同的函式。crypto.createSecretKey()crypto.createPublicKey()crypto.createPrivateKey() 方法用於建立 KeyObject 執行個體。KeyObject 物件不得使用 new 關鍵字直接建立。

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

KeyObject 執行個體可透過 postMessage() 傳遞給其他執行緒。接收者會取得複製的 KeyObject,且 KeyObject 不需要列在 transferList 參數中。

靜態方法:KeyObject.from(金鑰)#

範例:將 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<數字> 金鑰大小(以位元為單位)(RSA、DSA)。
    • publicExponent<BigInt> 公開指數(RSA)。
    • hashAlgorithm<字串> 訊息摘要名稱(RSA-PSS)。
    • mgf1HashAlgorithm<字串> MGF1 使用的訊息摘要名稱(RSA-PSS)。
    • saltLength<數字> 最小鹽長度(以位元組為單位)(RSA-PSS)。
    • divisorLength<數字> q 的大小(以位元為單位)(DSA)。
    • namedCurve<字串> 曲線名稱(EC)。

此屬性僅存在於非對稱金鑰中。此物件會根據金鑰類型包含金鑰相關資訊。透過此屬性取得的資訊無法用於唯一識別金鑰或危害金鑰安全性。

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

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

keyObject.asymmetricKeyType#

對於非對稱金鑰,此屬性代表金鑰的類型。支援的金鑰類型為

  • 'rsa' (OID 1.2.840.113549.1.1.1)
  • 'rsa-pss' (OID 1.2.840.113549.1.1.10)
  • 'dsa' (OID 1.2.840.10040.4.1)
  • 'ec' (OID 1.2.840.10045.2.1)
  • 'x25519' (OID 1.3.101.110)
  • 'x448' (OID 1.3.101.111)
  • 'ed25519' (OID 1.3.101.112)
  • 'ed448' (OID 1.3.101.113)
  • 'dh' (OID 1.2.840.113549.1.3.1)

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

keyObject.export([options])#

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

  • 格式<字串> 必須為 'buffer' (預設) 或 'jwk'

對於公開金鑰,可以使用下列編碼選項

  • 類型<字串> 必須為 'pkcs1' (僅 RSA) 或 'spki' 之一。
  • 格式<字串> 必須為 'pem''der''jwk'

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

  • 類型<字串> 必須為 'pkcs1' (僅 RSA)、'pkcs8''sec1' (僅 EC) 之一。
  • 格式<字串> 必須為 'pem''der''jwk'
  • 密碼<字串> 如果有指定,私鑰將會使用指定的 密碼通行碼 透過 PKCS#5 v2.0 基於密碼的加密進行加密。
  • 通行碼<字串> | <Buffer> 用於加密的通行碼,請參閱 密碼

結果類型取決於所選的編碼格式,如果是 PEM,結果會是字串;如果是 DER,結果會是包含 DER 編碼資料的緩衝區;如果是 JWK,結果會是物件。

如果選取 JWK 編碼格式,所有其他編碼選項都會被忽略。

PKCS#1、SEC1 和 PKCS#8 類型的金鑰可以使用 cipherformat 選項組合進行加密。PKCS#8 type 可與任何 format 搭配使用,透過指定 cipher 來加密任何金鑰演算法 (RSA、EC 或 DH)。僅當使用 PEM format 時,PKCS#1 和 SEC1 才能透過指定 cipher 來加密。為了達到最大的相容性,請對加密的私密金鑰使用 PKCS#8。由於 PKCS#8 定義了自己的加密機制,因此在加密 PKCS#8 金鑰時不支援 PEM 層級加密。請參閱 RFC 5208 以取得 PKCS#8 加密資訊,以及 RFC 1421 以取得 PKCS#1 和 SEC1 加密資訊。

keyObject.equals(otherKeyObject)#

傳回 truefalse,視金鑰的類型、值和參數是否完全相同而定。此方法並非 定時攻擊

keyObject.symmetricKeySize#

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

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 <字串> 對於 DSA 和 ECDSA,這個選項會指定已產生簽章的格式。它可以是下列其中之一

    • 'der' (預設):DER 編碼 ASN.1 簽章結構編碼 (r, s)
    • 'ieee-p1363':簽章格式 r || s,如 IEEE-P1363 中所建議。
  • padding <整數> RSA 的選用填充值,下列其中之一

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

    RSA_PKCS1_PSS_PADDING 將使用 MGF1 與用於簽署訊息的相同雜湊函數,如 RFC 4055 第 3.1 節所述,除非已將 MGF1 雜湊函數指定為金鑰的一部分,以符合 RFC 4055 第 3.3 節。

  • saltLength <整數> 當填充是 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' 編碼。如果 dataBufferTypedArrayDataView,則會忽略 inputEncoding

當資料串流時,可以使用新資料呼叫此方法多次。

類別:Verify#

Verify 類別是驗證簽章的工具程式。它可以用兩種方式之一使用

crypto.createVerify() 方法用於建立 Verify 執行個體。Verify 物件不得使用 new 關鍵字直接建立。

請參閱 Sign 以取得範例。

verify.update(data[, inputEncoding])#

使用給定的 data 更新 Verify 內容,編碼在 inputEncoding 中給出。如果未提供 inputEncoding,且 data 為字串,則強制執行 'utf8' 編碼。如果 dataBufferTypedArrayDataView,則會忽略 inputEncoding

當資料串流時,可以使用新資料呼叫此方法多次。

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

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

如果 object 不是 KeyObject,此函式會像將 object 傳遞給 crypto.createPublicKey() 一樣運作。如果它是一個物件,可以傳遞下列額外的屬性

  • dsaEncoding <string> 對於 DSA 和 ECDSA,此選項會指定簽章的格式。它可以是下列其中一個

    • 'der' (預設):DER 編碼 ASN.1 簽章結構編碼 (r, s)
    • 'ieee-p1363':簽章格式 r || s,如 IEEE-P1363 中所建議。
  • padding <整數> RSA 的選用填充值,下列其中之一

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

    RSA_PKCS1_PSS_PADDING 會使用 MGF1,其雜湊函式與用於驗證訊息的雜湊函式相同,如 RFC 4055 的第 3.1 節所述,除非 MGF1 雜湊函式已指定為金鑰的一部分,以符合 RFC 4055 的第 3.3 節。

  • 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#

  • 類型:<布林值>如果這是憑證授權 (CA) 憑證,將會是 true

x509.checkEmail(email[, options])#

  • email <字串>
  • options <Object>
    • subject <string> 'default''always''never'預設:'default'
  • 傳回:<string> | <undefined> 如果憑證與電子郵件地址相符,傳回 email;如果不相符,傳回 undefined

檢查憑證是否與指定的電子郵件地址相符。

如果 '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 <布林值> 預設值: false
    • singleLabelSubdomains <布林值> 預設值: false
  • 傳回: <字串> | <未定義> 傳回與 name 相符的主體名稱,或如果沒有主體名稱與 name 相符,則傳回 undefined

檢查憑證是否與指定的網域名稱相符。

如果憑證與指定的網域名稱相符,則傳回相符的主體名稱。傳回的名稱可能是完全相符(例如 foo.example.com),或可能包含萬用字元(例如 *.example.com)。由於網域名稱比對不區分大小寫,因此傳回的主體名稱可能也會與指定的 name 在大小寫上有所不同。

如果 'subject' 選項未定義或設為 'default',則只有在主體備用名稱延伸模組不存在或不包含任何 DNS 名稱時,才會考慮憑證主體。此行為與 RFC 2818(「透過 TLS 的 HTTP」)一致。

如果 'subject' 選項設為 'always',且主體備用名稱延伸模組不存在或不包含相符的 DNS 名稱,則會考慮憑證主體。

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

x509.checkIP(ip)#

檢查憑證是否與指定的 IP 位址(IPv4 或 IPv6)相符。

只考慮 RFC 5280 iPAddress 主旨備用名稱,且它們必須與指定的 ip 位址完全相符。其他主旨備用名稱以及憑證的主旨欄位將會被忽略。

x509.checkIssued(otherCert)#

檢查此憑證是否由指定的 otherCert 簽發。

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

詳細說明此憑證的主要延伸用法的陣列。

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

此憑證有效的日期/時間。

x509.verify(publicKey)#

驗證此憑證是由指定的公開金鑰簽署。不會對憑證執行任何其他驗證檢查。

node:crypto 模組方法和屬性#

crypto.constants#

一個包含用於加密和安全相關操作的常用常數的物件。目前定義的特定常數已在 加密常數 中說明。

crypto.fips#

穩定性:0 - 已棄用

用於檢查和控制目前是否正在使用符合 FIPS 的加密提供者的屬性。設為 true 需要 Node.js 的 FIPS 組建。

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

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

  • candidate <ArrayBuffer> | <SharedArrayBuffer> | <TypedArray> | <Buffer> | <DataView> | <bigint> 一個可能的質數,編碼為任意長度的 big endian 八位元組序列。
  • 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> 一個可能的質數,編碼為任意長度的 big endian 八位元組序列。
  • options <Object>
    • checks <number> 要執行的 Miller-Rabin 機率質數迭代次數。當值為 0(零)時,將使用會產生最多 2-64 的假陽性率的檢查次數,用於隨機輸入。選擇檢查次數時必須小心。請參閱 OpenSSL 文件中的 BN_is_prime_ex 函數 nchecks 選項,以取得更多詳細資訊。預設值:0
  • 傳回值:<boolean> 如果候選值是質數,且錯誤機率低於 0.25 ** options.checks,則為 true

檢查 candidate 的質數性。

crypto.createCipher(algorithm, password[, options])#

穩定性:0 - 已標示為不建議使用:請改用 crypto.createCipheriv()

建立並傳回使用指定 algorithmpasswordCipher 物件。

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

algorithm 依賴於 OpenSSL,範例為 'aes192' 等。在最近的 OpenSSL 版本中,openssl list -cipher-algorithms 會顯示可用的密碼演算法。

password 用於衍生密碼金鑰和初始化向量 (IV)。值必須是 'latin1' 編碼字串、BufferTypedArrayDataView

此函式在語意上對於所有支援的密碼都是不安全的,而且對於計數器模式(例如 CTR、GCM 或 CCM)的密碼有致命的缺陷。

crypto.createCipher() 的實作使用 OpenSSL 函式 EVP_BytesToKey 衍生金鑰,摘要演算法設定為 MD5,一次反覆運算,而且沒有鹽。由於沒有鹽,因此相同的密碼總是會建立相同的金鑰,這會允許字典攻擊。反覆運算次數少和非密碼安全雜湊演算法允許非常快速的密碼測試。

根據 OpenSSL 的建議,改用較新的演算法,取代 EVP_BytesToKey,建議開發人員自行使用 crypto.scrypt() 衍生金鑰和 IV,並使用 crypto.createCipheriv() 建立 Cipher 物件。使用者不應在 crypto.createCipher() 中使用計數器模式的密碼(例如 CTR、GCM 或 CCM)。為了避免 IV 重複使用的風險,導致漏洞,因此在使用這些模式時會發出警告。關於 GCM 中 IV 重複使用的情況,請參閱 Nonce-Disrespecting Adversaries 以取得詳細資訊。

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

建立並傳回 Cipher 物件,其中包含指定的 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' 編碼字串、緩衝區TypedArrayDataViewkey 可以選擇為類型為 secretKeyObject。如果密碼不需要初始化向量,iv 可以為 null

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

初始化向量應難以預測且獨一無二;理想情況下,它們會是密碼隨機數。它們不必是機密:IV 通常只會加入未加密的密文訊息。聽起來似乎矛盾,有些東西必須難以預測且獨一無二,但不必是機密;請記住,攻擊者不能提前預測特定 IV 會是什麼。

crypto.createDecipher(algorithm, password[, options])#

建立並傳回一個 Decipher 物件,使用指定的 algorithmpassword(金鑰)。

options 參數控制串流行為,而且是選用的,除非使用 CCM 或 OCB 模式(例如 'aes-128-ccm')的密碼。在這種情況下,authTagLength 選項是必要的,並以位元組為單位指定驗證標記的長度,請參閱 CCM 模式。對於 chacha20-poly1305authTagLength 選項預設為 16 個位元組。

此函式在語意上對於所有支援的密碼都是不安全的,而且對於計數器模式(例如 CTR、GCM 或 CCM)的密碼有致命的缺陷。

crypto.createDecipher() 的實作使用 OpenSSL 函數 EVP_BytesToKey 衍生金鑰,摘要演算法設定為 MD5,一次反覆運算,且沒有鹽值。由於沒有鹽值,因此允許字典攻擊,因為相同的密碼總是會建立相同的金鑰。反覆運算次數少且非密碼編譯安全雜湊演算法允許非常快速地測試密碼。

依據 OpenSSL 建議,使用較現代的演算法取代 EVP_BytesToKey,建議開發人員使用 crypto.scrypt() 自行衍生金鑰和 IV,並使用 crypto.createDecipheriv() 建立 Decipher 物件。

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

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

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

algorithm 依賴於 OpenSSL,範例為 'aes192' 等。在最近的 OpenSSL 版本中,openssl list -cipher-algorithms 會顯示可用的密碼演算法。

keyalgorithm 使用的原始金鑰,而 iv初始化向量。兩個參數都必須是 'utf8' 編碼字串、緩衝區TypedArrayDataViewkey 可以選擇為類型為 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 字串指定的預先定義曲線,建立橢圓曲線 Diffie-Hellman (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])#

建立並傳回 Hmac 物件,其使用指定的 algorithmkey。選用的 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.diffieHellman(options)#

根據 privateKeypublicKey 計算 Diffie-Hellman 祕密。兩個金鑰必須具有相同的 asymmetricKeyType,而 asymmetricKeyType 必須為下列其中一個:'dh'(適用於 Diffie-Hellman)、'ec'(適用於 ECDH)、'x448''x25519'(適用於 ECDH-ES)。

crypto.hash(algorith, data[, outputEncoding])#

穩定性:1.2 - 發行候選版本

一個用於建立資料一次性雜湊摘要的工具程式。當雜湊較少量的資料 (<= 5MB) 且資料容易取得時,它可能比物件導向的 crypto.createHash() 更快。如果資料量可能很大或資料是串流的,建議改用 crypto.createHash()

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

範例

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.generateKey(type, options, callback)#

  • type: <字串> 已產生機密金鑰的預定用途。目前可接受的值為 'hmac''aes'
  • options: <物件>
    • length: <數字> 要產生的金鑰的位元長度。此值必須大於 0。
      • 如果 type'hmac',最小值為 8,最大長度為 231-1。如果值不是 8 的倍數,產生的金鑰將會被截斷為 Math.floor(length / 8)
      • 如果 type'aes',長度必須為 128192256 之一。
  • callback: <函式>

非同步產生一個新的隨機機密金鑰,長度為指定的 lengthtype 會決定對 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 設為 undefined,而 publicKey / privateKey 則代表產生的金鑰對。

如果此方法以其 util.promisify() 版本呼叫,它會傳回一個 Promise,其中包含一個具有 publicKeyprivateKey 屬性的 Object

crypto.generateKeyPairSync(type, options)#

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

如果指定了 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: <字串> 已產生機密金鑰的預定用途。目前可接受的值為 'hmac''aes'
  • options: <物件>
    • length: <number> 要產生的金鑰的位元長度。
      • 如果 type'hmac',最小值為 8,最大長度為 231-1。如果值不是 8 的倍數,產生的金鑰將會被截斷為 Math.floor(length / 8)
      • 如果 type'aes',長度必須為 128192256 之一。
  • 傳回:<KeyObject>

同步產生一個新的隨機密鑰,其長度為指定的 lengthtype 會決定要對 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.add,且 options.safe 不是 true,質數將會符合 prime % add = 1 的條件。
  • 如果只有設定 options.add,且 options.safe 設定為 true,質數將會符合 prime % add = 3 的條件。這是必要的,因為 options.add > 2prime % add = 1 將會與 options.safe 強制執行的條件相矛盾。
  • 如果未提供 options.add,將會忽略 options.rem

如果 options.addoptions.remArrayBufferSharedArrayBufferTypedArrayBufferDataView 提供,兩者都必須編碼為大端序序列。

預設情況下,質數會編碼為 <ArrayBuffer> 中的 big-endian 八位元組序列。如果 bigint 選項為 true,則會提供 <bigint>

crypto.generatePrimeSync(size[, options])#

產生一個 size 位元的偽亂數質數。

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

options.addoptions.rem 參數可用於強制執行額外的需求,例如 Diffie-Hellman

  • 如果 options.addoptions.rem 都已設定,質數將會符合 prime % add = rem 的條件。
  • 如果只有設定 options.add,且 options.safe 不是 true,質數將會符合 prime % add = 1 的條件。
  • 如果只有設定 options.add,且 options.safe 設定為 true,質數將會符合 prime % add = 3 的條件。這是必要的,因為 options.add > 2prime % add = 1 將會與 options.safe 強制執行的條件相矛盾。
  • 如果未提供 options.add,將會忽略 options.rem

如果 options.addoptions.remArrayBufferSharedArrayBufferTypedArrayBufferDataView 提供,兩者都必須編碼為大端序序列。

預設情況下,質數會編碼為 <ArrayBuffer> 中的 big-endian 八位元組序列。如果 bigint 選項為 true,則會提供 <bigint>

crypto.getCipherInfo(nameOrNid[, options])#

  • nameOrNid<string> | <number> 要查詢的密碼名稱或 nid。
  • options: <物件>
    • keyLength<number> 測試金鑰長度。
    • ivLength<number> 測試 IV 長度。
  • 傳回:<物件>
    • 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.hkdf(digest, ikm, salt, info, keylen, callback)#

HKDF 是 RFC 5869 中定義的簡單金鑰衍生函數。所提供的 ikmsaltinfo 會與 digest 一起使用,以衍生一個長度為 keylen 位元組的金鑰。

所提供的 callback 函數會以兩個引數呼叫:errderivedKey。如果在衍生金鑰時發生錯誤,err 會設定為錯誤;否則 err 會為 null。成功產生的 derivedKey 會以 <ArrayBuffer> 傳遞給 callback。如果任何輸入引數指定無效的值或類型,就會擲回錯誤。

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

提供 RFC 5869 中定義的同步 HKDF 金鑰衍生函數。所提供的 ikmsaltinfo 會與 digest 一起使用,以衍生一個長度為 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 傳遞給 callback。如果任一輸入參數指定無效值或類型,則會擲回錯誤。

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.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.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.randomInt([min, ]max[, callback])#

  • min <整數> 隨機範圍的開始(包含)。預設值:0
  • max <整數> 隨機範圍的結束(不包含)。
  • callback <函式> 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 <布林值> 預設情況下,為了提升效能,Node.js 會產生並快取足夠的隨機資料,以產生多達 128 個隨機 UUID。若要產生 UUID 而不用快取,請將 disableEntropyCache 設為 true預設值:false
  • 傳回:<字串>

產生一個隨機 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 會傳遞給 callback 作為 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()#

  • 傳回:<物件>
    • total <number> 使用 --secure-heap=n 命令列旗標指定,已配置的安全堆大小總計。
    • min <number> 使用 --secure-heap-min 命令列旗標指定,從安全堆中配置的最小值。
    • used <number> 目前從安全堆中配置的位元組總數。
    • utilization <number> 已配置位元組中 usedtotal 的計算比率。

crypto.setEngine(engine[, flags])#

載入並設定某些或所有 OpenSSL 函式的 engine(由旗標選取)。

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

如果 key 不是 KeyObject,這個函式會像 key 已傳遞給 crypto.createPrivateKey() 一樣運作。如果是物件,可以傳遞下列額外屬性

  • dsaEncoding <字串> 對於 DSA 和 ECDSA,這個選項會指定已產生簽章的格式。它可以是下列其中之一

    • 'der' (預設):DER 編碼 ASN.1 簽章結構編碼 (r, s)
    • 'ieee-p1363':簽章格式 r || s,如 IEEE-P1363 中所建議。
  • padding <整數> RSA 的選用填充值,下列其中之一

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

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

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

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

crypto.subtle#

crypto.webcrypto.subtle 的方便別名。

crypto.timingSafeEqual(a, b)#

此函式使用恆定時間演算法比較表示給定 ArrayBufferTypedArrayDataView 執行個體的基礎位元組。

此函式不會洩漏時序資訊,讓攻擊者可以猜測其中一個值。這適合用於比較 HMAC 摘要或機密值,例如驗證 cookie 或 功能網址

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)而定。

如果 key 不是 KeyObject,此函式會像 key 已傳遞給 crypto.createPublicKey() 一樣運作。如果它是一個物件,可以傳遞下列其他屬性

  • dsaEncoding <string> 對於 DSA 和 ECDSA,此選項會指定簽章的格式。它可以是下列其中一個

    • 'der' (預設):DER 編碼 ASN.1 簽章結構編碼 (r, s)
    • 'ieee-p1363':簽章格式 r || s,如 IEEE-P1363 中所建議。
  • padding <整數> RSA 的選用填充值,下列其中之一

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

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

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

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 模組新增至 Node.js 之前,尚未有統一串流 API 的概念,也沒有 Buffer 物件來處理二進位資料。因此,許多 crypto 類別有其他實作 串流 API(例如 update()final()digest())的 Node.js 類別通常沒有的方法。此外,許多方法預設接受和傳回 '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 演算法 之一。使用此模式的應用程式在使用密碼 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 提供者搭配使用時支援 FIPS 140-2,例如 OpenSSL 3 的 FIPS 提供者,可以透過遵循 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 使用 Cisco 的 DTLS_BAD_VER「特殊」版本。
SSL_OP_COOKIE_EXCHANGE 指示 OpenSSL 開啟 Cookie 交換。
SSL_OP_CRYPTOPRO_TLSEXT_BUG 指示 OpenSSL 從早期版本的 cryptopro 草稿中新增伺服器 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 停用加密然後 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_METHDS
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 的 salt 長度。
POINT_CONVERSION_COMPRESSED
POINT_CONVERSION_UNCOMPRESSED
POINT_CONVERSION_HYBRID

Node.js 加密常數#

常數 說明
defaultCoreCipherList 指定 Node.js 使用的內建預設加密清單。
defaultCipherList 指定目前 Node.js 程序使用的有效預設加密清單。