加密
History
稳定性:2 - 稳定
node:crypto 模块提供加密功能,包括一组 OpenSSL 的哈希、HMAC、加密、解密、签名和验证函数的包装器。
const { createHmac } = await import('node:crypto'); const secret = 'abcdefg'; const hash = createHmac('sha256', secret) .update('I love cupcakes') .digest('hex'); console.log(hash); // 输出: // 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 对象。
示例:将 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和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 和 chacha20-poly1305),
cipher.setAAD() 方法设置用于_附加认证数据_ (AAD) 输入参数的值。
plaintextLength 选项对于 GCM 和 OCB 是可选的。当使用 CCM 时,
必须指定 plaintextLength 选项,并且其值必须与明文长度(字节)匹配。参见 CCM 模式。
必须在 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.final() 之后调用 cipher.update() 将导致抛出错误。
类:Decipheriv
History
Decipheriv 类的实例用于解密数据。该类可以通过以下两种方式使用:
- 作为一个既可读又可写的 流,将纯加密数据写入以在可读侧产生未加密数据,或
- 使用
decipher.update()和decipher.final()方法来产生未加密数据。
crypto.createDecipheriv() 方法用于创建 Decipheriv 实例。不应直接使用 new 关键字创建 Decipheriv 对象。
示例:将 Decipheriv 对象用作流:
import { Buffer } from 'node:buffer'; const { scryptSync, createDecipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = '用于生成密钥的密码'; // 密钥长度取决于算法。在这种情况下,对于 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 和 chacha20-poly1305)时,decipher.setAAD() 方法设置用于 额外认证数据 (AAD) 输入参数的值。
对于 GCM,options 参数是可选的。当使用 CCM 时,必须指定 plaintextLength 选项,并且其值必须与密文的字节长度匹配。参见 CCM 模式。
必须在 decipher.update() 之前调用 decipher.setAAD() 方法。
当传递字符串作为 buffer 时,请考虑 [将字符串用作加密 API 输入时的注意事项][]。
decipher.setAuthTag(buffer, encoding?): void
当使用认证加密模式(目前支持 GCM、CCM、OCB 和 chacha20-poly1305)时,decipher.setAuthTag() 方法用于传入接收到的 认证标签。如果未提供标签,或者密文已被篡改,decipher.final() 将抛出错误,表明由于认证失败应丢弃密文。如果标签长度根据 NIST SP 800-38D 无效,或者与 authTagLength 选项的值不匹配,decipher.setAuthTag() 将抛出错误。
对于 CCM 模式,必须在 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?): Buffer | string
Updates the decipher with data. If the inputEncoding argument is given, the data argument is a string using the specified encoding. If the inputEncoding argument is not given, data must be a Buffer. If data is a Buffer, inputEncoding is ignored.
outputEncoding specifies the output format of the deciphered data. If outputEncoding is specified, a string using the specified encoding is returned. If outputEncoding is not provided, a Buffer is returned.
When specifying outputEncoding, the same encoding must be used as in previous calls to decipher.update().
The decipher.update() method can be called multiple times with new data until decipher.final() is called. Calling decipher.update() after decipher.final() will cause an error to be thrown.
Even if the underlying cipher implements authentication, the authenticity and integrity of the plaintext returned from this function may be uncertain at this time. For authenticated encryption algorithms, authenticity is generally established only when the application calls 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
Object创建一个新的 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'。
类:Sign
History
- 继承自:
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' 选项为 undefined 或设置为 'default',则仅当主题备用名称扩展不存在或不包含任何电子邮件地址时,才考虑证书主题。
如果 'subject' 选项设置为 'always',并且如果主题备用名称扩展不存在或不包含匹配的电子邮件地址,则考虑证书主题。
如果 'subject' 选项设置为 'never',则从不考虑证书主题,即使证书不包含主题备用名称。
检查主机名是否匹配
History
subject 选项现在默认为 'default'。
subject 选项现在可以设置为 'default'。
检查证书是否与给定的主机名匹配。
如果证书与给定的主机名匹配,则返回匹配的主题名称。返回的名称可能是完全匹配(例如,foo.example.com),也可能包含通配符(例如,*.example.com)。因为主机名比较不区分大小写,所以返回的主题名称在大写上也可能与给定的 name 不同。
如果 'subject' 选项为 undefined 或设置为 'default',则仅当主题备用名称扩展不存在或不包含任何 DNS 名称时,才考虑证书主题。此行为与 RFC 2818("HTTP Over TLS")一致。
如果 '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 传递。
传递 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 | nullObject创建并返回一个 Cipheriv 对象,带有给定的 algorithm、key 和初始化向量 (iv)。
options 参数控制流行为,除了使用 CCM 或 OCB 模式(例如 'aes-128-ccm')的密码外,它是可选的。在这种情况下,authTagLength 选项是必需的,并指定认证标签的长度(以字节为单位),参见 CCM 模式。在 GCM 模式下,authTagLength 选项不是必需的,但可用于设置 getAuthTag() 返回的认证标签的长度,默认为 16 字节。对于 chacha20-poly1305,authTagLength 选项默认为 16 字节。
algorithm 依赖于 OpenSSL,示例有 'aes192' 等。在最近的 OpenSSL 版本上,openssl list -cipher-algorithms 将显示可用的密码算法。
key 是 algorithm 使用的原始密钥,iv 是 初始化向量。两个参数必须是 'utf8' 编码的字符串、缓冲区、TypedArray 或 DataView。key 也可以是类型为 secret 的 KeyObject。如果密码不需要初始化向量,iv 可以是 null。
当为 key 或 iv 传递字符串时,请考虑 使用字符串作为加密 API 输入时的注意事项。
初始化向量应该是不可预测且唯一的;理想情况下,它们应该是加密随机的。它们不必是秘密的:IV 通常只是未加密地添加到密文消息中。听起来可能矛盾的是,某物必须不可预测且唯一,但不必是秘密的;请记住,攻击者必须无法提前预测给定 IV 将是什么。
crypto.createDecipheriv
History
不再支持将 CryptoKey 作为 key 传递。
传递 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 | nullObject创建并返回一个 Decipheriv 对象,使用给定的 algorithm、key 和初始化向量 (iv)。
options 参数控制流行为,除了使用 CCM 或 OCB 模式(例如 'aes-128-ccm')的密码外,它是可选的。在这种情况下,authTagLength 选项是必需的,并指定认证标签的长度(以字节为单位),参见 CCM 模式。对于 AES-GCM 和 chacha20-poly1305,authTagLength 选项默认为 16 字节,如果使用不同长度则必须设置为不同的值。
algorithm 依赖于 OpenSSL,示例有 'aes192' 等。在最近的 OpenSSL 版本上,openssl list -cipher-algorithms 将显示可用的密码算法。
key 是 algorithm 使用的原始密钥,iv 是 初始化向量。两个参数必须是 'utf8' 编码的字符串、缓冲区、TypedArray 或 DataView。key 也可以是类型为 secret 的 KeyObject。如果密码不需要初始化向量,iv 可以是 null。
当为 key 或 iv 传递字符串时,请考虑 使用字符串作为加密 API 输入时的注意事项。
初始化向量应该是不可预测且唯一的;理想情况下,它们应该是加密随机的。它们不必是秘密的: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
XOF 哈希函数若没有默认输出长度,则现在需要 outputLength 选项。
为 XOF 哈希函数添加了 outputLength 选项。
crypto.createHash(algorithm, options?): void
创建并返回一个 Hash 对象,可用于使用给定的 algorithm 生成哈希摘要。可选的 options 参数控制流行为。对于诸如 'shake256' 之类的 XOF 哈希函数,outputLength 选项指定所需的输出长度(以字节为单位)。对于没有默认输出长度的 XOF 哈希函数,这是必需的。
当数据较小(< 5MB)且可直接获取时,通常 crypto.hash() 的速度更快。
algorithm 取决于平台上 OpenSSL 版本所支持的可用算法。示例包括 'sha256'、'sha512' 等。在较新版本的 OpenSSL 中,openssl list -digest-algorithms 将显示可用的摘要算法。
示例:生成文件的 sha256 总和
import { createReadStream, } from 'node:fs'; import { argv } from 'node:process'; const { createHash, } = await import('node:crypto'); const filename = argv[2]; const hash = createHash('sha256'); const input = createReadStream(filename); input.on('readable', () => { // 哈希流只会产生一个元素。 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 参数控制流行为。
algorithm 取决于平台上 OpenSSL 版本支持的可用算法。示例有 'sha256'、'sha512' 等。在最近的 OpenSSL 版本上,openssl list -digest-algorithms 将显示可用的摘要算法。
key 是用于生成加密 HMAC 哈希的 HMAC 密钥。如果它是 KeyObject,其类型必须是 secret。如果它是字符串,请考虑 使用字符串作为加密 API 输入时的注意事项。如果它是从加密安全的熵源获得的,例如 crypto.randomBytes() 或 crypto.generateKey(),其长度不应超过 algorithm 的块大小(例如,SHA-256 为 512 位)。
示例:生成文件的 sha256 HMAC
import { createReadStream, } from 'node:fs'; import { argv } from 'node:process'; const { createHmac, } = await import('node:crypto'); const filename = argv[2]; const hmac = createHmac('sha256', 'a secret'); const input = createReadStream(filename); input.on('readable', () => { // 哈希流只会产生一个元素。 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.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
创建并返回一个 Verify 对象,使用给定的摘要算法。使用 [crypto.getHashes][] 获取可用摘要算法的名称。可选的回调参数控制异步行为。
在某些情况下,可以使用签名算法的名称(如 RSA-SHA256)而不是摘要算法来创建 Verify 实例。这将使用相应的摘要算法。这不适用于所有签名算法,例如 RSA-SHA1,因此最好始终使用摘要算法名称。
crypto.createVerify(algorithm)
History
创建并返回一个 Verify 对象,使用给定的算法。使用 [crypto.getHashes][] 获取可用签名算法名称的数组。可选的回调参数控制异步行为。
在某些情况下,可以使用签名算法的名称(如 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 的新非对称密钥对。参见支持的 非对称密钥类型。
如果指定了 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 的新非对称密钥对。参见支持的 非对称密钥类型。
如果指定了 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'。哈希算法也称为“摘要”算法。
const { getHashes, } = await import('node:crypto'); console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]
const { getHashes, } = require('node:crypto'); console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]
crypto.getRandomValues(typedArray): void
Buffer | TypedArray | DataView | ArrayBuffercrypto.webcrypto.getRandomValues() 的便捷别名。此实现不符合 Web Crypto 规范,要编写 Web 兼容代码,请改用 crypto.webcrypto.getRandomValues()。
crypto.hash
History
对于没有默认输出长度的 XOF 哈希函数,现在必须提供 outputLength 选项。
此 API 不再处于实验阶段。
为 XOF 哈希函数添加了 outputLength 选项。
crypto.hash(algorithm, data, options?): void
string | Buffer | TypedArray | DataViewdata
是字符串时,它将在被哈希之前编码为 UTF-8。如果希望字符串输入使用不同的输入编码,用户可以使用
TextEncoder
或
Buffer.from()
将字符串编码为
TypedArray
,并将编码后的
TypedArray
传递到此 API 中。用于创建数据一次性哈希摘要的实用工具。当哈希少量现成数据(<= 5MB)时,它可能比基于对象的 crypto.createHash() 更快。如果数据可能很大或是流式的,仍建议使用 crypto.createHash()。
algorithm 取决于平台上 OpenSSL 版本支持的可用算法。例如 'sha256'、'sha512' 等。在最新版本的 OpenSSL 上,openssl list -digest-algorithms 将显示可用的摘要算法。
如果 options 是字符串,则它指定 outputEncoding。
示例:
const crypto = require('node:crypto'); const { Buffer } = require('node:buffer'); // 对字符串进行哈希处理并将结果作为十六进制编码字符串返回。 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 字节的密钥。
提供的 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 字节的密钥。
成功生成的 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'
密钥派生函数 2(PBKDF2)
History
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' });
可以使用 crypto.getHashes() 检索支持的摘要函数数组。
此 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'
可以使用 crypto.getHashes() 检索支持的摘要函数数组。
crypto.privateDecrypt
History
The mgf1Hash option was added.
传入 CryptoKey 作为 privateKey 已不再受支持。
除非 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
is set, MGF1 的哈希函数。
默认值:
'sha1'stringoaepHash
is used.
This allows the OAEP digest and the MGF1 digest to differ.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()。
如果 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
The mgf1Hash option was added.
作为 key 传递 CryptoKey 已不再受支持。
添加了 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
is set, MGF1 的哈希函数。
默认值:
'sha1'stringoaepHash
is used.
This allows the OAEP digest and the MGF1 digest to differ.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()。
如果 key 不是 KeyObject,此函数的行为就好像 key 已传递给 crypto.createPublicKey()。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_OAEP_PADDING。
因为 RSA 公钥可以从私钥派生,所以可以传递私钥而不是公钥。
crypto.randomBytes(size, callback?): Buffer
Generates cryptographically strong pseudorandom data. The size argument is a number indicating the number of bytes to generate.
If a callback function is provided, the bytes are generated asynchronously and the callback function is called with two arguments: err and buf. If an error occurs, err will be an Error object; otherwise it will be null. The buf argument is a Buffer containing the generated bytes.
// 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')}`); });
If the callback function is not provided, the random bytes are generated synchronously and returned as a Buffer. An error will be thrown if there is a problem generating the bytes.
// 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')}`);
The crypto.randomBytes() method will not complete until there is sufficient available entropy. This will normally never take longer than a few milliseconds. The only time generating random bytes may block for a longer period of time is right after startup, when the entire system is still low on entropy.
This API uses libuv's threadpool, which can have surprising and negative performance implications for some applications; see the UV_THREADPOOL_SIZE documentation for more information.
The asynchronous version of crypto.randomBytes() is carried out in a single threadpool request. To minimize threadpool task length variation, partition large randomBytes requests when fulfilling client requests.
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。
如果 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。
如果 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 标准的实现。
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 模式。crypto.setFips()会更改 FIPS/属性查询状态。在 OpenSSL 3 上,它不会安装、加载、初始化或验证提供程序。调用之前获取的实现不会发生变化。crypto.getFips()会报告 FIPS/属性查询状态。在 OpenSSL 3 上,返回值为1并不能证明 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 进程使用的活动默认密码列表。 |