加密
History
稳定性:2 - 稳定
node:crypto 模块提供加密功能,其中包含一组封装器,用于调用 OpenSSL 的哈希、消息认证码(MAC)、加密、解密、签名、验证和密钥封装机制(KEM)函数。
const { createHmac } = await import('node:crypto'); const secret = 'abcdefg'; const hash = createHmac('sha256', secret) .update('I love cupcakes') .digest('hex'); console.log(hash); // 输出: // c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e
const { createHmac } = require('node:crypto'); const secret = 'abcdefg'; const hash = createHmac('sha256', secret) .update('I love cupcakes') .digest('hex'); console.log(hash); // 输出: // c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e
Node.js 有可能在不包含 node:crypto 模块支持的情况下构建。在这种情况下,尝试从 crypto import 或调用 require('node:crypto') 将导致抛出错误。
使用 CommonJS 时,可以使用 try/catch 捕获抛出的错误:
let crypto; try { crypto = require('node:crypto'); } catch (err) { console.error('加密支持已禁用!'); }
当使用词法 ESM import 关键字时,只有在加载模块之前注册了 process.on('uncaughtException') 的处理程序,才能捕获该错误(例如,使用预加载模块)。
使用 ESM 时,如果代码可能在未启用加密支持的 Node.js 构建上运行,请考虑使用 import() 函数而不是词法 import 关键字:
let crypto; try { crypto = await import('node:crypto'); } catch (err) { console.error('加密支持已禁用!'); }
以下内容按照导入和导出每种类型所支持的完整格式集合,列出了
KeyObject API 所识别的非对称密钥类型。
格式: 'pem'、'der'
'dh'(Diffie-Hellman) — OID1.2.840.113549.1.3.1'dsa'— OID1.2.840.10040.4.1'rsa-pss'— OID1.2.840.113549.1.1.10
格式: 'pem'、'der'、'jwk'
'rsa'— OID1.2.840.113549.1.1.1
格式: 'pem'、'der'、'jwk'、'raw-public'、'raw-private'
'ec'(椭圆曲线) — OID1.2.840.10045.2.1'ed25519'— OID1.3.101.112'ed448'— OID1.3.101.113'slh-dsa-sha2-128f'1 — OID2.16.840.1.101.3.4.3.21'slh-dsa-sha2-128s'1 — OID2.16.840.1.101.3.4.3.20'slh-dsa-sha2-192f'1 — OID2.16.840.1.101.3.4.3.23'slh-dsa-sha2-192s'1 — OID2.16.840.1.101.3.4.3.22'slh-dsa-sha2-256f'1 — OID2.16.840.1.101.3.4.3.25'slh-dsa-sha2-256s'1 — OID2.16.840.1.101.3.4.3.24'slh-dsa-shake-128f'1 — OID2.16.840.1.101.3.4.3.27'slh-dsa-shake-128s'1 — OID2.16.840.1.101.3.4.3.26'slh-dsa-shake-192f'1 — OID2.16.840.1.101.3.4.3.29'slh-dsa-shake-192s'1 — OID2.16.840.1.101.3.4.3.28'slh-dsa-shake-256f'1 — OID2.16.840.1.101.3.4.3.31'slh-dsa-shake-256s'1 — OID2.16.840.1.101.3.4.3.30'x25519'— OID1.3.101.110'x448'— OID1.3.101.111
格式: 'pem'、'der'、'jwk'、'raw-public'、'raw-seed'
'ml-dsa-44'1 — OID2.16.840.1.101.3.4.3.17'ml-dsa-65'1 — OID2.16.840.1.101.3.4.3.18'ml-dsa-87'1 — OID2.16.840.1.101.3.4.3.19'ml-kem-512'1 — OID2.16.840.1.101.3.4.4.1'ml-kem-768'1 — OID2.16.840.1.101.3.4.4.2'ml-kem-1024'1 — OID2.16.840.1.101.3.4.4.3
非对称密钥可以用几种格式表示。推荐的方法是将密钥材料导入 KeyObject 一次,并在所有后续操作中重用它,因为这避免了重复解析并提供最佳性能。
当 KeyObject 不切实际时——例如,当密钥材料出现在协议消息中且仅使用一次时——大多数加密函数也接受 PEM 字符串或直接指定格式和密钥材料的对象。有关每种格式接受的完整选项,请参阅 crypto.createPublicKey()、crypto.createPrivateKey() 和 keyObject.export()。
KeyObject 是解析后的密钥的内存表示。它由 crypto.createPublicKey()、crypto.createPrivateKey()、crypto.createSecretKey() 或密钥生成函数(如 crypto.generateKeyPair())创建。使用给定 KeyObject 进行的第一个加密操作可能比后续操作慢,因为 OpenSSL 会在首次使用时延迟初始化内部缓存。
PEM 和 DER 是基于 ASN.1 结构的非对称密钥的传统编码格式。
- PEM 是一种文本编码,它将 Base64 编码的 DER 数据包装在页眉和页脚行之间(例如
-----BEGIN PUBLIC KEY-----)。PEM 字符串可以直接传递给大多数加密操作。 - DER 是相同 ASN.1 结构的二进制编码。提供 DER 输入时,必须明确指定
type(通常为'spki'或'pkcs8')。
JSON Web Key (JWK) 是 RFC 7517 中定义的基于 JSON 的密钥表示。JWK 将每个密钥组件编码为 JSON 对象内的单个 Base64url 编码值。对于 RSA 密钥,JWK 避免了 ASN.1 解析开销,是最快的序列化导入格式。
稳定性:1.1 - 积极开发中
'raw-public'、'raw-private' 和 'raw-seed' 密钥格式允许导入和导出原始密钥材料而无需任何编码包装器。有关使用详情,请参阅 keyObject.export()、crypto.createPublicKey() 和 crypto.createPrivateKey()。
'raw-public' 通常是导入公钥的最快方式。'raw-private' 和 'raw-seed' 并不总是比其他格式快,因为它们仅包含私钥标量或种子——导入它们需要派生公钥组件(例如,椭圆曲线点乘法或种子扩展),这可能很昂贵。其他格式包括私钥和公钥组件,避免了该计算。
始终优先使用 KeyObject——从你拥有的任何格式创建一个并重用它。下面的指南仅适用于在选择序列化格式时,无论是导入到 KeyObject 还是在 KeyObject 不切实际时内联传递密钥材料。
当创建 KeyObject 以供重复使用时,导入成本只支付一次,因此选择更快的格式可以减少启动延迟。
导入成本分为两部分:解析开销(解码序列化包装器)和密钥计算(重建完整密钥所需的任何数学工作,例如从私钥标量派生公钥或扩展种子)。哪部分占主导地位取决于密钥类型。例如:
- 公钥——
'raw-public'是最快的序列化格式,因为原始格式跳过了所有 ASN.1 和 Base64 解码。 - EC 私钥——
'raw-private'比 PEM 或 DER 快,因为它避免了 ASN.1 解析。但是,对于较大的曲线(例如 P-384、P-521),从私钥标量派生公钥点所需的计算变得昂贵,减少了优势。 - RSA 密钥——
'jwk'是最快的序列化格式。JWK 将 RSA 密钥组件表示为单个 Base64url 编码的整数,完全避免了 ASN.1 解析的开销。
当无法重用 KeyObject 时(例如,密钥作为原始字节出现在协议消息中且仅使用一次),大多数加密函数也接受 PEM 字符串或直接指定格式和密钥材料的对象。在这种情况下,总成本是密钥导入和加密计算本身的总和。
对于加密计算占主导地位的操作——例如使用 RSA 签名或使用 P-384 或 P-521 进行 ECDH 密钥协商——序列化格式对整体吞吐量的影响可以忽略不计,因此选择最方便的格式。对于轻量级操作,如 Ed25519 签名或验证,导入成本占总成本的较大比例,因此更快的格式(如 'raw-public' 或 'raw-private')可以显著提高吞吐量。
即使相同的密钥材料只使用几次,将其导入到 KeyObject 也比重复传递原始或 PEM 表示更值得。
示例:在签名和验证操作中重用 KeyObject:
import { promisify } from 'node:util'; const { generateKeyPair, sign, verify } = await import('node:crypto'); const { publicKey, privateKey } = await promisify(generateKeyPair)('ed25519'); // KeyObject 将解析后的密钥保存在内存中,可以复用 // 跨多个操作而无需重新解析。 const data = new TextEncoder().encode('message to sign'); const signature = sign(null, data, privateKey); verify(null, data, publicKey, signature);
示例:将各种格式的密钥导入到 KeyObject 中:
import { promisify } from 'node:util'; const { createPrivateKey, createPublicKey, generateKeyPair, } = await import('node:crypto'); const generated = await promisify(generateKeyPair)('ed25519'); // PEM const privatePem = generated.privateKey.export({ format: 'pem', type: 'pkcs8' }); const publicPem = generated.publicKey.export({ format: 'pem', type: 'spki' }); createPrivateKey(privatePem); createPublicKey(publicPem); // DER - 需要明确指定类型 const privateDer = generated.privateKey.export({ format: 'der', type: 'pkcs8' }); const publicDer = generated.publicKey.export({ format: 'der', type: 'spki' }); createPrivateKey({ key: privateDer, format: 'der', type: 'pkcs8' }); createPublicKey({ key: publicDer, format: 'der', type: 'spki' }); // JWK const privateJwk = generated.privateKey.export({ format: 'jwk' }); const publicJwk = generated.publicKey.export({ format: 'jwk' }); createPrivateKey({ key: privateJwk, format: 'jwk' }); createPublicKey({ key: publicJwk, format: 'jwk' }); // 原始格式 const rawPriv = generated.privateKey.export({ format: 'raw-private' }); const rawPub = generated.publicKey.export({ format: 'raw-public' }); createPrivateKey({ key: rawPriv, format: 'raw-private', asymmetricKeyType: 'ed25519' }); createPublicKey({ key: rawPub, format: 'raw-public', asymmetricKeyType: 'ed25519' });
示例:直接将密钥材料传递给 crypto.sign() 和 crypto.verify() 而无需先创建 KeyObject:
import { promisify } from 'node:util'; const { generateKeyPair, sign, verify } = await import('node:crypto'); const generated = await promisify(generateKeyPair)('ed25519'); const data = new TextEncoder().encode('message to sign'); // PEM 字符串 const privatePem = generated.privateKey.export({ format: 'pem', type: 'pkcs8' }); const publicPem = generated.publicKey.export({ format: 'pem', type: 'spki' }); const sig1 = sign(null, data, privatePem); verify(null, data, publicPem, sig1); // JWK 对象 const privateJwk = generated.privateKey.export({ format: 'jwk' }); const publicJwk = generated.publicKey.export({ format: 'jwk' }); const sig2 = sign(null, data, { key: privateJwk, format: 'jwk' }); verify(null, data, { key: publicJwk, format: 'jwk' }, sig2); // 原始密钥字节 const rawPriv = generated.privateKey.export({ format: 'raw-private' }); const rawPub = generated.publicKey.export({ format: 'raw-public' }); const sig3 = sign(null, data, { key: rawPriv, format: 'raw-private', asymmetricKeyType: 'ed25519', }); verify(null, data, { key: rawPub, format: 'raw-public', asymmetricKeyType: 'ed25519', }, sig3);
示例:对于 EC 密钥,导入原始密钥时需要 namedCurve 选项:
import { promisify } from 'node:util'; const { createPrivateKey, createPublicKey, generateKeyPair, sign, verify, } = await import('node:crypto'); const generated = await promisify(generateKeyPair)('ec', { namedCurve: 'P-256', }); // 导出原始 EC 公钥(默认未压缩)。 const rawPublicKey = generated.publicKey.export({ format: 'raw-public' }); // 以下等效。 const rawPublicKeyUncompressed = generated.publicKey.export({ format: 'raw-public', type: 'uncompressed', }); // 导出压缩点格式。 const rawPublicKeyCompressed = generated.publicKey.export({ format: 'raw-public', type: 'compressed', }); // 导出原始 EC 私钥。 const rawPrivateKey = generated.privateKey.export({ format: 'raw-private' }); // 导入原始 EC 密钥。 // 接受压缩和未压缩的点格式。 const publicKey = createPublicKey({ key: rawPublicKey, format: 'raw-public', asymmetricKeyType: 'ec', namedCurve: 'P-256', }); const privateKey = createPrivateKey({ key: rawPrivateKey, format: 'raw-private', asymmetricKeyType: 'ec', namedCurve: 'P-256', }); const data = new TextEncoder().encode('message to sign'); const signature = sign('sha256', data, privateKey); verify('sha256', data, publicKey, signature);
示例:导出原始种子并导入它们:
import { promisify } from 'node:util'; const { createPrivateKey, decapsulate, encapsulate, generateKeyPair, } = await import('node:crypto'); const generated = await promisify(generateKeyPair)('ml-kem-768'); // 导出原始种子(ML-KEM 为 64 字节)。 const seed = generated.privateKey.export({ format: 'raw-seed' }); // 导入原始种子。 const privateKey = createPrivateKey({ key: seed, format: 'raw-seed', asymmetricKeyType: 'ml-kem-768', }); const { ciphertext } = encapsulate(generated.publicKey); decapsulate(privateKey, ciphertext);
类:Certificate
History
SPKAC 是一种证书签名请求机制,最初由 Netscape 实现,并作为 HTML5 的 keygen 元素的一部分被正式规范。
<keygen> 自 HTML 5.2 起已弃用,新项目不应再使用此元素。
node:crypto 模块提供了 Certificate 类用于处理 SPKAC 数据。最常见的用法是处理 HTML5 <keygen> 元素生成的输出。Node.js 在内部使用 OpenSSL 的 SPKAC 实现。
静态方法:Certificate.exportChallenge(spkac[, encoding])
History
spkac 参数可以是 ArrayBuffer。限制 spkac 参数的大小最大为 2**31 - 1 字节。
const { Certificate } = await import('node:crypto'); const spkac = getSpkacSomehow(); const challenge = Certificate.exportChallenge(spkac); console.log(challenge.toString('utf8')); // 打印:挑战作为 UTF8 字符串
const { Certificate } = require('node:crypto'); const spkac = getSpkacSomehow(); const challenge = Certificate.exportChallenge(spkac); console.log(challenge.toString('utf8')); // 打印:挑战作为 UTF8 字符串
静态方法:Certificate.exportPublicKey(spkac[, encoding])
History
spkac 参数可以是 ArrayBuffer。限制 spkac 参数的大小最大为 2**31 - 1 字节。
const { Certificate } = await import('node:crypto'); const spkac = getSpkacSomehow(); const publicKey = Certificate.exportPublicKey(spkac); console.log(publicKey); // 打印:公钥为 <Buffer ...>
const { Certificate } = require('node:crypto'); const spkac = getSpkacSomehow(); const publicKey = Certificate.exportPublicKey(spkac); console.log(publicKey); // 打印:公钥为 <Buffer ...>
静态方法:Certificate.verifySpkac(spkac[, encoding])
History
spkac 参数可以是 ArrayBuffer。添加了 encoding。限制 spkac 参数的大小最大为 2**31 - 1 字节。
import { Buffer } from 'node:buffer'; const { Certificate } = await import('node:crypto'); const spkac = getSpkacSomehow(); console.log(Certificate.verifySpkac(Buffer.from(spkac))); // 打印:true 或 false
const { Buffer } = require('node:buffer'); const { Certificate } = require('node:crypto'); const spkac = getSpkacSomehow(); console.log(Certificate.verifySpkac(Buffer.from(spkac))); // 打印:true 或 false
稳定性:0 - 已弃用
作为遗留接口,可以如下面的示例所示创建 crypto.Certificate 类的新实例。
new crypto.Certificate(): void
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?): void
const { Certificate } = await import('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const challenge = cert.exportChallenge(spkac); console.log(challenge.toString('utf8')); // 打印:挑战作为 UTF8 字符串
const { Certificate } = require('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const challenge = cert.exportChallenge(spkac); console.log(challenge.toString('utf8')); // 打印:挑战作为 UTF8 字符串
certificate.exportPublicKey(spkac, encoding?): void
const { Certificate } = await import('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const publicKey = cert.exportPublicKey(spkac); console.log(publicKey); // 打印:公钥为 <Buffer ...>
const { Certificate } = require('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const publicKey = cert.exportPublicKey(spkac); console.log(publicKey); // 打印:公钥为 <Buffer ...>
certificate.verifySpkac(spkac, encoding?): void
import { Buffer } from 'node:buffer'; const { Certificate } = await import('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); console.log(cert.verifySpkac(Buffer.from(spkac))); // 打印:true 或 false
const { Buffer } = require('node:buffer'); const { Certificate } = require('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); console.log(cert.verifySpkac(Buffer.from(spkac))); // 打印:true 或 false
类:Cipheriv
History
Cipheriv 类的实例用于加密数据。该类可以通过以下两种方式使用:
- 作为一个既可读又可写的 [stream][],将明文未加密数据写入以在可读侧产生加密数据,或
- 使用
cipher.update()和cipher.final()方法来生成加密数据。
crypto.createCipheriv() 方法用于创建 Cipheriv 实例。不应直接使用 new 关键字创建 Cipheriv 对象。
所选算法可能会对流式处理以及对 cipher.update() 的调用施加其他限制。请参阅 CCM mode、CBC-CTS mode、XTS mode、AES key wrap modes 和 SIV and GCM-SIV modes。
示例:将 Cipheriv 对象用作流:
const { scrypt, randomFill, createCipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = '用于生成密钥的密码'; // 首先,我们将生成密钥。密钥长度取决于算法。 // 在这种情况下,对于 aes192,它是 24 字节(192 位)。 scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // 然后,我们将生成一个随机初始化向量 randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; // 一旦我们有了密钥和 iv,我们就可以创建并使用密码... 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 = '用于生成密钥的密码'; // 首先,我们将生成密钥。密钥长度取决于算法。 // 在这种情况下,对于 aes192,它是 24 字节(192 位)。 scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // 然后,我们将生成一个随机初始化向量 randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; // 一旦我们有了密钥和 iv,我们就可以创建并使用密码... 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 = '用于生成密钥的密码'; // 首先,我们将生成密钥。密钥长度取决于算法。 // 在这种情况下,对于 aes192,它是 24 字节(192 位)。 scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // 然后,我们将生成一个随机初始化向量 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 = '用于生成密钥的密码'; // 首先,我们将生成密钥。密钥长度取决于算法。 // 在这种情况下,对于 aes192,它是 24 字节(192 位)。 scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // 然后,我们将生成一个随机初始化向量 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 = '用于生成密钥的密码'; // 首先,我们将生成密钥。密钥长度取决于算法。 // 在这种情况下,对于 aes192,它是 24 字节(192 位)。 scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // 然后,我们将生成一个随机初始化向量 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 = '用于生成密钥的密码'; // 首先,我们将生成密钥。密钥长度取决于算法。 // 在这种情况下,对于 aes192,它是 24 字节(192 位)。 scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // 然后,我们将生成一个随机初始化向量 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?): void
如果在之前调用 cipher.update() 时指定了输出编码,
则 outputEncoding 必须使用相同的编码。
一旦调用了 cipher.final() 方法,Cipheriv 对象将无法再用于加密数据。
尝试多次调用 cipher.final() 将导致抛出错误。
cipher.getAuthTag(): void
- 返回:
Buffer使用认证加密模式时(目前支持GCM、CCM、OCB、SIV、GCM-SIV和chacha20-poly1305),cipher.getAuthTag()方法会返回一个Buffer,其中包含根据给定数据计算得出的 认证标签。
cipher.getAuthTag() 方法应仅在使用 cipher.final() 方法完成加密后调用。
如果在 cipher 实例创建期间设置了 authTagLength 选项,
此函数将正好返回 authTagLength 字节。
cipher.setAAD(buffer, options?): void
string | ArrayBuffer | Buffer | TypedArray | DataView使用认证加密模式时(目前支持 GCM、CCM、OCB、SIV、GCM-SIV 和 chacha20-poly1305),cipher.setAAD() 方法会设置用于 附加认证数据(AAD)输入参数的值。
对于 GCM、OCB、SIV 和 GCM-SIV,plaintextLength 选项是可选的。使用 CCM 时,必须指定 plaintextLength 选项,且其值必须与明文的字节长度相符。请参阅 CCM mode。
必须在 cipher.update() 之前调用 cipher.setAAD() 方法。
cipher.setAutoPadding(autoPadding?): void
booleantrue使用标准块填充的分组密码时,Cipheriv 类会自动将填充添加到输入数据,使其达到适当的块大小。若要禁用默认填充,请调用 cipher.setAutoPadding(false)。
对于使用标准块填充的分组密码,当 autoPadding 为 false 时,整个输入数据的长度必须是密码块大小的倍数,否则 cipher.final() 将抛出错误。禁用自动填充适用于非标准填充,例如使用 0x0 而不是 PKCS 填充。
必须在 cipher.final() 之前调用 cipher.setAutoPadding() 方法。
cipher.update(data, inputEncoding?, outputEncoding?): void
使用 data 更新密码。如果给出了 inputEncoding 参数,
则 data 参数是使用指定编码的字符串。如果未给出 inputEncoding
参数,data 必须是 Buffer、TypedArray 或 DataView。如果 data 是 Buffer、TypedArray 或 DataView,则
忽略 inputEncoding。
outputEncoding 指定加密数据的输出格式。如果指定了
outputEncoding,则返回使用指定编码的字符串。如果未提供
outputEncoding,则返回 Buffer。
指定 outputEncoding 时,必须使用与之前调用 cipher.update() 时相同的编码。
对于大多数算法,可以使用新数据多次调用 cipher.update(),直到调用 cipher.final()。某些算法会限制对 cipher.update() 的调用。例如,CCM mode、CBC-CTS mode、XTS mode、AES key wrap modes 和 SIV and GCM-SIV modes 要求在单次调用中提供完整消息。在调用 cipher.final() 后再调用 cipher.update() 将导致抛出错误。
类:Decipheriv
History
Decipheriv 类的实例用于解密数据。该类可以通过以下两种方式使用:
- 作为一个既可读又可写的 流,将纯加密数据写入以在可读侧产生未加密数据,或
- 使用
decipher.update()和decipher.final()方法来产生未加密数据。
crypto.createDecipheriv() 方法用于创建 Decipheriv 实例。不应直接使用 new 关键字创建 Decipheriv 对象。
所选算法可能会对流式处理以及对 decipher.update() 的调用施加其他限制。请参阅 CCM mode、CBC-CTS mode、XTS mode、AES key wrap modes 和 SIV and GCM-SIV modes。
示例:将 Decipheriv 对象用作流:
import { Buffer } from 'node:buffer'; const { scryptSync, createDecipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = '用于生成密钥的密码'; // 密钥长度取决于算法。在这种情况下,对于 aes192,它是 // 24 字节(192 位)。 // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 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); // 输出:一些明文数据 }); // 使用相同的算法、密钥和 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 = '用于生成密钥的密码'; // 密钥长度取决于算法。在这种情况下,对于 aes192,它是 // 24 字节(192 位)。 // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 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); // 输出:一些明文数据 }); // 使用相同的算法、密钥和 iv 进行加密。 const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'; decipher.write(encrypted, 'hex'); decipher.end();
示例:将 Decipheriv 对象用作流:
import { Buffer } from 'node:buffer'; const { scryptSync, createDecipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = '用于生成密钥的密码'; // 密钥长度取决于算法。在这种情况下,对于 aes192,它是 // 24 字节(192 位)。 // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 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); // 输出:一些明文数据 }); // 使用相同的算法、密钥和 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 = '用于生成密钥的密码'; // 密钥长度取决于算法。在这种情况下,对于 aes192,它是 // 24 字节(192 位)。 // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 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); // 输出:一些明文数据 }); // 使用相同的算法、密钥和 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 = '用于生成密钥的密码'; // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 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 = '用于生成密钥的密码'; // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 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 = '用于生成密钥的密码'; // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 const decipher = createDecipheriv(algorithm, key, iv); // 使用相同的算法、密钥和 iv 进行加密。 const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'; let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); console.log(decrypted); // 输出:一些明文数据
const { scryptSync, createDecipheriv, } = require('node:crypto'); const { Buffer } = require('node:buffer'); const algorithm = 'aes-192-cbc'; const password = '用于生成密钥的密码'; // 请改用异步的 `crypto.scrypt()`。 const key = scryptSync(password, 'salt', 24); // IV 通常与密文一起传递。 const iv = Buffer.alloc(16, 0); // 初始化向量。 const decipher = createDecipheriv(algorithm, key, iv); // 使用相同的算法、密钥和 iv 进行加密。 const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'; let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); console.log(decrypted); // 输出:一些明文数据
decipher.final(outputEncoding?): void
如果在之前调用 decipher.update() 时指定了输出编码,outputEncoding 必须使用相同的编码。
一旦调用了 decipher.final() 方法,Decipheriv 对象将无法再用于解密数据。尝试多次调用 decipher.final() 将导致抛出错误。
decipher.setAAD
History
buffer 参数可以是字符串或 ArrayBuffer,并且限制为不超过 2 ** 31 - 1 字节。
此方法现在返回对 decipher 的引用。
decipher.setAAD(buffer, options?): void
string | ArrayBuffer | Buffer | TypedArray | DataView使用认证加密模式时(目前支持 GCM、CCM、OCB、SIV、GCM-SIV 和 chacha20-poly1305),decipher.setAAD() 方法会设置用作_附加认证数据_(AAD)输入参数的值。
对于 GCM、OCB、SIV 和 GCM-SIV,options 参数是可选的。使用 CCM 时,必须指定 plaintextLength 选项,且其值必须与密文的字节长度相同。参见 [CCM 模式][]。
必须在 decipher.update() 之前调用 decipher.setAAD() 方法。
当传递字符串作为 buffer 时,请考虑 [将字符串用作加密 API 输入时的注意事项][]。
decipher.setAuthTag(buffer, encoding?): void
使用认证加密模式时(目前支持 GCM、CCM、OCB、SIV、GCM-SIV 和 chacha20-poly1305),decipher.setAuthTag() 方法用于传入收到的_认证标签_。如果未提供标签,或者密文遭到篡改,decipher.final() 将抛出错误,表明由于认证失败,应丢弃密文。如果标签长度不符合 NIST SP 800-38D 的规定,或与 authTagLength 选项的值不匹配,decipher.setAuthTag() 将抛出错误。
对于 CCM、SIV 和 GCM-SIV 模式,必须在 decipher.update() 之前调用 decipher.setAuthTag() 方法;对于 GCM 和 OCB 模式以及 chacha20-poly1305,则必须在 decipher.final() 之前调用。decipher.setAuthTag() 只能调用一次。
当传递字符串作为认证标签时,请考虑 [将字符串用作加密 API 输入时的注意事项][]。
decipher.setAutoPadding(autoPadding?): void
booleantrue当数据在没有标准块填充的情况下被加密时,调用 decipher.setAutoPadding(false) 将禁用自动填充,以防止 decipher.final() 检查并移除填充。
对于使用标准块填充的分组密码,禁用填充后,输入数据的长度必须是密码块大小的倍数。
必须在 decipher.final() 之前调用 decipher.setAutoPadding() 方法。
decipher.update
History
The default inputEncoding was changed from binary to utf8.
decipher.update(data, inputEncoding?, outputEncoding?): void
使用 data 更新解密器。如果提供了 inputEncoding 参数,data 参数就是使用指定编码的字符串。如果未提供 inputEncoding 参数,data 必须是 Buffer、TypedArray 或 DataView。如果 data 是 Buffer、TypedArray 或 DataView,则会忽略 inputEncoding。
outputEncoding 指定解密数据的输出格式。如果指定了 outputEncoding,则返回使用指定编码的字符串。如果未提供 outputEncoding,则返回 Buffer。指定 outputEncoding 时,它必须与之前调用 decipher.update() 时使用相同的编码。
对于大多数算法,可以使用新数据多次调用 decipher.update(),直到调用 decipher.final()。某些算法会限制对 decipher.update() 的调用。例如,[CCM 模式][]、[CBC-CTS 模式][]、[XTS 模式][]、[AES 密钥包装模式][]以及 [SIV 和 GCM-SIV 模式][]要求在一次调用中提供完整消息。在 decipher.final() 之后调用 decipher.update() 将导致抛出错误。
即使底层密码实现了认证,此函数返回的明文在此时也可能无法确定其真实性和完整性。对于认证加密算法,通常只有在应用程序调用 decipher.final() 后,才能确认其真实性。
类:DiffieHellman
History
DiffieHellman 类是用于创建 Diffie-Hellman 密钥交换的工具。
DiffieHellman 类的实例可以使用 crypto.createDiffieHellman() 函数创建。
import assert from 'node:assert'; const { createDiffieHellman, } = await import('node:crypto'); // 生成 Alice 的密钥... const alice = createDiffieHellman(2048); const aliceKey = alice.generateKeys(); // 生成 Bob 的密钥... const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator()); const bobKey = bob.generateKeys(); // 交换并生成秘密... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); // 正常 assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
const assert = require('node:assert'); const { createDiffieHellman, } = require('node:crypto'); // 生成 Alice 的密钥... const alice = createDiffieHellman(2048); const aliceKey = alice.generateKeys(); // 生成 Bob 的密钥... const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator()); const bobKey = bob.generateKeys(); // 交换并生成秘密... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); // 正常 assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
diffieHellman.computeSecret(otherPublicKey, inputEncoding?, outputEncoding?): void
string | ArrayBuffer | Buffer | TypedArray | DataView使用 otherPublicKey 作为另一方的公钥计算共享秘密,并返回计算出的共享秘密。提供的密钥使用指定的 inputEncoding 进行解释,秘密使用指定的 outputEncoding 进行编码。如果未提供 inputEncoding,则 otherPublicKey 应为 Buffer、TypedArray 或 DataView。
如果给出了 outputEncoding,则返回字符串;否则返回 Buffer。
diffieHellman.generateKeys(encoding?): void
生成私钥和公钥 Diffie-Hellman 密钥值(除非它们已经生成或计算过),并以指定的 encoding 返回公钥。此密钥应传输给另一方。如果提供了 encoding,则返回字符串;否则返回 Buffer。
此函数是对 DH_generate_key() 的轻量封装。特别是,一旦私钥已生成或已设置,调用此函数只会根据现有私钥重新计算公钥。由于公钥是由私钥决定的,除非通过 diffieHellman.setPrivateKey() 更改了私钥,否则结果将保持不变。
diffieHellman.getGenerator(encoding?): void
返回指定 encoding 的 Diffie-Hellman 生成元。如果提供了 encoding,则返回字符串;否则返回 Buffer。
diffieHellman.getPrime(encoding?): void
返回指定 encoding 的 Diffie-Hellman 素数。如果提供了 encoding,则返回字符串;否则返回 Buffer。
diffieHellman.getPrivateKey(encoding?): void
返回指定 encoding 的 Diffie-Hellman 私钥。如果提供了 encoding,则返回字符串;否则返回 Buffer。
diffieHellman.getPublicKey(encoding?): void
返回指定 encoding 的 Diffie-Hellman 公钥。如果提供了 encoding,则返回字符串;否则返回 Buffer。
diffieHellman.setPrivateKey(privateKey, encoding?): void
string | ArrayBuffer | Buffer | TypedArray | DataView设置 Diffie-Hellman 私钥。如果提供了 encoding 参数,privateKey 应为字符串。如果未提供 encoding,privateKey 应为 Buffer、TypedArray 或 DataView。
此函数不会自动计算关联的公钥。可以使用 diffieHellman.setPublicKey() 或 diffieHellman.generateKeys() 手动提供公钥或自动派生它。
diffieHellman.setPublicKey(publicKey, encoding?): void
string | ArrayBuffer | Buffer | TypedArray | DataView设置 Diffie-Hellman 公钥。如果提供了 encoding 参数,publicKey 应为字符串。如果未提供 encoding,publicKey 应为 Buffer、TypedArray 或 DataView。
位字段,包含在 DiffieHellman 对象初始化期间执行的检查所产生的任何警告和/或错误。
此属性的有效值如下(在 node:constants 模块中定义):
DH_CHECK_P_NOT_SAFE_PRIMEDH_CHECK_P_NOT_PRIMEDH_UNABLE_TO_CHECK_GENERATORDH_NOT_SUITABLE_GENERATOR
类:DiffieHellmanGroup
History
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 节)
以下组仍然受支持但已弃用(参见 注意事项):
这些已弃用的组可能会在未来的 Node.js 版本中被移除。
类:ECDH
History
ECDH 类是用于创建椭圆曲线 Diffie-Hellman(ECDH)密钥交换的工具。
ECDH 类的实例可以使用 crypto.createECDH() 函数创建。
import assert from 'node:assert'; const { createECDH, } = await import('node:crypto'); // 生成 Alice 的密钥... const alice = createECDH('secp521r1'); const aliceKey = alice.generateKeys(); // 生成 Bob 的密钥... const bob = createECDH('secp521r1'); const bobKey = bob.generateKeys(); // 交换并生成秘密... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex')); // 正常
const assert = require('node:assert'); const { createECDH, } = require('node:crypto'); // 生成 Alice 的密钥... const alice = createECDH('secp521r1'); const aliceKey = alice.generateKeys(); // 生成 Bob 的密钥... const bob = createECDH('secp521r1'); const bobKey = bob.generateKeys(); // 交换并生成秘密... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex')); // 正常
静态方法:ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])
History
将由 key 和 curve 指定的 EC Diffie-Hellman 公钥转换为由 format 指定的格式。format 参数指定点编码,可以是 'compressed'、'uncompressed' 或 'hybrid'。提供的密钥使用指定的 inputEncoding 进行解释,返回的密钥使用指定的 outputEncoding 进行编码。
使用 crypto.getCurves() 获取可用曲线名称列表。
在最近的 OpenSSL 版本中,openssl ecparam -list_curves 也将显示每个可用椭圆曲线的名称和描述。
如果未指定 format,点将以 'uncompressed' 格式返回。
如果未提供 inputEncoding,key 应为 Buffer、TypedArray 或 DataView。
示例(解压缩密钥):
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'); // 转换后的密钥和未压缩的公钥应该相同 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'); // 转换后的密钥和未压缩的公钥应该相同 console.log(uncompressedKey === ecdh.getPublicKey('hex'));
ecdh.computeSecret(otherPublicKey, inputEncoding?, outputEncoding?): void
string | ArrayBuffer | Buffer | TypedArray | DataView使用 otherPublicKey 作为另一方的公钥计算共享秘密,并返回计算出的共享秘密。提供的密钥使用指定的 inputEncoding 进行解释,返回的秘密使用指定的 outputEncoding 进行编码。
如果未提供 inputEncoding,则 otherPublicKey 应为 Buffer、TypedArray 或 DataView。
如果给出了 outputEncoding,则返回字符串;否则返回 Buffer。
当 otherPublicKey 位于椭圆曲线之外时,ecdh.computeSecret 将抛出 ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY 错误。由于 otherPublicKey 通常是通过不安全网络从远程用户提供的,因此请务必相应地处理此异常。
ecdh.generateKeys(encoding?, format?): void
生成私钥和公钥 EC Diffie-Hellman 密钥值,并以指定的 format 和 encoding 返回公钥。此密钥应传输给另一方。
format 参数指定点编码,可以是 'compressed' 或 'uncompressed'。如果未指定 format,点将以 'uncompressed' 格式返回。
如果提供了 encoding,则返回字符串;否则返回 Buffer。
ecdh.getPrivateKey(encoding?): void
如果指定了 encoding,则返回字符串;否则返回 Buffer。
ecdh.getPublicKey(encoding?, format?): void
format 参数指定点编码,可以是 'compressed' 或 'uncompressed'。如果未指定 format,点将以 'uncompressed' 格式返回。
如果指定了 encoding,则返回字符串;否则返回 Buffer。
ecdh.setPrivateKey(privateKey, encoding?): void
string | ArrayBuffer | Buffer | TypedArray | DataView设置 EC Diffie-Hellman 私钥。
如果提供了 encoding,privateKey 应为字符串;否则 privateKey 应为 Buffer、TypedArray 或 DataView。
如果 privateKey 对于创建 ECDH 对象时指定的曲线无效,则会抛出错误。设置私钥后,关联的公点(密钥)也会生成并设置在 ECDH 对象中。
ecdh.setPublicKey(publicKey, encoding?): void
稳定性:0 - 已弃用
string | ArrayBuffer | Buffer | TypedArray | DataView设置 EC Diffie-Hellman 公钥。
如果提供了 encoding,publicKey 应为字符串;否则应为 Buffer、TypedArray 或 DataView。
通常没有理由调用此方法,因为 ECDH 只需要私钥和另一方的公钥来计算共享秘密。通常会调用 ecdh.generateKeys() 或 ecdh.setPrivateKey()。ecdh.setPrivateKey() 方法尝试生成与正在设置的私钥关联的公点/密钥。
示例(获取共享秘密):
const { createECDH, createHash, } = await import('node:crypto'); const alice = createECDH('secp256k1'); const bob = createECDH('secp256k1'); // 这是一种指定 Alice 之前的私钥之一的快捷方式。 // 在实际应用程序中使用如此可预测的私钥是不明智的。 alice.setPrivateKey( createHash('sha256').update('alice', 'utf8').digest(), ); // Bob 使用新生成的加密强度高的 // 伪随机密钥对 bob.generateKeys(); const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex'); const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex'); // aliceSecret 和 bobSecret 应该是相同的共享秘密值 console.log(aliceSecret === bobSecret);
const { createECDH, createHash, } = require('node:crypto'); const alice = createECDH('secp256k1'); const bob = createECDH('secp256k1'); // 这是一种指定 Alice 之前的私钥之一的快捷方式。 // 在实际应用程序中使用如此可预测的私钥是不明智的。 alice.setPrivateKey( createHash('sha256').update('alice', 'utf8').digest(), ); // Bob 使用新生成的加密强度高的 // 伪随机密钥对 bob.generateKeys(); const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex'); const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex'); // aliceSecret 和 bobSecret 应该是相同的共享秘密值 console.log(aliceSecret === bobSecret);
类:Hash
History
Hash 类是一个用于创建数据哈希摘要的工具。它可以通过以下两种方式使用:
- 作为一个既可读又可写的 流,数据被写入以在可读侧产生计算出的哈希摘要,或
- 使用
hash.update()和hash.digest()方法来产生计算出的哈希。
crypto.createHash() 方法用于创建 Hash 实例。Hash 对象不应直接使用 new 关键字创建。
示例:将 Hash 对象用作流:
const { createHash, } = await import('node:crypto'); const hash = createHash('sha256'); hash.on('readable', () => { // 哈希流只会产生一个元素。 const data = hash.read(); if (data) { console.log(data.toString('hex')); // 输出: // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50 } }); hash.write('some data to hash'); hash.end();
const { createHash, } = require('node:crypto'); const hash = createHash('sha256'); hash.on('readable', () => { // 哈希流只会产生一个元素。 const data = hash.read(); if (data) { console.log(data.toString('hex')); // 输出: // 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')); // 输出: // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
const { createHash, } = require('node:crypto'); const hash = createHash('sha256'); hash.update('some data to hash'); console.log(hash.digest('hex')); // 输出: // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
hash.copy(options?): void
Objectstream.transform
选项][]创建一个新的 Hash 对象,其中包含当前 Hash 对象内部状态的深拷贝。
可选的 options 参数控制流行为。对于 XOF 哈希函数(如 'shake256'),outputLength 选项可用于指定所需的输出长度(单位字节)。
如果在调用 hash.digest() 方法后尝试复制 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')); // 等等。
// 计算滚动哈希。 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')); // 等等。
hash.digest(encoding?): void
计算传递给哈希的所有数据的摘要(使用 hash.update() 方法)。
如果提供了 encoding,则返回字符串;否则返回 Buffer。
调用 hash.digest() 方法后,Hash 对象不能再被使用。多次调用将导致抛出错误。
hash.update(data, inputEncoding?): void
使用给定的 data 更新哈希内容,其编码由 inputEncoding 给出。
如果未提供 encoding,且 data 是字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则忽略 inputEncoding。
随着数据流式传输,可以多次调用此方法并传入新数据。
类:Hmac
History
- 继承自:
stream.Transform
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', () => { // 哈希流只会产生一个元素。 const data = hmac.read(); if (data) { console.log(data.toString('hex')); // 输出: // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e } }); hmac.write('some data to hash'); hmac.end();
const { createHmac, } = require('node:crypto'); const hmac = createHmac('sha256', 'a secret'); hmac.on('readable', () => { // 哈希流只会产生一个元素。 const data = hmac.read(); if (data) { console.log(data.toString('hex')); // 输出: // 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')); // 输出: // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
const { createHmac, } = require('node:crypto'); const hmac = createHmac('sha256', 'a secret'); hmac.update('some data to hash'); console.log(hmac.digest('hex')); // 输出: // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
hmac.digest(encoding?): void
计算使用 hmac.update() 传递的所有数据的 HMAC 摘要。
如果提供了 encoding,则返回字符串;否则返回 Buffer。
调用 hmac.digest() 后,Hmac 对象不能再被使用。多次调用 hmac.digest() 将导致抛出错误。
hmac.update(data, inputEncoding?): void
使用给定的 data 更新 Hmac 内容,其编码由 inputEncoding 给出。
如果未提供 encoding,且 data 是字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则忽略 inputEncoding。
随着数据流式传输,可以多次调用此方法并传入新数据。
类:KeyObject
History
添加对 ML-DSA 密钥的支持。
此类的实例现在可以使用 postMessage 传递给 worker 线程。
此类现在已导出。
Node.js 使用 KeyObject 类来表示对称或非对称密钥,并且每种密钥公开不同的函数。
crypto.createSecretKey()、crypto.createPublicKey() 和 crypto.createPrivateKey() 方法用于创建 KeyObject 实例。KeyObject 对象不应直接使用 new 关键字创建。
由于安全功能的改进,大多数应用程序应考虑使用新的 KeyObject API,而不是将密钥作为字符串或 Buffer 传递。
KeyObject 实例可以通过 postMessage() 传递给其他线程。接收者获得一个克隆的 KeyObject,并且 KeyObject 不需要列在 transferList 参数中。
静态方法:KeyObject.from(key)
History
不再支持将不可提取的 CryptoKey 作为 key 传递。
将不可提取的 CryptoKey 作为 key 传递已弃用。
CryptoKey返回可提取的 CryptoKey 的底层密钥材料的 KeyObject 表示。
返回的 KeyObject 不会保留 Web Crypto API 对原始 CryptoKey 施加的任何限制,例如允许的密钥用途、算法或哈希算法绑定。
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); // 输出:32(对称密钥大小,单位字节)
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); // 输出:32(对称密钥大小,单位字节) })();
证书对象
History
公开 RSA-PSS 密钥的 RSASSA-PSS-params 序列参数。
- 类型:
ObjectAttributes
此属性仅存在于非对称密钥上。根据密钥类型,此对象包含有关密钥的信息。通过此属性获得的任何信息都不能用于唯一标识密钥或危害密钥的安全性。
对于 RSA-PSS 密钥,如果密钥材料包含 RSASSA-PSS-params 序列,则将设置 hashAlgorithm、mgf1HashAlgorithm 和 saltLength 属性。
其他密钥详细信息可能会通过其他属性通过此 API 公开。
- 类型:
string
对于非对称密钥,此属性表示密钥的类型。请参阅支持的 非对称密钥类型。
对于无法识别的 KeyObject 类型和对称密钥,此属性为 undefined。
生成相等性检查
History
KeyObjectkeyObject
比较的
KeyObject
。根据密钥是否具有完全相同的类型、值和参数返回 true 或 false。此方法不是 恒定时间。
Object对于对称密钥,可以使用以下编码选项:
string'buffer'
(默认)或
'jwk'
。对于公钥,可以使用以下编码选项:
对于私钥,可以使用以下编码选项:
结果类型取决于所选的编码格式,当为 PEM 时结果是字符串,当为 DER 时将是包含 DER 编码数据的 buffer,当为 JWK 时将是对象。原始格式返回包含原始密钥材料的 Buffer。
可以通过指定 cipher 和 passphrase 来加密私钥。
PKCS#8 type 支持任何密钥算法的 PEM 和 DER format 加密。
PKCS#1 和 SEC1 仅在使用 PEM format 时可以加密。
为了最大兼容性,对加密私钥使用 PKCS#8。
由于 PKCS#8 定义了自己的加密机制,加密 PKCS#8 密钥时不支持 PEM 级加密。
请参阅 RFC 5208 了解 PKCS#8 加密,RFC 1421 了解 PKCS#1 和 SEC1 加密。
密钥大小
History
- 类型:
number
对于密钥,此属性表示密钥的大小(单位字节)。此属性对于非对称密钥为 undefined。
导入密钥
History
string | Algorithm | RsaHashedImportParams | EcKeyImportParams | HmacImportParams将 KeyObject 实例转换为 CryptoKey。
密钥用途
History
- 类型:
string
根据此 KeyObject 的类型,此属性对于密钥(对称)为 'secret',对于公钥(非对称)为 'public',或对于私钥(非对称)为 'private'。
- 继承自:
stream.Transform
Mac 类使用 OpenSSL 提供程序提供的 MAC 实现来计算消息认证码。它可以通过以下两种方式之一使用:
- 作为可读写的 流,将数据写入其中,并在可写端结束时从可读端生成一个认证标签;或者
- 调用一次或多次
mac.update(),然后调用mac.final()。
Mac 实例使用 crypto.createMac() 创建。Mac 类不会由 node:crypto 模块直接导出。
如果未先写入数据就调用 mac.end(),则会计算空消息的认证标签。如果所选 MAC 生成零字节标签(例如,提供程序接受 outputLength: 0),则可读端会在不发出数据块的情况下结束,因为 Node.js 流不会发出零长度数据块。改用 mac.final() 时,它会返回零长度的 Buffer 或空编码字符串。
mac.end() 和 mac.final() 是互斥的终结操作,不得在同一个对象上同时调用。尝试执行任一终结操作,或底层 MAC 更新失败后,都不能再次使用 Mac 对象。
示例:使用 mac.update() 和 mac.final():
const { createMac, randomBytes } = await import('node:crypto'); const key = randomBytes(16); const mac = createMac('CMAC', key, { cipher: 'AES-128-CBC', }); mac.update('some data to authenticate'); console.log(mac.final('hex'));
mac.final(outputEncoding?): void
完成 MAC 计算并返回认证标签。如果省略 outputEncoding 或其值为 'buffer',则返回 Buffer。否则返回字符串。
要验证认证标签,请使用 crypto.timingSafeEqual() 比较长度相同的 Buffer 值。
尝试终结后(包括终结失败时),都不能再次使用 Mac 对象。之后调用 mac.update() 或 mac.final() 会抛出 ERR_CRYPTO_MAC_FINALIZED。
mac.update(data, inputEncoding?): void
使用 data 更新 MAC,并返回 Mac 对象,以便链式调用。当 data 是字符串时,inputEncoding 默认为 'utf8'。当 data 是 Buffer、TypedArray 或 DataView 时,会忽略 inputEncoding。
在终结之前可以多次调用此方法。如果底层 MAC 更新失败,则不能再次使用 Mac 对象。在先前的底层 MAC 更新失败后或终结后调用此方法会抛出 ERR_CRYPTO_MAC_FINALIZED。
- 继承自:
stream.Writable
Sign 类是一个用于生成签名的工具。它可以通过以下两种方式使用:
- 作为可写 流,将待签名的数据写入其中,并使用
sign.sign()方法生成并返回签名,或者 - 使用
sign.update()和sign.sign()方法来生成签名。
crypto.createSign() 方法用于创建 Sign 实例。参数是要使用的哈希函数字符串名称。不应直接使用 new 关键字创建 Sign 对象。
示例:将 Sign 和 Verify 对象作为流使用:
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')); // 输出:true
const { 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')); // 输出: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)); // 输出:true
const { 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)); // 输出:true
sign
sign(privateKey, outputEncoding?): void
计算通过 sign.update() 或 sign.write() 传入的所有数据的签名。
如果 privateKey 不是 KeyObject,此函数的行为就像将 privateKey 传入 crypto.createPrivateKey() 一样。当 privateKey 是字符串、ArrayBuffer、Buffer、TypedArray 或 DataView 时,它必须包含 PEM 编码的密钥材料。如果它是一个对象,则可以传入以下附加属性:
string(r, s)
。r || s
。integerintegerRSA_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?): void
使用给定的 data 更新 Sign 内容,其编码在 inputEncoding 中给出。
如果未提供 encoding,且 data 是字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则忽略 inputEncoding。
随着数据流式传输,可以多次调用此方法并传入新数据。
类:Verify
History
- 继承自:
stream.Writable
Verify 类是一个用于验证签名的工具。它可以通过以下两种方式使用:
- 作为可写 流,其中写入的数据用于针对提供的签名进行验证,或者
- 使用
verify.update()和verify.verify()方法来验证签名。
crypto.createVerify() 方法用于创建 Verify 实例。不应直接使用 new 关键字创建 Verify 对象。
示例请参阅 Sign。
verify.update(data, inputEncoding?): void
使用给定的 data 更新 Verify 内容,其编码在 inputEncoding 中给出。
如果未提供 inputEncoding,且 data 是字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则忽略 inputEncoding。
随着数据流式传输,可以多次调用此方法并传入新数据。
verify(key, signature, signatureEncoding?): void
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectstring | ArrayBuffer | Buffer | TypedArray | DataView使用给定的 key 和 signature 来验证所提供的数据。
如果 key 不是 KeyObject,此函数的行为就像将 key 传递给了 crypto.createPublicKey() 一样。当 key 是字符串、ArrayBuffer、Buffer、TypedArray 或 DataView 时,它必须包含 PEM 编码的密钥材料。如果它是一个对象,则可以传入以下附加属性:
string(r, s)
。r || s
。integerintegerRSA_PKCS1_PSS_PADDING
时的盐长度。特殊值
crypto.constants.RSA_PSS_SALTLEN_DIGEST
将盐长度设置为摘要大小,
crypto.constants.RSA_PSS_SALTLEN_AUTO
(默认)使其自动确定。signature 参数是之前在 signatureEncoding 中计算出的数据签名。
如果指定了 signatureEncoding,则 signature 预期为字符串;否则 signature 预期为 Buffer、TypedArray 或 DataView。
调用 verify.verify() 后,verify 对象不能再被使用。多次调用 verify.verify() 将导致抛出错误。
因为公钥可以从私钥派生,所以可以传递私钥而不是公钥。
类:X509Certificate
History
封装一个 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);
颁发者证书
History
string | TypedArray | Buffer | DataView主题备用名称
History
- 类型:
boolean如果这是一个证书颁发机构 (CA) 证书,则为true。
检查证书是否与给定的电子邮件地址匹配。
如果 'subject' 选项未定义或设置为 'default',则根据 OpenSSL 的默认行为考虑证书主题。
如果 'subject' 选项设置为 'always',并且如果主题备用名称扩展不存在或不包含匹配的电子邮件地址,则考虑证书主题。
如果 'subject' 选项设置为 'never',则从不考虑证书主题,即使证书不包含主题备用名称。
检查主机名是否匹配
History
subject 选项现在默认为 'default'。
subject 选项现在可以设置为 'default'。
检查证书是否与给定的主机名匹配。
如果证书与给定的主机名匹配,则返回匹配的主题名称。返回的名称可能是完全匹配(例如,foo.example.com),也可能包含通配符(例如,*.example.com)。因为主机名比较不区分大小写,所以返回的主题名称在大写上也可能与给定的 name 不同。
如果 'subject' 选项未定义或设置为 'default',则根据 OpenSSL 的默认行为考虑证书主题。
如果 'subject' 选项设置为 'always',并且如果主题备用名称扩展不存在或不包含匹配的 DNS 名称,则考虑证书主题。
如果 'subject' 选项设置为 'never',则从不考虑证书主题,即使证书不包含主题备用名称。
检查 IP 地址是否匹配
History
options 参数已被移除,因为它没有效果。
string检查证书是否与给定的 IP 地址(IPv4 或 IPv6)匹配。
仅考虑 RFC 5280 iPAddress 主题备用名称,并且它们必须与给定的 ip 地址完全匹配。其他主题备用名称以及证书的主题字段将被忽略。
颁发者检查
History
X509Certificate通过比较证书元数据,检查此证书是否可能由给定的 otherCert 颁发。
这对于修剪可能已使用更基本的过滤例程(即仅基于主题和颁发者名称)选择的潜在颁发者证书列表很有用。
最后,要验证此证书的签名是由对应于 otherCert 公钥的私钥生成的,请使用 x509.verify(publicKey),并将 otherCert 的公钥表示为 KeyObject,如下所示
if (!x509.verify(otherCert.publicKey)) { throw new Error('otherCert did not issue x509'); }
x509.checkPrivateKey(privateKey): void
KeyObject检查此证书的公钥是否与给定的私钥一致。
- 类型:
string
此证书的 SHA-1 指纹。
因为 SHA-1 在密码学上已被破解,且其安全性显著低于常用于签署证书的算法,请考虑改用 x509.fingerprint256。
- 类型:
string
此证书的 SHA-256 指纹。
- 类型:
string
此证书的 SHA-512 指纹。
因为计算 SHA-256 指纹通常更快,且其大小仅为 SHA-512 指纹的一半,所以 x509.fingerprint256 可能是更好的选择。虽然 SHA-512 通常提供更高级别的安全性,但 SHA-256 的安全性与常用于签署证书的大多数算法匹配。
x509.infoAccess
History
作为对 CVE-2021-44532 的响应,此字符串的部分内容可能被编码为 JSON 字符串字面量。
- 类型:
string
证书授权信息访问扩展的文本表示。
这是一个由换行符分隔的访问描述列表。每行以访问方法和访问位置的种类开头,后跟冒号和与访问位置关联的值。
在表示访问方法和访问位置种类的前缀之后,每行的其余部分可能会用引号括起来,以表明该值是 JSON 字符串字面量。为了向后兼容,Node.js 仅在此属性内必要时使用 JSON 字符串字面量以避免歧义。第三方代码应准备好处理这两种可能的条目格式。
- 类型:
string
此证书中包含的颁发者标识。
颁发者证书,如果颁发者证书不可用则为 undefined。
- 类型:
string[]
一个数组,详细说明此证书的密钥扩展用法。
- 类型:
KeyObject
此证书的公钥 KeyObject。
- 类型:
Buffer
一个包含此证书 DER 编码的 Buffer。
- 类型:
string
此证书的序列号。
序列号由证书颁发机构分配,并不能唯一标识证书。请考虑改用 x509.fingerprint256 作为唯一标识符。
- 类型:
string
此证书的完整主题。
x509.subjectAltName
History
作为对 CVE-2021-44532 的响应,此字符串的部分内容可能被编码为 JSON 字符串字面量。
- 类型:
string
为此证书指定的主题备用名称。
这是一个逗号分隔的主题备用名称列表。每个条目都以一个标识主题备用名称种类的字符串开头,后跟冒号和与该条目关联的值。
早期版本的 Node.js 错误地假设在此属性处以双字符序列 ', ' 分割是安全的(参见 CVE-2021-44532)。然而,恶意和合法证书都可能包含在表示为字符串时包括此序列的主题备用名称。
在表示条目类型的前缀之后,每个条目的其余部分可能会用引号括起来,以表明该值是 JSON 字符串字面量。为了向后兼容,Node.js 仅在此属性内必要时使用 JSON 字符串字面量以避免歧义。第三方代码应准备好处理这两种可能的条目格式。
x509.toJSON(): void
- 类型:
string
X509 证书没有标准的 JSON 编码。toJSON() 方法返回一个包含 PEM 编码证书的字符串。
x509.toLegacyObject(): void
- 类型:
Object
使用遗留的 证书对象 编码返回有关此证书的信息。
x509.toString(): void
- 类型:
string
返回 PEM 编码的证书。
- 类型:
string
此证书有效的起始日期/时间。
- 类型:
Date
此证书有效的起始日期/时间,封装在 Date 对象中。
- 类型:
string
此证书有效的截止日期/时间。
- 类型:
Date
此证书有效的截止日期/时间,封装在 Date 对象中。
用于签署证书的算法,如果 OpenSSL 不知道签名算法则为 undefined。
- 类型:
string
用于签署证书的算法的 OID。
x509.verify(publicKey): void
KeyObject验证此证书是否由给定的公钥签署。不对证书执行任何其他验证检查。
argon2
History
- 类型
stringArgon2 的变体,取值为 argon2d、argon2i 或 argon2id。 - 选项
Object- 密码短语
string | ArrayBuffer | Buffer | TypedArray | DataView必需,这是 Argon2 密码哈希应用中的密码。 - 盐值
string | ArrayBuffer | Buffer | TypedArray | DataView必需,长度必须至少为 8 字节。这是 Argon2 密码哈希应用中的盐值。 - 并行度
number必需,并行度决定可运行多少条计算链(lane)。必须至少为 1,且至多为 4。 - 密钥长度
number必需,要生成的密钥长度。必须至少为 4,且至多为 4294967295。 - 内存
number必需,以 1KiB 块为单位的内存成本。必须至少为 8192,且至多为 4294967295。实际块数会向下取整到最接近的 4 的倍数。 - 迭代次数
number必需,遍数(迭代次数)。必须至少为 1,且至多为 4294967295。 - secret
string | ArrayBuffer | Buffer | TypedArray | DataView | undefined可选,随机附加输入,类似于盐值,但不应与派生密钥一起存储。在密码哈希应用中这称为 pepper。如果使用,其长度不得超过 4294967295 字节。 - associatedData
string | ArrayBuffer | Buffer | TypedArray | DataView | undefined可选,要添加到哈希中的附加数据,功能上等同于盐值或 secret,但用于非随机数据。如果使用,其长度不得超过 4294967295 字节。
- 密码短语
- 回调函数
Function
提供异步 Argon2 实现。Argon2 是一种基于密码的密钥派生函数,旨在在计算和内存方面都很昂贵,以使暴力破解攻击无利可图。
nonce 应尽可能唯一。建议 nonce 是随机的且至少 16 字节长。详见 NIST SP 800-132。
当为 passphrase、salt、secret 或 associatedData 传递字符串时,请考虑 使用字符串作为加密 API 输入时的注意事项。
callback 函数带有两个参数:error 和 result。如果密钥派生失败,error 是一个异常对象,否则 result 为 Buffer。error 作为 [err][] 传递给回调。
当任何输入参数指定无效的值或类型时,将抛出异常。
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): void
string"argon2d"
、
"argon2i"
或
"argon2id"
。Objectstring | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewnumber2**24-1
。number4
,且至多为
2**32-1
。number8 * parallelism
,且至多为
2**32-1
。实际块数会向下取整到最接近的
4 * parallelism
的倍数。number1
,且至多为
2**32-1
。string | ArrayBuffer | Buffer | TypedArray | DataView | undefined2**32-1
字节。string | ArrayBuffer | Buffer | TypedArray | DataView | undefined2**32-1
字节。提供同步 Argon2 实现。Argon2 是一种基于密码的密钥派生函数,旨在在计算和内存方面都很昂贵,以使暴力破解攻击无利可图。
nonce 应尽可能唯一。建议 nonce 是随机的且至少 16 字节长。详见 NIST SP 800-132。
当为 message、nonce、secret 或 associatedData 传递字符串时,请考虑 使用字符串作为加密 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
History
现在向 callback 参数传递无效的回调会抛出 ERR_INVALID_ARG_TYPE,而不是 ERR_INVALID_CALLBACK。
crypto.checkPrime(candidate, options?, callback): void
ArrayBuffer | SharedArrayBuffer | TypedArray | Buffer | DataView | bigintObjectnumber0
(零)时,使用的检查次数产生的随机输入假阳性率最多为 2
-64
。选择检查次数时必须小心。有关更多详细信息,请参阅 OpenSSL 文档中的
BN_is_prime_ex
函数
nchecks
选项。
默认:
0检查 candidate 的素性。
crypto.checkPrimeSync(candidate, options?): void
ArrayBuffer | SharedArrayBuffer | TypedArray | Buffer | DataView | bigintObjectnumber0
(零)时,使用的检查次数产生的随机输入假阳性率最多为 2
-64
。选择检查次数时必须小心。有关更多详细信息,请参阅 OpenSSL 文档中的
BN_is_prime_ex
函数
nchecks
选项。
默认:
0检查 candidate 的素性。
- 类型:
Object
一个包含常用于加密和安全相关操作的常量的对象。当前定义的具体常量在 加密常量 中描述。
crypto.createCipheriv
History
不再支持将 CryptoKey 作为 key 传入。
现在支持通过 OpenSSL providers 提供的其他密码(例如 SM4-GCM、SM4-CCM、SM4-XTS、CBC-CTS 和 AES 密钥包装变体)。新增了 ctsMode 和 xtsStandard 选项。
现在支持 SIV 和 GCM-SIV 模式下的密码。
传递 CryptoKey 作为 key 已弃用。
使用 chacha20-poly1305 密码时,authTagLength 选项现在是可选的,默认为 16 字节。
密码和 iv 参数可以是 ArrayBuffer,并且每个都限制为最大 2 ** 31 - 1 字节。
key 参数现在可以是 KeyObject。
现在支持密码 chacha20-poly1305(ChaCha20-Poly1305 的 IETF 变体)。
现在支持 OCB 模式下的密码。
authTagLength 选项现在可用于在 GCM 模式下生成更短的认证标签,默认为 16 字节。
对于不需要初始化向量的密码,iv 参数现在可以是 null。
crypto.createCipheriv(algorithm, key, iv, options?): void
stringstring | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectstring | ArrayBuffer | Buffer | TypedArray | DataView | nullObjectstream.transform
选项][],包含以下附加属性:创建并返回一个 Cipheriv 对象,带有给定的 algorithm、key 和初始化向量 (iv)。
options 参数控制特定于密码的设置和流行为。除非使用 CCM 或 OCB 模式下的密码(例如 'aes-128-ccm'),否则该参数是可选的。在这种情况下,必须设置 authTagLength 选项,以指定认证标签的长度(单位为字节),参见 [CCM 模式][]。在 GCM 模式下,authTagLength 选项不是必需的,但可用于设置 getAuthTag() 返回的认证标签长度,默认值为 16 字节。
对于 SIV、GCM-SIV 和 chacha20-poly1305,authTagLength 选项默认为 16 字节。SIV 和 GCM-SIV 仅支持 16 字节的认证标签。
ctsMode 和 xtsStandard 选项用于配置 OpenSSL providers 暴露的参数。只有 OpenSSL 3.0 或更高版本,以及支持相应参数的 provider 才能使用这些选项。ctsMode 仅适用于 CBC-CTS 密码,而 xtsStandard 仅适用于 sm4-xts。如果为不支持该选项的可用密码实现提供其中任一选项,则会抛出 ERR_CRYPTO_UNSUPPORTED_OPERATION 错误。详情请参阅 [CBC-CTS 模式][]和 [XTS 模式][]。
可用算法取决于 OpenSSL。crypto.getCiphers() 列出 Node.js 暴露的算法。在较新的 OpenSSL 版本中,openssl list -cipher-algorithms 会显示 OpenSSL 可用的算法,其中可能包含 Node.js 未暴露的算法。
key 是 algorithm 使用的原始密钥,iv 是初始化向量。二者都可以是字符串、ArrayBuffer、Buffer、TypedArray 或 DataView。字符串形式的 key 使用 options.encoding 解码,该选项默认为 'utf8';字符串形式的 iv 始终按 UTF-8 解码。key 也可以是类型为 secret 的 KeyObject。如果密码不需要初始化向量,iv 可以是 null。
当为 key 或 iv 传递字符串时,请考虑 使用字符串作为加密 API 输入时的注意事项。
初始化向量的要求取决于算法。对于某些算法,IV 必须不可预测且唯一;对于其他算法,仅需唯一即可、必须使用固定值,或不使用 IV。请遵循所选算法的要求。IV 通常不必保密,可以与密文一起传输。
crypto.createDecipheriv
History
不再支持将 CryptoKey 作为 key 传入。
现在支持通过 OpenSSL providers 提供的其他密码(例如 SM4-GCM、SM4-CCM、SM4-XTS、CBC-CTS 和 AES 密钥包装变体)。新增了 ctsMode 和 xtsStandard 选项。
现在支持 SIV 和 GCM-SIV 模式下的密码。
传递 CryptoKey 作为 key 已弃用。
使用 chacha20-poly1305 密码时,authTagLength 选项现在是可选的,默认为 16 字节。
key 参数现在可以是 KeyObject。
现在支持密码 chacha20-poly1305(ChaCha20-Poly1305 的 IETF 变体)。
现在支持 OCB 模式下的密码。
authTagLength 选项现在可用于限制接受的 GCM 认证标签长度。
对于不需要初始化向量的密码,iv 参数现在可以是 null。
crypto.createDecipheriv(algorithm, key, iv, options?): void
stringstring | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectstring | ArrayBuffer | Buffer | TypedArray | DataView | nullObjectstream.transform
选项][],包含以下附加属性:创建并返回一个 Decipheriv 对象,使用给定的 algorithm、key 和初始化向量 (iv)。
options 参数控制特定于密码的设置和流行为。除非使用 CCM 或 OCB 模式下的密码(例如 'aes-128-ccm'),否则该参数是可选的。在这种情况下,必须设置 authTagLength 选项,以指定认证标签的长度(单位为字节),参见 [CCM 模式][]。对于 GCM 和 chacha20-poly1305,authTagLength 选项默认为 16 字节;如果使用不同的长度,则必须设置该选项。对于 SIV 和 GCM-SIV,authTagLength 选项默认为 16 字节,并且仅支持 16 字节的认证标签。
ctsMode 和 xtsStandard 选项用于配置 OpenSSL providers 暴露的参数。只有 OpenSSL 3.0 或更高版本,以及支持相应参数的 provider 才能使用这些选项。ctsMode 仅适用于 CBC-CTS 密码,而 xtsStandard 仅适用于 sm4-xts。如果为不支持该选项的可用密码实现提供其中任一选项,则会抛出 ERR_CRYPTO_UNSUPPORTED_OPERATION 错误。详情请参阅 [CBC-CTS 模式][]和 [XTS 模式][]。
可用算法取决于 OpenSSL。crypto.getCiphers() 列出 Node.js 暴露的算法。在较新的 OpenSSL 版本中,openssl list -cipher-algorithms 会显示 OpenSSL 可用的算法,其中可能包含 Node.js 未暴露的算法。
key 是 algorithm 使用的原始密钥,iv 是初始化向量。二者都可以是字符串、ArrayBuffer、Buffer、TypedArray 或 DataView。字符串形式的 key 使用 options.encoding 解码,该选项默认为 'utf8';字符串形式的 iv 始终按 UTF-8 解码。key 也可以是类型为 secret 的 KeyObject。如果密码不需要初始化向量,iv 可以是 null。
当为 key 或 iv 传递字符串时,请考虑 使用字符串作为加密 API 输入时的注意事项。
初始化向量的要求取决于算法。对于某些算法,IV 必须不可预测且唯一;对于其他算法,仅需唯一即可、必须使用固定值,或不使用 IV。请遵循所选算法的要求。IV 通常不必保密,可以与密文一起传输。
crypto.createDiffieHellman(prime, primeEncoding?, generator?, generatorEncoding?): void
string | ArrayBuffer | Buffer | TypedArray | DataViewnumber | string | ArrayBuffer | Buffer | TypedArray | DataView2使用提供的 prime 和可选的特定 generator 创建 DiffieHellman 密钥交换对象。
generator 参数可以是数字、字符串或 Buffer。如果未指定 generator,则使用值 2。
如果指定了 primeEncoding,则 prime 预期为字符串;否则预期为 Buffer、TypedArray 或 DataView。
如果指定了 generatorEncoding,则 generator 预期为字符串;否则预期为数字、Buffer、TypedArray 或 DataView。
crypto.createDiffieHellman(primeLength, generator?): void
创建 DiffieHellman 密钥交换对象,并使用可选的特定数字 generator 生成 primeLength 位的素数。如果未指定 generator,则使用值 2。
crypto.createDiffieHellmanGroup(name): void
stringcrypto.getDiffieHellman() 的别名。
crypto.createECDH(curveName): void
string使用由 curveName 字符串指定的预定义曲线创建椭圆曲线 Diffie-Hellman (ECDH) 密钥交换对象。使用 crypto.getCurves() 获取可用曲线名称列表。在最近的 OpenSSL 版本上,openssl ecparam -list_curves 也将显示每个可用椭圆曲线的名称和描述。
crypto.createHash
History
The outputLength option is now required for XOF hash functions without default output lengths.
Hash algorithms exposed by OpenSSL providers are now supported. The functionName and customization options were added for cSHAKE hash functions.
为 XOF 哈希函数添加了 outputLength 选项。
crypto.createHash(algorithm, options?): void
stringObjectstring | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewnumber创建并返回一个 Hash 对象,可用于使用给定的 algorithm 生成哈希摘要。可选的 options 参数控制流行为。对于诸如 'shake256' 之类的 XOF 哈希函数,outputLength 选项指定所需的输出长度(以字节为单位)。对于没有默认输出长度的 XOF 哈希函数,这是必需的。
functionName 和 customization 选项仅适用于 cSHAKE-128 和 cSHAKE-256。只有在使用 OpenSSL 4.0 或更高版本构建 Node.js,且所选提供程序支持相应摘要参数时,才支持这些选项。字符串会编码为 UTF-8,字符串和值都不得包含 NUL 字节。这两个选项的默认值均为空字节字符串。对于 OpenSSL 内置提供程序,functionName 区分大小写,且必须是 ''、'TupleHash'、'ParallelHash' 或 'KMAC'。其他提供程序可能会施加不同的限制。当这两个选项均为空时,对于相同的输出长度,cSHAKE 会产生与对应 SHAKE 函数相同的输出。cshake-128 和 cshake-256 的默认输出长度分别为 32 字节和 64 字节。
当数据量较小(< 5MB)且可随时获取时,通常 crypto.hash() 更快。
可用算法取决于平台上的 OpenSSL 版本和配置。例如 'sha256' 和 'sha512'。使用 crypto.getHashes() 获取 Node.js 进程可用的哈希算法列表。
示例:生成文件的 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', () => { // 哈希流只会产生一个元素。 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', () => { // 哈希流只会产生一个元素。 const data = input.read(); if (data) hash.update(data); else { console.log(`${hash.digest('hex')} ${filename}`); } });
crypto.createHmac(algorithm, key, options?): void
创建并返回一个 Hmac 对象,使用给定的 algorithm 和 key。可选 options 参数控制流行为。
可用算法取决于平台上的 OpenSSL 版本和配置。例如 'sha256' 和 'sha512'。crypto.getHashes() 列出了哈希 API 可用的算法,但 HMAC 另有一些限制,因此并非列出的所有算法都适用。
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', () => { // 哈希流只会产生一个元素。 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', () => { // 哈希流只会产生一个元素。 const data = input.read(); if (data) hmac.update(data); else { console.log(`${hmac.digest('hex')} ${filename}`); } });
crypto.createMac(algorithm, key, options?): void
稳定性:1.2 - 候选发布版
stringArrayBuffer | Buffer | TypedArray | DataView | KeyObjectObjectstringstringArrayBuffer | Buffer | TypedArray | DataViewArrayBuffer | Buffer | TypedArray | DataViewArrayBuffer | Buffer | TypedArray | DataViewnumberalgorithm 必须是非空的提供程序 MAC 名称。上面列出的 MAC 特定属性是标准 stream.transform options 的扩展,只有在所选提供程序实现声明支持对应类型的参数时,才会传递这些属性。如果提供了所选实现不支持的 MAC 特定选项,则会导致错误。
下表总结了 OpenSSL 内置提供程序中的 MAC 实现所接受的 MAC 特定选项。每种 MAC 都必须提供 key 参数。该表仅列出 MAC 特定选项;每个系列仍可使用标准 stream.transform options。
| MAC 系列 | 必需选项 | 可选选项 | 备注 |
|---|---|---|---|
| HMAC | digest | 无 | |
| CMAC | 使用 CBC 模式的 cipher | 无 | |
| GMAC | 使用 GCM 模式的 cipher、非空 iv | 无 | 对使用给定密钥进行身份验证的每条消息,都必须使用唯一的 IV。 |
| KMAC | 无 | customization、outputLength | |
| BLAKE2 MAC | 无 | customization、salt、outputLength | |
| Poly1305 | 无 | 无 | 每个密钥只能用于一条消息。 |
| SipHash | 无 | outputLength |
outputLength 用于配置提供程序 MAC 的输出大小。它绝不会通过计算更长的标签再截断来实现。值 0 会传递给提供程序,且只有在该提供程序能够以零字节输出初始化并完成 MAC 时才会被接受。如果省略 outputLength,则使用提供程序的默认输出大小,该值必须非零。
key 必须包含字节,或者是类型为 secret 的 KeyObject。密钥长度和其他密钥要求由所选提供程序实现决定。
可用算法及其接受的参数取决于 OpenSSL 版本、已加载的提供程序以及当前启用的默认属性查询。使用 crypto.getMacs() 列出可获取的 MAC 名称。列出的名称仍可能要求提供选项或具有提供程序特定属性的密钥。
crypto.createPrivateKey
History
密钥也可以是引用 OpenSSL STORE 加载器对象的 URL。新增了 properties 选项。
以 CryptoKey 作为 key 传递不再受支持。
为 ML-KEM 和 SLH-DSA 密钥类型新增了 JWK 格式支持。
将 CryptoKey 作为 key 传递已弃用。
添加了对 'raw-private' 和 'raw-seed' 格式的支持。
添加对 ML-DSA 密钥的支持。
key 也可以是 JWK 对象。
key 也可以是 ArrayBuffer。添加了 encoding 选项。key 不能包含超过 2 ** 32 - 1 字节。
crypto.createPrivateKey(key): void
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | URLstring | ArrayBuffer | Buffer | TypedArray | DataView | Object | URLURL
。string'pem'
、
'der'
、
'jwk'
、
'raw-private'
或
'raw-seed'
。
默认值:
'pem'
。string'pkcs1'
、
'pkcs8'
或
'sec1'
。仅当
format
为
'der'
时才需要此选项,否则将忽略该选项。stringkey
为字符串时使用的字符串编码。stringformat
为
'raw-private'
或
'raw-seed'
时必须提供,否则将忽略该选项。
必须是[受支持的密钥类型][asymmetric key types]。stringasymmetricKeyType
为
'ec'
时必须提供,否则将忽略该选项。创建并返回一个包含私钥的新密钥对象。如果 key 是字符串或 Buffer,format 假定为 'pem';否则,key 必须是具有上述属性的对象。
如果私钥已加密,则必须指定 passphrase。密码短语的长度限制为 1024 字节。
稳定性:1.1 - 活跃开发中
如果 key 是 URL(或 key 属性为 URL 的对象),则会通过 OpenSSL STORE 加载器加载私钥。该 URL 会作为 URI 传递给 OpenSSL,例如 file: URI 或由提供程序支持的方案(如 pkcs11:)。启用[权限模型][Permission Model]时,需要使用 --allow-openssl-store。
警告:URI 方案不会固定 OpenSSL STORE 加载器,也不能证明返回的密钥来自何处。Node.js 会将 URI 转发给 OpenSSL,由 OpenSSL 根据其版本和配置选择加载器。例如,OpenSSL 可能会在尝试
pkcs11加载器之前,先将不透明的 URI(例如pkcs11:object=...,即方案后没有//的 URI)提供给其file加载器。如果完整 URI 是有效的本地路径且该文件存在,则可能会加载该文件。 Node.js 不会验证是哪个加载器提供了密钥。不要依赖特定于提供程序的 URI 方案来证明密钥来自该提供程序或硬件设备。
已配置的 OpenSSL STORE 加载器拥有广泛的权限,可能会访问文件、设备、令牌或网络。加载器执行的访问不受 fs.read、fs.write 或 net 权限范围的限制。
使用 URL 时,即使 format、type、asymmetricKeyType 和 namedCurve 这些选项原本会相互依赖(例如 format: 'der' 时的 type,或 asymmetricKeyType: 'ec' 时的 namedCurve),也会忽略它们。输入会作为 URI 传递给 STORE 加载器,而不会作为 PEM、DER、JWK 或原始密钥材料处理。passphrase 仍会作为传递给加载器的可选 PIN/密码短语使用;如果该 passphrase 是字符串,encoding 也会生效。
请使用 passphrase,而不要将凭据嵌入传递给 STORE 加载器的 URI 中。Node.js 会从自身的权限拒绝资源和诊断信息中隐藏 URI。加载开始后,OpenSSL 或提供程序报告的错误可能会包含 URI。
当 properties 与 URL 密钥一同指定时,它会作为用于选择 STORE 加载器的属性查询传递给 OpenSSL。它不会追加到 URL 中,并且不同于特定于提供程序的 URI 参数。
crypto.createPublicKey
History
以 CryptoKey 作为 key 传递不再受支持。
为 ML-KEM 和 SLH-DSA 密钥类型新增了 JWK 格式支持。
将 CryptoKey 作为 key 传递已弃用。
添加了对 'raw-public' 格式的支持。
添加对 ML-DSA 密钥的支持。
key 也可以是 JWK 对象。
key 也可以是 ArrayBuffer。添加了 encoding 选项。key 不能包含超过 2 ** 32 - 1 字节。
key 参数现在可以是类型为 private 的 KeyObject。
key 参数现在可以是私钥。
crypto.createPublicKey(key): void
Object | string | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataView | Objectstring'pem'
、
'der'
、
'jwk'
或
'raw-public'
。
默认:
'pem'
。string'pkcs1'
或
'spki'
。仅当
format
为
'der'
时需要此选项,否则忽略。stringkey
是字符串时使用的字符串编码。stringasymmetricKeyType
为
'ec'
时需要,否则忽略。创建并返回一个包含公钥的新密钥对象。如果 key 是字符串或 Buffer,format 假定为 'pem';如果 key 是类型为 'private' 的 KeyObject,则公钥是从给定的私钥派生的;否则,key 必须是具有上述属性的对象。
如果格式是 'pem',key 也可以是 X.509 证书。
因为公钥可以从私钥派生,所以可以传递私钥而不是公钥。在这种情况下,此函数的行为就像调用了 crypto.createPrivateKey(),除了返回的 KeyObject 的类型将是 'public' 并且无法从返回的 KeyObject 中提取私钥。类似地,如果给定类型为 'private' 的 KeyObject,将返回类型为 'public' 的新 KeyObject,并且无法从返回的对象中提取私钥。
由存储支持的私钥可以先使用 crypto.createPrivateKey() 加载,然后作为公钥使用;不能直接将 URL 传递给 crypto.createPublicKey()。
crypto.createSecretKey(key, encoding?): void
创建并返回一个包含用于对称加密或 Hmac 的密钥的新密钥对象。
crypto.createSign(algorithm, options?): void
创建并返回一个使用给定 algorithm 的 Sign 对象。使用 crypto.getHashes() 获取哈希 API 可用的名称。密钥类型和签名方案可能会对可用摘要施加其他限制。可选的 options 参数用于控制 stream.Writable 的行为。
在某些情况下,可以使用签名算法的名称(如 RSA-SHA256)而不是摘要算法来创建 Verify 实例。这将使用相应的摘要算法。这不适用于所有签名算法,例如 RSA-SHA1,因此最好始终使用摘要算法名称。
crypto.createVerify(algorithm)
History
创建并返回一个使用给定 algorithm 的 Verify 对象。
使用 crypto.getHashes() 获取哈希 API 可用的名称。
密钥类型和签名方案可能会对可用摘要施加其他限制。可选的 options 参数用于控制
stream.Writable 的行为。
在某些情况下,可以使用签名算法的名称(如 RSA-SHA256)而不是摘要算法来创建 Verify 实例。这将使用相应的摘要算法。这不适用于所有签名算法,例如 RSA-SHA1,因此最好始终使用摘要算法名称。
crypto.createHash(algorithm)
History
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject | URLArrayBuffer | Buffer | TypedArray | DataView使用私钥和 KEM 算法进行密钥解封装。
支持的密钥类型及其 KEM 算法有:
- RSA-OAEP2 RSA 密钥封装
- P-2563 DHKEM(P-256, HKDF-SHA256)、DHKEM(P-384, HKDF-SHA256)、DHKEM(P-521, HKDF-SHA256)
- X255193 DHKEM(X25519, HKDF-SHA256)
- X4483 DHKEM(X448, HKDF-SHA512)
- ML-KEM-5121 ML-KEM
- ML-KEM-7681 ML-KEM
- ML-KEM-10241 ML-KEM
如果 ciphertext 不是 [Buffer][],此函数的行为就像已将 encoding 传递给 [Buffer.from][]。
如果提供了 callback 函数,此函数使用 libuv 的线程池。
crypto.diffieHellman(key)
History
除了 KeyObject 实例外,还接受密钥数据。
添加了可选的 callback 参数。
ObjectObject | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject | URLObject | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject基于 privateKey 和 publicKey 计算 Diffie-Hellman 共享秘密。 两个密钥必须表示相同的非对称密钥类型,并且必须支持 DH 或 ECDH 操作。
如果 privateKey 不是 [KeyObject][],此函数的行为就像 encoding 已传递给 [Buffer.from][]。
如果 publicKey 不是 [KeyObject][],此函数的行为就像 encoding 已传递给 [Buffer.from][]。
如果提供了 callback 函数,此函数使用 libuv 的线程池。
crypto.encapsulate(publicKey)
History
- publicKey
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject公钥 - callback
Function - 返回:
Object未提供 callback 函数时。
使用公钥和 KEM 算法进行密钥封装。
支持的密钥类型及其 KEM 算法有:
- RSA-OAEP2 RSA 密钥封装
- P-2563 DHKEM(P-256, HKDF-SHA256)、DHKEM(P-384, HKDF-SHA256)、DHKEM(P-521, HKDF-SHA256)
- X255193 DHKEM(X25519, HKDF-SHA256)
- X4483 DHKEM(X448, HKDF-SHA512)
- ML-KEM-5121 ML-KEM
- ML-KEM-7681 ML-KEM
- ML-KEM-10241 ML-KEM
如果 publicKey 不是 [KeyObject][],此函数的行为就像将 encoding 传递给了 [Buffer.from][]。
如果提供了 callback 函数,此函数使用 libuv 的线程池。
crypto.fips
History
稳定性:0 - 已弃用
用于检查和控制 FIPS 模式. 已弃用的属性。请改用
crypto.getFips() 和 crypto.setFips()。
crypto.generateKey(type, options)
History
向 callback 参数传递无效的回调现在抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK。
- type
string生成的密钥的预期用途。当前接受的值为 'hmac' 和 'aes'。 - options
Object- length
number要生成的密钥的位长度。这必须是大于 0 的值。- 如果 type 是 'hmac',最小值为 8,最大长度为 231-1。如果值不是 8 的倍数,生成的密钥将被截断为长度。
- 如果 type 是 'aes',长度必须是 128、192 或 256 之一。
- length
- callback
Function
异步生成给定类型的新随机密钥。options 将决定对 type 执行哪些验证。
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
History
添加对 SLH-DSA 密钥对的支持。
添加对 ML-KEM 密钥对的支持。
添加对 ML-DSA 密钥对的支持。
向 callback 参数传递无效的回调现在抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK。
添加为 RSA-PSS 密钥对定义 RSASSA-PSS-params 序列参数的能力。
添加对 Diffie-Hellman 的支持。
添加对 RSA-PSS 密钥对的支持。
添加生成 X25519 和 X448 密钥对的能力。
添加生成 Ed25519 和 Ed448 密钥对的能力。
如果未指定编码,generateKeyPair 和 generateKeyPairSync 函数现在生成密钥对象。
crypto.generateKeyPair(type, options, callback): void
Objectnumbernumber0x10001
。stringstringnumbernumberq
的大小(位)(DSA)。stringBuffernumbernumber2
。stringcrypto.getDiffieHellman()
。string'named'
或
'explicit'
(EC)。
默认:
'named'
。ObjectkeyObject.export()
。ObjectkeyObject.export()
。生成给定 type 的新非对称密钥对。参见支持的 非对称密钥类型。
对于 RSA-PSS 密钥,crypto.getHashes() 会列出哈希 API 可用的算法,但并非所有列出的摘要都能编码到 RSA-PSS 参数中,或受到活动 RSA 实现的支持。
如果指定了 publicKeyEncoding 或 privateKeyEncoding,此函数的行为就像对其结果调用了 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) => { // 处理错误并使用生成的密钥对。 });
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) => { // 处理错误并使用生成的密钥对。 });
完成后,callback 将被调用,err 设置为 undefined,publicKey / privateKey 代表生成的密钥对。
如果此方法作为其 util.promisify() 版本调用,它返回一个 Promise,对象包含 publicKey 和 privateKey 属性。
crypto.generateKeyPairSync
History
添加对 SLH-DSA 密钥对的支持。
添加对 ML-KEM 密钥对的支持。
添加对 ML-DSA 密钥对的支持。
添加为 RSA-PSS 密钥对定义 RSASSA-PSS-params 序列参数的能力。
添加对 Diffie-Hellman 的支持。
添加对 RSA-PSS 密钥对的支持。
添加生成 X25519 和 X448 密钥对的能力。
添加生成 Ed25519 和 Ed448 密钥对的能力。
如果未指定编码,generateKeyPair 和 generateKeyPairSync 函数现在生成密钥对象。
crypto.generateKeyPairSync(type, options): void
Objectnumbernumber0x10001
。stringstringnumbernumberq
的大小(位)(DSA)。stringBuffernumbernumber2
。stringcrypto.getDiffieHellman()
。string'named'
或
'explicit'
(EC)。
默认:
'named'
。ObjectkeyObject.export()
。ObjectkeyObject.export()
。生成给定 type 的新非对称密钥对。参见支持的 非对称密钥类型。
对于 RSA-PSS 密钥,crypto.getHashes() 会列出哈希 API 可用的算法,但并非所有列出的摘要都能编码到 RSA-PSS 参数中,或受到活动 RSA 实现的支持。
如果指定了 publicKeyEncoding 或 privateKeyEncoding,此函数的行为就像对其结果调用了 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): void
同步生成给定 length 的新随机密钥。type 将决定对 length 执行哪些验证。
const { generateKeySync, } = await import('node:crypto'); const key = generateKeySync('hmac', { length: 512 }); console.log(key.export().toString('hex')); // e89..........41e
const { generateKeySync, } = require('node:crypto'); const key = generateKeySync('hmac', { length: 512 }); console.log(key.export().toString('hex')); // e89..........41e
生成的 HMAC 密钥的大小不应超过底层哈希函数的块大小。有关更多信息,请参见 crypto.createHmac()。
crypto.generatePrime
History
向 callback 参数传递无效的回调现在抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK。
crypto.generatePrime(size, options?, callback): void
numberObjectArrayBuffer | SharedArrayBuffer | TypedArray | Buffer | DataView | bigintArrayBuffer | SharedArrayBuffer | TypedArray | Buffer | DataView | bigintbooleanfalse
。booleantrue
时,生成的素数作为
bigint
返回。FunctionErrorArrayBuffer | bigint生成 size 位的伪随机素数。
如果 options.safe 为 true,素数将是安全素数——即,(prime - 1) / 2 也将是素数。
options.add 和 options.rem 参数可用于强制执行额外要求,例如,对于 Diffie-Hellman:
- 如果
options.add和options.rem都设置,素数将满足条件prime % add = rem。 - 如果仅设置
options.add且options.safe不为true,素数将满足条件prime % add = 1。 - 如果仅设置
options.add且options.safe设置为true,素数将改为满足条件prime % add = 3。这是必要的,因为对于options.add > 2,prime % add = 1将与options.safe强制的条件相矛盾。 - 如果未给出
options.add,则忽略options.rem。
如果 options.add 和 options.rem 作为 ArrayBuffer、SharedArrayBuffer、TypedArray、Buffer 或 DataView 给出,则必须编码为大端序列。
默认情况下,素数编码为 ArrayBuffer 中的大端字节序列。如果 bigint 选项为 true,则提供 bigint。
素数的 size 将直接影响生成素数所需的时间。大小越大,所需时间越长。因为我们使用 OpenSSL 的 BN_generate_prime_ex 函数,它只提供最小控制我们中断生成过程的能力,所以不建议生成过大的素数,因为这样做可能会使进程无响应。
crypto.generatePrimeSync(size, options?): void
numberObjectArrayBuffer | SharedArrayBuffer | TypedArray | Buffer | DataView | bigintArrayBuffer | SharedArrayBuffer | TypedArray | Buffer | DataView | bigintbooleanfalse
。booleantrue
时,生成的素数作为
bigint
返回。生成 size 位的伪随机素数。
如果 options.safe 为 true,素数将是安全素数——即,(prime - 1) / 2 也将是素数。
options.add 和 options.rem 参数可用于强制执行额外要求,例如,对于 Diffie-Hellman:
- 如果
options.add和options.rem都设置,素数将满足条件prime % add = rem。 - 如果仅设置
options.add且options.safe不为true,素数将满足条件prime % add = 1。 - 如果仅设置
options.add且options.safe设置为true,素数将改为满足条件prime % add = 3。这是必要的,因为对于options.add > 2,prime % add = 1将与options.safe强制的条件相矛盾。 - 如果未给出
options.add,则忽略options.rem。
如果 options.add 和 options.rem 作为 ArrayBuffer、SharedArrayBuffer、TypedArray、Buffer 或 DataView 给出,则必须编码为大端序列。
默认情况下,素数编码为 ArrayBuffer 中的大端字节序列。如果 bigint 选项为 true,则提供 bigint。
素数的 size 将直接影响生成素数所需的时间。大小越大,所需时间越长。因为我们使用 OpenSSL 的 BN_generate_prime_ex 函数,它只提供最小控制我们中断生成过程的能力,所以不建议生成过大的素数,因为这样做可能会使进程无响应。
crypto.getCipherInfo(nameOrNid, options?): void
返回有关给定密码的信息。
某些密码接受可变长度的密钥和初始化向量。默认情况下,crypto.getCipherInfo() 方法将返回这些密码的默认值。要测试给定的密钥长度或 IV 长度对于给定密码是否可接受,请使用 keyLength 和 ivLength 选项。如果给定的值不可接受,将返回 undefined。
crypto.getCiphers(): void
- 返回:
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(): void
- 返回值:
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.createDiffieHellmanGroup(name): void
string创建一个预定义的 Diffie-Hellman 密钥交换对象。支持的组列在 [crypto.getDiffieHellman][] 文档中。
返回的对象模仿由 [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 和 bobSecret 应该相同 */ 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 和 bobSecret 应该相同 */ console.log(aliceSecret === bobSecret);
crypto.getFips(): void
使用 OpenSSL 3 时,此 API 报告默认属性查询是否包含 fips=yes。它不能证明 FIPS 提供程序已加载或经过验证。即使请求的加密实现无法获取,因为没有已加载的提供程序为 fips=yes 提供匹配项,它也可能返回 1。请参阅 FIPS 模式。
crypto.getHashes(): void
- 返回:
string[]支持的哈希算法名称数组,例如'RSA-SHA256'。哈希算法也称为“摘要”算法。
这是当前进程中可供 crypto.createHash() 和 crypto.hash() 使用的权威 Node.js 哈希算法列表。对于 OpenSSL 3 或更高版本,该列表取决于已加载的提供程序,以及首次生成列表时生效的默认属性查询。部分列出的算法可能需要特定于 API 的选项,例如 XOF 哈希函数的 outputLength。
列出的哈希算法不一定受将摘要与另一项加密操作结合使用的 API 支持,例如 HMAC、密钥派生或签名。这些操作可能会施加额外限制。
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.getMacs(): void
稳定性:1.2 - 候选发布版
- 返回:
string[]一个新数组,包含可获取的 MAC 实现的小写名称及其别名,并按名称排序。
返回已加载的 OpenSSL 提供程序所公开且符合当前默认属性查询的 MAC 名称。重复名称和数字 OID 别名会被省略。在不支持 OpenSSL EVP_MAC 的构建版本中,此函数返回空数组。
返回的名称描述的是 OpenSSL 可以获取的实现。它们并不保证 crypto.createMac() 无需额外选项即可初始化 MAC。提供程序可能要求额外参数或具有特定于算法属性的密钥,也可能公开此 API 不支持的参数。
使用 crypto.setFips() 成功更改 FIPS 模式后,后续调用会反映新的模式,新建的 Mac 对象也会使用该模式。现有的 Mac 对象会继续使用创建时选定的提供程序实现。
const { getMacs } = await import('node:crypto'); console.log(getMacs()); // ['blake2bmac', 'blake2smac', 'cmac', 'gmac', 'hmac', ...]
crypto.getRandomValues(typedArray): void
Buffer | TypedArray | DataView | ArrayBuffercrypto.webcrypto.getRandomValues() 的便捷别名。此实现不符合 Web Crypto 规范,要编写 Web 兼容代码,请改用 crypto.webcrypto.getRandomValues()。
crypto.hash
History
The outputLength option is now required for XOF hash functions without default output lengths.
Hash algorithms exposed by OpenSSL providers are now supported. The functionName and customization options were added for cSHAKE hash functions.
此 API 不再处于实验阶段。
为 XOF 哈希函数添加了 outputLength 选项。
crypto.hash(algorithm, data, options?): void
string | Buffer | TypedArray | DataViewdata
是字符串时,它将在被哈希之前编码为 UTF-8。如果希望字符串输入使用不同的输入编码,用户可以使用
TextEncoder
或
Buffer.from()
将字符串编码为
TypedArray
,并将编码后的
TypedArray
传递到此 API 中。string | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewstring'hex'
。number用于创建数据一次性哈希摘要的实用工具。当哈希少量现成数据(<= 5MB)时,它可能比基于对象的 crypto.createHash() 更快。如果数据可能很大或是流式的,仍建议使用 crypto.createHash()。
可用算法取决于平台上的 OpenSSL 版本和配置。示例包括 'sha256' 和 'sha512'。使用 crypto.getHashes() 获取 Node.js 进程可用的哈希算法列表。
functionName 和 customization 选项仅适用于 cSHAKE-128 和 cSHAKE-256。只有在使用 OpenSSL 4.0 或更高版本构建 Node.js,且所选提供程序支持相应摘要参数时,才支持这些选项。字符串会编码为 UTF-8,字符串和字节值均不得包含 NUL 字节。这两个选项的默认值都是空字节串。对于 OpenSSL 内置提供程序,functionName 区分大小写,且必须为 ''、'TupleHash'、'ParallelHash' 或 'KMAC'。其他提供程序可能施加不同限制。当这两个选项都为空时,对于相同的输出长度,cSHAKE 会产生与相应 SHAKE 函数相同的输出。cshake-128 和 cshake-256 的默认输出长度分别为 32 和 64 字节。
如果 options 是字符串,则它指定 outputEncoding。
示例:
const crypto = require('node:crypto'); const { Buffer } = require('node:buffer'); // 对字符串进行哈希处理并将结果作为十六进制编码字符串返回。 const string = 'Node.js'; // 10b3493287f831e81a438811a1ffba01f8cec4b7 console.log(crypto.hash('sha1', string)); // 将 base64 编码的字符串编码为 Buffer,对其进行哈希处理并将 // 结果作为 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'; // 对字符串进行哈希处理并将结果作为十六进制编码字符串返回。 const string = 'Node.js'; // 10b3493287f831e81a438811a1ffba01f8cec4b7 console.log(crypto.hash('sha1', string)); // 将 base64 编码的字符串编码为 Buffer,对其进行哈希处理,并将 // 结果作为 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): void
stringstring | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectstring | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewnumber255
倍(例如
sha512
生成 64 字节哈希,使最大 HKDF 输出为 16320 字节)。FunctionErrorArrayBufferHKDF 是 RFC 5869 中定义的一种简单密钥派生函数。给定的 ikm、salt 和 info 与 digest 一起使用,以派生长度为 keylen 字节的密钥。可用的摘要算法取决于 OpenSSL 的版本和配置。HKDF 在内部使用 HMAC。crypto.getHashes() 列出了哈希 API 可用的算法,但列出的算法并非都适用于 HMAC 或 HKDF。
提供的 callback 函数接收两个参数:err 和 derivedKey。如果在派生密钥时发生错误,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): void
stringstring | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectstring | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewnumber255
倍(例如
sha512
生成 64 字节哈希,使最大 HKDF 输出为 16320 字节)。提供 RFC 5869 中定义的同步 HKDF 密钥派生函数。给定的 ikm、salt 和 info 与 digest 一起使用,以派生长度为 keylen 字节的密钥。可用的摘要算法取决于 OpenSSL 的版本和配置。HKDF 在内部使用 HMAC。crypto.getHashes() 列出了哈希 API 可用的算法,但列出的算法并非都适用于 HMAC 或 HKDF。
成功生成的 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.parsePKCS12(bundle, options?): void
ArrayBuffer | Buffer | TypedArray | DataView.p12
或
.pfx
)捆绑包。Objectstring | ArrayBuffer | Buffer | TypedArray | DataView''
。X509Certificate | nullprivateKey
匹配的证书,如果不存在匹配的证书,则为
null
。X509Certificate[]解析 PKCS#12 捆绑包(通常以 .p12 或 .pfx 为扩展名存储),并返回其中的私钥和证书。
import { parsePKCS12 } from 'node:crypto'; import { readFileSync } from 'node:fs'; const { privateKey, certificate, additionalCertificates } = parsePKCS12( readFileSync('bundle.p12'), { passphrase: 'secret' }, );
crypto.pbkdf2(password, salt, iterations, keylen, digest, callback): void
string | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewnumbernumberstring提供异步基于密码的密钥派生函数 2(PBKDF2)实现。应用由 digest 指定的选定 HMAC 摘要算法,从 password、salt 和 iterations 派生请求字节长度(keylen)的密钥。
提供的 callback 函数使用两个参数调用:err 和 derivedKey。如果派生密钥时发生错误,err 将被设置;否则 err 将为 null。默认情况下,成功生成的 derivedKey 将作为 Buffer 传递给回调。如果任何输入参数指定了无效的值或类型,将抛出错误。
iterations 参数必须是一个设置得尽可能高的数字。迭代次数越高,派生密钥就越安全,但完成所需的时间就越长。
salt 应尽可能唯一。建议 salt 是随机的且至少 16 字节长。详见 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑 [将字符串用作加密 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' });
可用的摘要算法取决于 OpenSSL 的版本和配置。PBKDF2 在内部使用 HMAC。crypto.getHashes() 列出了哈希 API 可用的算法,但列出的算法并非都适用于 HMAC 或 PBKDF2。
此 API 使用 libuv 的线程池,这可能会对某些应用程序产生令人惊讶的负面性能影响;有关更多信息,请参阅 UV_THREADPOOL_SIZE 文档。
crypto.pbkdf2Sync(password, salt, iterations, keylen, digest): void
string | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewnumbernumberstring提供同步基于密码的密钥派生函数 2 (PBKDF2) 实现。应用由 digest 指定的选定 HMAC 摘要算法,从 password、salt 和 iterations 派生请求字节长度 (keylen) 的密钥。
如果发生错误,将抛出 Error,否则派生密钥将作为 Buffer 返回。
iterations 参数必须是一个设置得尽可能高的数字。迭代次数越高,派生密钥就越安全,但完成所需的时间就越长。
salt 应尽可能唯一。建议 salt 是随机的且至少 16 字节长。详见 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑 [将字符串用作加密 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'
可用的摘要算法取决于 OpenSSL 的版本和配置。PBKDF2 在内部使用 HMAC。crypto.getHashes() 列出了哈希 API 可用的算法,但列出的算法并非都适用于 HMAC 或 PBKDF2。
crypto.privateDecrypt
History
不再支持将 CryptoKey 作为 privateKey 传入。
添加了 mgf1Hash 选项。
除非 OpenSSL 构建支持隐式拒绝,否则 RSA_PKCS1_PADDING 填充已被禁用。
添加了 string、ArrayBuffer 和 CryptoKey 作为允许的密钥类型。oaepLabel 可以是 ArrayBuffer。buffer 可以是 string 或 ArrayBuffer。所有接受 buffer 的类型限制为最大 2 ** 31 - 1 字节。
添加了 oaepLabel 选项。
添加了 oaepHash 选项。
此函数现在支持密钥对象。
crypto.privateDecrypt(privateKey, buffer): void
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject | URLstringmgf1Hash
。
默认值:
'sha1'stringoaepHash
的值。这允许 OAEP 摘要和 MGF1 摘要不同。string | ArrayBuffer | Buffer | TypedArray | DataViewcrypto.constantscrypto.constants
中定义的可选填充值,可以是:
crypto.constants.RSA_NO_PADDING
、
crypto.constants.RSA_PKCS1_PADDING
或
crypto.constants.RSA_PKCS1_OAEP_PADDING
。string | ArrayBuffer | Buffer | TypedArray | DataView使用 privateKey 解密 buffer。buffer 之前是使用相应的公钥加密的,例如使用 crypto.publicEncrypt()。
crypto.getHashes() 列出了哈希 API 可用的算法,但当前的 RSA 实现可能会对用于 OAEP 或 MGF1 的摘要施加额外限制。
如果 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): void
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject | URLstring | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject | URLstring | ArrayBuffer | Buffer | TypedArray | DataViewcrypto.constantscrypto.constants
中定义的可选填充值,可以是:
crypto.constants.RSA_NO_PADDING
或
crypto.constants.RSA_PKCS1_PADDING
。stringbuffer
、
key
或
passphrase
为字符串时使用的字符串编码。string | ArrayBuffer | Buffer | TypedArray | DataView使用 privateKey 加密 buffer。返回的数据可以使用相应的公钥解密,例如使用 crypto.publicDecrypt()。
如果 privateKey 不是 KeyObject,此函数的行为就好像 privateKey 已传递给 crypto.createPrivateKey()。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_PADDING。
crypto.publicDecrypt(key, buffer): void
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectstring | ArrayBuffer | Buffer | TypedArray | DataViewcrypto.constantscrypto.constants
中定义的可选填充值,可能是:
crypto.constants.RSA_NO_PADDING
或
crypto.constants.RSA_PKCS1_PADDING
。stringbuffer
、
key
、
或
passphrase
为字符串时使用的字符串编码。string | ArrayBuffer | Buffer | TypedArray | DataView使用 key 解密 buffer。buffer 之前是使用相应的私钥加密的,例如使用 crypto.privateEncrypt()。
如果 key 不是 KeyObject,此函数的行为就好像 key 已传递给 crypto.createPublicKey()。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_PADDING。
因为 RSA 公钥可以从私钥派生,所以可以传递私钥而不是公钥。
crypto.publicEncrypt
History
将 CryptoKey 作为 key 传递不再受支持。
添加了 mgf1Hash 选项。
添加了 string、ArrayBuffer 和 CryptoKey 作为允许的密钥类型。oaepLabel 和 passphrase 可以是 ArrayBuffer。buffer 可以是 string 或 ArrayBuffer。所有接受 buffer 的类型限制为最大 2 ** 31 - 1 字节。
添加了 oaepLabel 选项。
添加了 oaepHash 选项。
此函数现在支持密钥对象。
crypto.publicEncrypt(key, buffer): void
Object | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectstring | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectKeyObject
。stringmgf1Hash
。
默认值:
'sha1'stringoaepHash
的值。
这样可以使 OAEP 摘要与 MGF1 摘要不同。string | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewcrypto.constantscrypto.constants
中定义的可选填充值,可能是:
crypto.constants.RSA_NO_PADDING
、
crypto.constants.RSA_PKCS1_PADDING
,或
crypto.constants.RSA_PKCS1_OAEP_PADDING
。stringbuffer
、
key
、
oaepLabel
或
passphrase
为字符串时使用的字符串编码。string | ArrayBuffer | Buffer | TypedArray | DataView使用 key 加密 buffer 的内容并返回一个包含加密内容的新 Buffer。返回的数据可以使用相应的私钥解密,例如使用 crypto.privateDecrypt()。
crypto.getHashes() 列出了哈希 API 可用的算法,但当前活动的 RSA 实现可能会对用于 OAEP 或 MGF1 的摘要施加额外限制。
如果 key 不是 KeyObject,此函数的行为就好像 key 已传递给 crypto.createPublicKey()。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_OAEP_PADDING。
因为 RSA 公钥可以从私钥派生,所以可以传递私钥而不是公钥。
crypto.randomBytes(size, callback?): void
生成在密码学上安全的伪随机数据。size 参数是一个数字,表示要生成的字节数。
如果提供了 callback 函数,字节将异步生成,并使用两个参数 err 和 buf 调用 callback 函数。如果发生错误,err 将是一个 Error 对象;否则它将为 null。buf 参数是一个包含所生成字节的 Buffer。
// Asynchronous const { randomBytes, } = await import('node:crypto'); randomBytes(256, (err, buf) => { if (err) throw err; console.log(`${buf.length} 字节的随机数据:${buf.toString('hex')}`); });
// Asynchronous const { randomBytes, } = require('node:crypto'); randomBytes(256, (err, buf) => { if (err) throw err; console.log(`${buf.length} 字节的随机数据:${buf.toString('hex')}`); });
如果未提供 callback 函数,随机字节将同步生成,并作为 Buffer 返回。如果生成字节时出现问题,则会抛出错误。
// Synchronous const { randomBytes, } = await import('node:crypto'); const buf = randomBytes(256); console.log( `${buf.length} 字节的随机数据:${buf.toString('hex')}`);
// Synchronous const { randomBytes, } = require('node:crypto'); const buf = randomBytes(256); console.log( `${buf.length} 字节的随机数据:${buf.toString('hex')}`);
crypto.randomBytes() 方法会一直等待,直到有足够的可用熵。通常,这不会超过几毫秒。生成随机字节可能长时间阻塞的唯一情况是在启动后,此时整个系统的熵仍然不足。
此 API 使用 libuv 的线程池,这可能会对某些应用程序产生令人惊讶的负面性能影响;有关更多信息,请参阅 UV_THREADPOOL_SIZE 文档。
crypto.randomBytes() 的异步版本通过单个线程池请求执行。为了尽量减少线程池任务长度的变化,在处理客户端请求时,请将大型 randomBytes 请求拆分。
crypto.randomFill
History
向 callback 参数传递无效的回调现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK。
buffer 参数可以是任何 TypedArray 或 DataView。
crypto.randomFill(buffer, offset?, size?, callback): void
ArrayBuffer | Buffer | TypedArray | DataViewbuffer
大小不得大于
2**31 - 1
。numberTypedArray
,单位为元素,对于
ArrayBuffer
或
DataView
,单位为字节。
默认值:
0numberoffset
相同。
**默认值:**对于
TypedArray
,为
buffer.length - offset
;对于
ArrayBuffer
或
DataView
,为
buffer.byteLength - offset
。
size
不得大于
2**31 - 1
。Functionfunction(err, buf) {}
。此函数类似于 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')); }); // 上面等同于以下: 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')); }); // 上面等同于以下: randomFill(buf, 5, 5, (err, buf) => { if (err) throw err; console.log(buf.toString('hex')); });
任何 ArrayBuffer、TypedArray 或 DataView 实例都可以作为 buffer 传递。
虽然这包括 Float32Array 和 Float64Array 实例,但此函数不应用于生成随机浮点数。结果可能包含 +Infinity、-Infinity 和 NaN,即使数组仅包含有限数字,它们也不是从均匀随机分布中提取的,并且没有有意义的下限或上限。
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
History
buffer 参数可以是任何 TypedArray 或 DataView。
crypto.randomFillSync(buffer, offset?, size?): void
ArrayBuffer | Buffer | TypedArray | DataViewbuffer
大小不得大于
2**31 - 1
。numberTypedArray
,单位为元素;对于
ArrayBuffer
或
DataView
,单位为字节。
默认值:
0numberoffset
相同。
**默认值:**对于
TypedArray
,为
buffer.length - offset
;对于
ArrayBuffer
或
DataView
,为
buffer.byteLength - offset
。
size
不得大于
2**31 - 1
。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')); // 上面等同于以下: 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')); // 上面等同于以下: randomFillSync(buf, 5, 5); console.log(buf.toString('hex'));
任何 ArrayBuffer、TypedArray 或 DataView 实例都可以作为 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
History
向 callback 参数传递无效的回调现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK。
crypto.randomInt(min?, max, callback?): void
返回一个随机整数 n,使得 min <= n < max。此实现避免了 模偏差。
范围 (max - min) 必须小于 248。min 和 max 必须是 安全整数。
如果未提供 callback 函数,则随机整数会同步生成。
// 异步 const { randomInt, } = await import('node:crypto'); randomInt(3, (err, n) => { if (err) throw err; console.log(`从 (0, 1, 2) 中选择的随机数:${n}`); });
// 异步 const { randomInt, } = require('node:crypto'); randomInt(3, (err, n) => { if (err) throw err; console.log(`从 (0, 1, 2) 中选择的随机数:${n}`); });
// 同步 const { randomInt, } = await import('node:crypto'); const n = randomInt(3); console.log(`从 (0, 1, 2) 中选择的随机数:${n}`);
// 同步 const { randomInt, } = require('node:crypto'); const n = randomInt(3); console.log(`从 (0, 1, 2) 中选择的随机数:${n}`);
// 带 `min` 参数 const { randomInt, } = await import('node:crypto'); const n = randomInt(1, 7); console.log(`掷出的骰子点数:${n}`);
// 带 `min` 参数 const { randomInt, } = require('node:crypto'); const n = randomInt(1, 7); console.log(`掷出的骰子点数:${n}`);
crypto.randomUUID(): void
生成一个随机 RFC 4122 版本 4 UUID。UUID 使用加密伪随机数生成器生成。
crypto.randomUUID(): void
生成一个随机的 RFC 9562 版本 7 UUID。该 UUID 在最高 48 位包含一个以毫秒为精度的 Unix 时间戳,随后在其余字段中包含加密安全的随机比特,因此适合作为带有基于时间排序能力的数据库键。嵌入的时间戳依赖于非单调时钟,并不保证严格递增。
crypto.scrypt(password, salt, keylen, options, callback): void
string | ArrayBuffer | Buffer | TypedArray | DataViewstring | ArrayBuffer | Buffer | TypedArray | DataViewnumberObject提供异步 scrypt 实现。Scrypt 是一种基于密码的密钥派生函数,旨在在计算和内存方面都很昂贵,从而使暴力破解攻击无利可图。
salt 应尽可能唯一。建议 salt 是随机的且至少 16 字节长。详见 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑 [将字符串用作加密 API 输入时的注意事项][]。
callback 函数使用两个参数调用:err 和 derivedKey。err 是密钥派生失败时的异常对象,否则 err 为 null。derivedKey 作为 [callback][] 传递给回调。
当任何输入参数指定无效的值或类型时,将抛出异常。
const { scrypt, } = await import('node:crypto'); // 使用工厂默认值。 scrypt('password', 'salt', 64, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...08d59ae' }); // 使用自定义 N 参数。必须是 2 的幂。 scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...aa39b34' });
const { scrypt, } = require('node:crypto'); // 使用工厂默认值。 scrypt('password', 'salt', 64, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...08d59ae' }); // 使用自定义 N 参数。必须是 2 的幂。 scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...aa39b34' });
crypto.scryptSync
History
maxmem 值现在可以是任何安全整数。
添加了 cost、blockSize 和 parallelization 选项名称。
crypto.scryptSync(password, salt, keylen, options?): void
- password
string | Buffer | TypedArray | DataView - salt
string | Buffer | TypedArray | DataView - keylen
number - options
Object - 返回:
Buffer
提供同步 scrypt 实现。Scrypt 是一种基于密码的密钥派生函数,旨在在计算和内存方面都很昂贵,从而使暴力破解攻击无利可图。
salt 应尽可能唯一。建议 salt 是随机的且至少 16 字节长。详见 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑 [将字符串用作加密 API 输入时的注意事项][]。
当密钥派生失败时抛出异常,否则派生密钥作为 [Buffer][] 返回。
当任何输入参数指定无效的值或类型时,将抛出异常。
const { scryptSync, } = await import('node:crypto'); // 使用工厂默认值。 const key1 = scryptSync('password', 'salt', 64); console.log(key1.toString('hex')); // '3745e48...08d59ae' // 使用自定义 N 参数。必须是 2 的幂。 const key2 = scryptSync('password', 'salt', 64, { N: 1024 }); console.log(key2.toString('hex')); // '3745e48...aa39b34'
const { scryptSync, } = require('node:crypto'); // 使用工厂默认值。 const key1 = scryptSync('password', 'salt', 64); console.log(key1.toString('hex')); // '3745e48...08d59ae' // 使用自定义 N 参数。必须是 2 的幂。 const key2 = scryptSync('password', 'salt', 64, { N: 1024 }); console.log(key2.toString('hex')); // '3745e48...aa39b34'
安全堆统计信息
History
- 返回:
ObjectAttributes
setEngine
History
稳定性:0 - 已弃用
stringcrypto.constantscrypto.constants.ENGINE_METHOD_ALL加载并为部分或全部 OpenSSL 函数设置 engine(由标志选择)。
由于自 OpenSSL 3 起已弃用自定义引擎支持,因此此 API 也已弃用。
engine 可以是 ID 或引擎共享库的路径。
可选的 flags 参数默认使用 ENGINE_METHOD_ALL。flags 是一个位字段,采用以下标志之一或组合(定义在 crypto.constants 中):
crypto.constants.ENGINE_METHOD_RSAcrypto.constants.ENGINE_METHOD_DSAcrypto.constants.ENGINE_METHOD_DHcrypto.constants.ENGINE_METHOD_RANDcrypto.constants.ENGINE_METHOD_ECcrypto.constants.ENGINE_METHOD_CIPHERScrypto.constants.ENGINE_METHOD_DIGESTScrypto.constants.ENGINE_METHOD_PKEY_METHScrypto.constants.ENGINE_METHOD_PKEY_ASN1_METHScrypto.constants.ENGINE_METHOD_ALLcrypto.constants.ENGINE_METHOD_NONE
enableFips
History
booleantrue
启用 FIPS 模式,
false
禁用 FIPS 模式。更改 FIPS 模式。对于 OpenSSL 3,这只会在默认属性查询中添加或移除
fips=yes。它不会安装、加载、初始化或验证 FIPS 提供程序。要获得可用的 FIPS
配置,请安装该提供程序,并按照 FIPS
模式 中的说明配置 OpenSSL,使其在 Node.js 启动时加载该提供程序。
如果没有已加载的提供程序提供与 fips=yes 匹配的请求加密实现,则调用仍可能成功,
且 crypto.getFips() 仍可能返回 1,但获取该实现会失败。受影响的 node:crypto
操作通常会失败,并返回 ERR_OSSL_EVP_UNSUPPORTED。不需要重新获取实现的操作,
包括使用先前已获取的实现或已初始化操作上下文的操作,仍可能成功。请在应用初始化
期间调用此方法,并在应用代码使用其他基于 OpenSSL 的 API 之前调用。
此方法只会影响后续的算法获取。Node.js 会在应用代码运行前初始化部分 OpenSSL 状态。
当属性查询必须从进程启动时就处于活动状态时,请在 OpenSSL 配置中设置
default_properties = fips=yes,或使用 --enable-fips 或
--force-fips。此外,命令行标志还要求配置名为 fips 的提供程序,以便对其
进行初始化并通过其自检;否则 Node.js 将无法启动。
如果 OpenSSL 无法更改状态,则抛出错误。当 Node.js 使用 --force-fips 启动时,
无法禁用 FIPS 模式。对于 OpenSSL 1.1.1,启用 FIPS 模式要求使用支持 FIPS 的
OpenSSL 构建版本。
签名
History
不再支持将 CryptoKey 作为 key 传入。
添加对 Ed25519 上下文参数的支持。
添加对 ML-DSA、Ed448 和 SLH-DSA 上下文参数的支持。
添加对 SLH-DSA 签名的支持。
添加对 ML-DSA 签名的支持。
向 callback 参数传递无效的回调现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK。
添加了可选的 callback 参数。
此函数现在支持 IEEE-P1363 DSA 和 ECDSA 签名。
ArrayBuffer | Buffer | SharedArrayBuffer | TypedArray | DataView | stringObject | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObject | URL使用给定的私钥和算法计算并返回 data 的签名。如果 algorithm 是 null 或 undefined,则算法取决于密钥类型。
对于 Ed25519、Ed448 和 ML-DSA,algorithm 必须是 null 或 undefined。
crypto.getHashes() 列出了哈希 API 可用的算法,但密钥类型和签名方案决定了列出的摘要算法是否可用于签名。
如果 key 不是 KeyObject,此函数的行为就像将 key 传递给了 crypto.createPrivateKey()。当 key 是字符串、ArrayBuffer、Buffer、TypedArray 或 DataView 时,它必须包含 PEM 编码的密钥材料。如果它是一个对象,则可以传入以下其他属性:
string(r, s)
。r || s
。integerintegerRSA_PKCS1_PSS_PADDING
时的盐长度。特殊值
crypto.constants.RSA_PSS_SALTLEN_DIGEST
将盐长度设置为摘要大小,
crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN
(默认)将其设置为最大允许值。ArrayBuffer | Buffer | TypedArray | DataView如果提供了 callback 函数,此函数使用 libuv 的线程池。
subtle
History
- 类型:
SubtleCrypto
crypto.webcrypto.subtle 的便捷别名。
timingSafeEqual
History
a 和 b 参数也可以是 ArrayBuffer。
此函数使用恒定时间算法比较给定
ArrayBuffer、TypedArray 或 DataView 实例所表示的底层字节。
此函数不会泄露可被攻击者用来猜测其中一个值的时间信息。这适用于 比较 HMAC 摘要或秘密值,例如身份验证 cookie 或 能力 URL。
a 和 b 必须都是 Buffer、TypedArray 或 DataView,并且它们
必须具有相同的字节长度。如果 a 和 b 具有
不同的字节长度,则会抛出错误。
如果 a 和 b 中至少有一个是每个条目超过一个字节的 TypedArray,
例如 Uint16Array,则结果将使用平台
字节序计算。
当两个输入都是 Float32Array 或
Float64Array 时,由于浮点数的 IEEE 754
编码,此函数可能会返回意外的结果。特别是,x === y 和
Object.is(x, y) 都不意味着两个浮点数
x 和 y 的字节表示相等。
使用 crypto.timingSafeEqual 并不能保证_周围_的代码
是时间安全的。应注意确保周围代码不会
引入时间漏洞。
crypto.verify
History
传递 CryptoKey 作为 key 已不再支持。
添加对 Ed25519 上下文参数的支持。
添加对 ML-DSA、Ed448 和 SLH-DSA 上下文参数的支持。
添加对 SLH-DSA 签名验证的支持。
添加对 ML-DSA 签名验证的支持。
向 callback 参数传递无效的回调现在会抛出 ERR_INVALID_ARG_TYPE 而不是ERR_INVALID_CALLBACK。
添加了可选的 callback 参数。
data、key 和 signature 参数也可以是 ArrayBuffer。
此函数现在支持 IEEE-P1363 DSA 和 ECDSA 签名。
crypto.verify(algorithm, data, key, signature, callback?): void
ArrayBuffer | Buffer | SharedArrayBuffer | TypedArray | DataView | stringObject | string | ArrayBuffer | Buffer | TypedArray | DataView | KeyObjectArrayBuffer | Buffer | SharedArrayBuffer | TypedArray | DataView使用给定的密钥和算法验证 data 的给定签名。如果
algorithm 是 null 或 undefined,则算法取决于
密钥类型。
对于 Ed25519、Ed448 和
ML-DSA,algorithm 必须为 null 或 undefined。
crypto.getHashes() 列出了哈希 API 可用的算法,但密钥类型和签名方案决定了列出的摘要算法是否可用于验证。
If key 不是 KeyObject,此函数的行为就像将 key 传递给了 crypto.createPublicKey()。当 key 是字符串、ArrayBuffer、Buffer、TypedArray 或 DataView 时,它必须包含 PEM 编码的密钥材料。如果它是一个对象,则可以传递以下附加属性:
string(r, s)
。r || s
。integerintegerRSA_PKCS1_PSS_PADDING
时的盐长度。特殊值
crypto.constants.RSA_PSS_SALTLEN_DIGEST
将盐长度设置为摘要
大小,
crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN
(默认)将其设置为
最大允许值。ArrayBuffer | Buffer | TypedArray | DataViewsignature 参数是之前为 data 计算出的签名。
因为公钥可以从私钥派生,所以可以将私钥或公钥传递给 key。
如果提供了 callback 函数,此函数使用 libuv 的线程池。
类型:Crypto Web Crypto API 标准的实现。
详见 [Web Crypto API 文档][]。
Node.js 公开了所链接的 OpenSSL 库提供的 FIPS 支持。Node.js 本身并未通过 FIPS 验证。验证针对特定的 OpenSSL 模块或提供程序,并且仅在按照其安全策略部署时适用。供应商提供的 Node.js 或 OpenSSL 构建可能需要不同的配置;对于这些构建,请遵循供应商的文档。
使用 OpenSSL 1.1.1 时,Node.js 必须针对支持 FIPS 的 OpenSSL 库构建。
使用 OpenSSL 3 时,FIPS 支持采用 OpenSSL FIPS 模块指南 中描述的提供程序模型。使用经 FIPS 批准的实现需要:
-
正确安装的 OpenSSL 3 FIPS 提供程序。
-
OpenSSL 3 FIPS 模块配置文件。
-
将 FIPS 提供程序加载到 Node.js 使用的 OpenSSL 库上下文中,通常是在 Node.js 启动时通过 OpenSSL 配置文件激活该提供程序。
-
在获取加密实现时,使默认属性查询包含
fips=yes。可以通过 OpenSSL 配置、--enable-fips或--force-fips在进程启动时设置,也可以通过crypto.setFips(true)为后续获取操作设置。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()。
Crypto 模块在 Node.js 尚未有统一流 API 概念、也尚未有用于处理二进制数据的 Buffer 对象之前就已加入。因此,许多 crypto 类具有其他实现 [streams][stream] API 的 Node.js 类通常没有的方法(例如 update()、final() 或 digest())。此外,许多方法默认接受并返回 'latin1' 编码的字符串,而不是 Buffer。此默认设置在 Node.js 0.9.3 中更改为默认使用 Buffer 对象。
node:crypto 模块仍支持一些已经遭破解且不建议使用的算法。该 API 也允许使用密钥长度较短、无法安全使用的密码和哈希算法。
用户应全权负责根据自身安全要求选择加密算法和密钥长度。
根据 NIST SP 800-131A 的建议:
- 在需要抗碰撞性的场景(例如数字签名)中,MD5 和 SHA-1 已不再适用。
- 建议 RSA、DSA 和 DH 算法使用的密钥至少为 2048 位,ECDSA 和 ECDH 使用的曲线至少为 224 位,以确保未来数年内可安全使用。
modp1、modp2和modp5DH 组的密钥长度小于 2048 位,不建议使用。
其他建议和详细信息请参阅参考资料。
一些已知存在弱点、且在实践中意义不大的算法仅可通过 [legacy provider][] 使用,该提供程序默认未启用。
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);
对于 CBC 密文窃取(CBC-CTS)密码,crypto.createCipheriv() 或 crypto.createDecipheriv() 的 ctsMode 选项用于选择变体:
'CS1'是默认值。对于块对齐的输入,其输出与 CBC 模式相同。'CS2'对于块对齐的输入也与 CBC 相同。对于末尾含有部分数据块的输入,它会相对于 CS1 交换末尾完整密文块和部分密文块的位置。'CS3'是 Kerberos 5 变体。对于末尾含有部分数据块的输入,它使用 CS2 的顺序;对于块对齐的输入,它也会交换末尾两个密文块。
加密和解密必须使用相同的变体。此选项仅适用于 OpenSSL 3.0 或更高版本中的 CBC-CTS 提供程序密码。
使用此模式的应用程序必须遵守以下限制:
- 明文或密文至少必须有一个数据块长。
- 密文长度与明文长度相同。
- 必须只调用一次
cipher.update()或decipher.update(),并传入所有输入数据。write(data)、end(data)或pipe()等流方法可能会失败,因为 CBC-CTS 不接受多次数据更新。 - 仍必须调用
cipher.final()或decipher.final()来完成操作。 crypto.getCipherInfo()会将基本模式报告为'cbc'。
XTS 密码对可独立调整的数据单元进行操作。一个 Cipheriv 或 Decipheriv 实例表示一个完整的数据单元,其 iv 参数提供 16 字节的 tweak。对于每个不同的逻辑数据单元,请使用具有相应位置 tweak 的新实例。
使用 XTS 模式的应用程序必须遵守以下限制:
- 明文或密文至少必须有一个 16 字节的数据块。其长度不必是 16 的倍数,因为 XTS 会对末尾的部分数据块使用密文窃取。
- 密文长度与明文长度相同。
- 必须只调用一次
cipher.update()或decipher.update(),并传入所有输入数据。write(data)、end(data)或pipe()等流方法可能会失败,因为 XTS 不接受多次数据更新。 - 仍必须调用
cipher.final()或decipher.final()来完成操作。
对于 sm4-xts,crypto.createCipheriv() 或 crypto.createDecipheriv() 的 xtsStandard 选项用于选择 GB/T 17964-2021 中的默认 'GB' 变体或 IEEE Std 1619-2007 中的 'IEEE' 变体。加密和解密必须使用相同的变体。此选项仅适用于 sm4-xts;不适用于 AES-XTS 密码。OpenSSL 的默认提供程序在 OpenSSL 3.2 或更高版本中支持 sm4-xts。
AES 密钥封装(AES-WRAP)和带填充的 AES 密钥封装(AES-WRAP-PAD)密码针对完整的密钥数据值进行操作,而不是针对增量字节流进行操作。逆变换变体具有相同的处理限制。
使用 AES 密钥封装密码的应用程序必须遵守以下限制:
- 必须只调用一次
cipher.update()或decipher.update(),并传入完整的非空输入值。 - 不要将 AES 密钥封装密码用作通用的
stream.Transform流。write(data)、end(data)和pipe()等方法可能会将一个值拆分为多次更新,而每次更新都会被视为单独的封装或解封装操作。 - 仍必须调用
cipher.final()或decipher.final()来完成操作。
如果 OpenSSL 支持,SIV2 和 GCM-SIV3 是受支持的 [AEAD 算法][]。使用这些模式的应用程序必须在使用密码 API 时遵守某些限制:
- 认证标签长度固定为 16 字节。
AES-SIV密钥长度是所指定 AES 密钥长度的两倍:aes-128-siv需要 32 字节密钥,aes-192-siv需要 48 字节密钥,aes-256-siv需要 64 字节密钥。AES-SIV密码不使用初始化向量。向crypto.createCipheriv()或crypto.createDecipheriv()传递null或长度为零的iv。- 只有在 OpenSSL 3.5 或更高版本中,
AES-SIV和AES-GCM-SIV密码才支持零长度明文。 AES-SIV没有单独的 nonce 或 IV 参数。RFC 5297 定义的AES-SIV以有序的关联数据输入列表为基础。每次调用setAAD()都会向该列表提供一个输入。如果某个协议在使用AES-SIV时使用 nonce,请在其他关联数据输入之后、update()之前调用setAAD(nonce)。最多可提供 126 个关联数据输入。AES-GCM-SIV密码需要 12 字节的初始化向量。- 解密时,必须在调用
update()之前通过setAuthTag()设置认证标签。 - 使用
write(data)、end(data)或pipe()等流方法可能会失败,因为这些模式的每个实例无法处理多个数据块。 - 由于这些模式会一次性处理整条消息,因此必须且只能调用一次
update()。 - 尽管调用
update()已足以加密或解密消息,但应用程序仍必须调用final()来计算或验证认证标签。
Node.js 公开了所链接的 OpenSSL 库提供的 FIPS 支持。Node.js 本身并未通过 FIPS 验证。验证针对特定的 OpenSSL 模块或提供程序,并且仅在按照其安全策略部署时适用。供应商提供的 Node.js 或 OpenSSL 构建可能需要不同的配置;对于这些构建,请遵循供应商的文档。
使用 OpenSSL 1.1.1 时,Node.js 必须针对支持 FIPS 的 OpenSSL 库构建。
使用 OpenSSL 3 时,FIPS 支持采用 OpenSSL FIPS 模块指南 中描述的提供程序模型。使用经 FIPS 批准的实现需要:
- 正确安装的 OpenSSL 3 FIPS 提供程序。
- OpenSSL 3 FIPS 模块配置文件。
- 将 FIPS 提供程序加载到 Node.js 使用的 OpenSSL 库上下文中,通常是在 Node.js 启动时通过 OpenSSL 配置文件激活该提供程序。
- 在获取加密实现时,使默认属性查询包含
fips=yes。可以通过 OpenSSL 配置、--enable-fips或--force-fips在进程启动时设置,也可以通过crypto.setFips(true)为后续获取操作设置。
OpenSSL 3 配置文件示例如下:
nodejs_conf = nodejs_init config_diagnostics = 1 .include /<absolute path>/fipsmodule.cnf [nodejs_init] providers = provider_sect alg_section = algorithm_sect [provider_sect] # FIPS 节的名称应与所包含的 fipsmodule.cnf 内的节名称匹配。 fips = fips_sect base = base_sect [base_sect] activate = 1 [algorithm_sect] default_properties = fips=yes
fipsmodule.cnf 文件是在安装 FIPS 提供程序时生成的,其中包含模块完整性和自检信息。具体命令和参数因安装方式而异;请参阅 OpenSSL FIPS 配置 和 OpenSSL FIPS 模块指南。安装过程使用 openssl fipsinstall。
该示例会在 Node.js 启动时激活提供程序并启用 fips=yes 属性查询。若要在启动时激活提供程序,但稍后通过 crypto.setFips(true) 启用属性查询,请省略 alg_section = algorithm_sect 和 [algorithm_sect] 代码块。提供程序仍然必须被加载;使用此启动配置时,请保持其激活状态。应在应用程序代码使用其他基于 OpenSSL 的 API 之前调用 crypto.setFips(true)。它不等同于在进程启动时启用属性查询,因为 Node.js 会在运行应用程序代码之前初始化一些 OpenSSL 状态。当属性查询必须从进程启动时就处于活动状态时,请使用此处所示的示例、--enable-fips 或 --force-fips。
config_diagnostics 会使配置错误阻止启动,而不是被忽略。base 提供程序提供非加密的支持算法,例如编码器和解码器,这些算法通常需要与 FIPS 提供程序配合使用。default_properties = fips=yes 会将 OpenSSL 的默认算法选择限制为符合 fips=yes 的实现。
将 OPENSSL_CONF 设置为 OpenSSL 配置文件。对于动态加载的提供程序,可以使用 OPENSSL_MODULES 设置包含提供程序模块的目录。例如:
export OPENSSL_CONF=/<path to configuration file>/nodejs.cnf export OPENSSL_MODULES=/<path to openssl lib>/ossl-modules
--openssl-config 命令行选项用于选择配置文件,其优先级高于 OPENSSL_CONF。如果两者均未设置,则使用 OpenSSL 的默认配置文件。
默认情况下,Node.js 会读取 nodejs_conf 节,而不是 OpenSSL 通常使用的 openssl_conf 节。使用 --openssl-shared-config 可读取 openssl_conf,或者使用 ./configure --openssl-conf-name=<name> 构建 Node.js,以更改默认节名称。
在 OpenSSL 3 上,上述配置会在启动时启用 fips=yes 属性查询。还可以使用以下控制项:
--enable-fips和--force-fips会启用属性查询,并额外要求配置的、名为fips的提供程序完成初始化并通过自检。如果检查失败,Node.js 将退出。--force-fips还会阻止通过脚本代码禁用 FIPS 模式。使用--force-fips=strict时,Node.js 还会拒绝通过 OpenSSL FIPS 指示器回调报告的非批准操作。crypto.setFips()会更改 FIPS/属性查询状态。在 OpenSSL 3 上,它不会安装、加载、初始化或验证提供程序。调用之前获取的实现不会发生变化。crypto.getFips()会报告 FIPS/属性查询状态。在 OpenSSL 3 上,返回值为1并不能证明 FIPS 提供程序已加载或已通过验证。- 使用
--enable-fips-indicator-events时,'crypto.fips.indicator'诊断通道会报告由配置为向后兼容的 OpenSSL 3.4 或更高版本 FIPS 提供程序允许的非批准操作。
使用 OpenSSL 1.1.1 时,这些控制项使用库提供的 FIPS 模式支持,并且要求使用支持 FIPS 的 OpenSSL 构建。
只能使用当前 FIPS 设置下可用的算法。在 OpenSSL 3 上,如果没有已加载的提供程序提供符合 fips=yes 的所请求加密实现,则获取该实现会失败,通常会产生 ERR_OSSL_EVP_UNSUPPORTED。对于 Node.js 支持、但在禁用 FIPS 模式时才可用且在当前 FIPS 设置下不可用的算法,也可能出现相同的错误。
OpenSSL 文档说明,同一个 FIPS 提供程序不能被一个进程中的多个 libcrypto 副本使用。这可能会影响加载另一个 libcrypto 副本的原生插件;OpenSSL 文档给出的解决方法是为每个 libcrypto 实例使用一个独立的提供程序副本。请参阅 OpenSSL FIPS 提供程序限制。
以下由 crypto.constants 导出的常量适用于 node:crypto、node:tls 和 node:https 模块的各种用途,通常特定于 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 草案的 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 禁用版本回滚攻击检测。 |
| 常量 | 描述 |
|---|---|
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 |
| 常量 | 描述 |
|---|---|
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 |
| 常量 | 描述 |
|---|---|
defaultCoreCipherList |
指定 Node.js 使用的内置默认密码列表。 |
defaultCipherList |
指定当前 Node.js 进程使用的活动默认密码列表。 |