Skip to content

加密

[稳定性: 2 - 稳定]

稳定性: 2 稳定性: 2 - 稳定

源代码: lib/crypto.js

node:crypto 模块提供加密功能,包括 OpenSSL 的哈希、HMAC、密码、解密、签名和验证函数的一组包装器。

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

const secret = 'abcdefg'
const hash = createHmac('sha256', secret).update('I love cupcakes').digest('hex')
console.log(hash)
// 输出:
//   c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e
js
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 导入或调用 require('node:crypto') 将导致抛出错误。

使用 CommonJS 时,可以使用 try/catch 捕获抛出的错误:

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

使用词法 ESM import 关键字时,只有在 尝试加载模块(例如,使用预加载模块)之前注册了 process.on('uncaughtException') 处理程序的情况下,才能捕获该错误。

使用 ESM 时,如果代码可能在未启用加密支持的 Node.js 版本上运行,请考虑使用 import() 函数而不是词法 import 关键字:

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

类: Certificate

新增于: v0.11.8

SPKAC 是一种证书签名请求机制,最初由 Netscape 实现,并作为 HTML5 的 <keygen> 元素的一部分正式指定。

<keygen>HTML 5.2 起已弃用,新项目不应再使用此元素。

node:crypto 模块提供 Certificate 类用于处理 SPKAC 数据。最常见的用法是处理 HTML5 <keygen> 元素生成的输出。Node.js 在内部使用 OpenSSL 的 SPKAC 实现

静态方法: Certificate.exportChallenge(spkac[, encoding])

[历史]

版本变更
v15.0.0spkac 参数可以是 ArrayBuffer。将 spkac 参数的大小限制为最大 2**31 - 1 字节。
v9.0.0新增于: v9.0.0
js
const { Certificate } = await import('node:crypto')
const spkac = getSpkacSomehow()
const challenge = Certificate.exportChallenge(spkac)
console.log(challenge.toString('utf8'))
// 打印:挑战作为 UTF8 字符串
js
const { Certificate } = require('node:crypto')
const spkac = getSpkacSomehow()
const challenge = Certificate.exportChallenge(spkac)
console.log(challenge.toString('utf8'))
// 打印:挑战作为 UTF8 字符串

静态方法: Certificate.exportPublicKey(spkac[, encoding])

[历史]

版本变更
v15.0.0spkac 参数可以是 ArrayBuffer。将 spkac 参数的大小限制为最大 2**31 - 1 字节。
v9.0.0新增于:v9.0.0
js
const { Certificate } = await import('node:crypto')
const spkac = getSpkacSomehow()
const publicKey = Certificate.exportPublicKey(spkac)
console.log(publicKey)
// 输出:公钥作为 <Buffer ...>
js
const { Certificate } = require('node:crypto')
const spkac = getSpkacSomehow()
const publicKey = Certificate.exportPublicKey(spkac)
console.log(publicKey)
// 输出:公钥作为 <Buffer ...>

静态方法:Certificate.verifySpkac(spkac[, encoding])

[历史]

版本变更
v15.0.0spkac 参数可以是 ArrayBuffer。添加了 encoding。将 spkac 参数的大小限制为最大 2**31 - 1 字节。
v9.0.0新增于:v9.0.0
js
import { Buffer } from 'node:buffer'
const { Certificate } = await import('node:crypto')

const spkac = getSpkacSomehow()
console.log(Certificate.verifySpkac(Buffer.from(spkac)))
// 打印:true 或 false
js
const { Buffer } = require('node:buffer')
const { Certificate } = require('node:crypto')

const spkac = getSpkacSomehow()
console.log(Certificate.verifySpkac(Buffer.from(spkac)))
// 打印:true 或 false

遗留 API

[稳定性: 0 - 已弃用]

稳定性: 0 稳定性: 0 - 已弃用

作为遗留接口,可以像以下示例中那样创建 crypto.Certificate 类的新实例。

new crypto.Certificate()

可以使用 new 关键字或将 crypto.Certificate() 作为函数调用来创建 Certificate 类的实例:

js
const { Certificate } = await import('node:crypto')

const cert1 = new Certificate()
const cert2 = Certificate()
js
const { Certificate } = require('node:crypto')

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

certificate.exportChallenge(spkac[, encoding])

添加于: v0.11.8

js
const { Certificate } = await import('node:crypto')
const cert = Certificate()
const spkac = getSpkacSomehow()
const challenge = cert.exportChallenge(spkac)
console.log(challenge.toString('utf8'))
// 打印:挑战作为 UTF8 字符串
js
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])

新增于:v0.11.8

js
const { Certificate } = await import('node:crypto')
const cert = Certificate()
const spkac = getSpkacSomehow()
const publicKey = cert.exportPublicKey(spkac)
console.log(publicKey)
// 打印:公钥作为 <Buffer ...>
js
const { Certificate } = require('node:crypto')
const cert = Certificate()
const spkac = getSpkacSomehow()
const publicKey = cert.exportPublicKey(spkac)
console.log(publicKey)
// 打印:公钥作为 <Buffer ...>

certificate.verifySpkac(spkac[, encoding])

新增于:v0.11.8

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

类: Cipher

新增于: v0.1.94

Cipher 类的实例用于加密数据。此类可以通过两种方式使用:

  • 作为可读写 ,将未加密的明文数据写入流中,以在可读端产生加密数据,或者
  • 使用 cipher.update()cipher.final() 方法来生成加密数据。

crypto.createCipheriv() 方法用于创建 Cipher 实例。不应使用 new 关键字直接创建 Cipher 对象。

示例:将 Cipher 对象用作流:

js
const { scrypt, randomFill, createCipheriv } = await import('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'

// 首先,我们将生成密钥。密钥长度取决于算法。
// 在此情况下,对于 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()
  })
})
js
const { scrypt, randomFill, createCipheriv } = require('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'

// 首先,我们将生成密钥。密钥长度取决于算法。
// 在此情况下,对于 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()
  })
})

示例:使用 Cipher 和管道流:

js
import { createReadStream, createWriteStream } from 'node:fs'

import { pipeline } from 'node:stream'

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

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'

// 首先,我们将生成密钥。密钥长度取决于算法。
// 在此情况下,对于 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
    })
  })
})
js
const { createReadStream, createWriteStream } = require('node:fs')

const { pipeline } = require('node:stream')

const { scrypt, randomFill, createCipheriv } = require('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'

// 首先,我们将生成密钥。密钥长度取决于算法。
// 在此情况下,对于 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() 方法:

js
const { scrypt, randomFill, createCipheriv } = await import('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'

// 首先,我们将生成密钥。密钥长度取决于算法。
// 在此情况下,对于 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)
  })
})
js
const { scrypt, randomFill, createCipheriv } = require('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'

// 首先,我们将生成密钥。密钥长度取决于算法。
// 在此情况下,对于 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])

新增于:v0.1.94

  • outputEncoding <string> 返回值的编码
  • 返回值: <Buffer> | <string> 任何剩余的加密内容。如果指定了 outputEncoding,则返回一个字符串。如果没有提供 outputEncoding,则返回一个 Buffer

一旦调用了 cipher.final() 方法,Cipher 对象就不能再用于加密数据。尝试多次调用 cipher.final() 将导致抛出错误。

cipher.getAuthTag()

新增于:v1.0.0

  • 返回值: <Buffer> 使用认证加密模式时(目前支持 GCMCCMOCBchacha20-poly1305),cipher.getAuthTag() 方法返回一个包含从给定数据计算出的 认证标签Buffer

cipher.getAuthTag() 方法应该只在使用 cipher.final() 方法完成加密后调用。

如果在创建 cipher 实例期间设置了 authTagLength 选项,则此函数将返回正好 authTagLength 字节。

cipher.setAAD(buffer[, options])

新增于: v1.0.0

当使用认证加密模式时(目前支持 GCMCCMOCBchacha20-poly1305),cipher.setAAD() 方法设置用于 附加认证数据 (AAD) 输入参数的值。

plaintextLength 选项对于 GCMOCB 是可选的。使用 CCM 时,必须指定 plaintextLength 选项,且其值必须与明文长度(以字节为单位)匹配。参见 CCM 模式

cipher.setAAD() 方法必须在 cipher.update() 之前调用。

cipher.setAutoPadding([autoPadding])

新增于:v0.7.1

  • autoPadding <布尔值> 默认值: true
  • 返回值:<Cipher> 用于方法链调用的相同 Cipher 实例。

使用分组加密算法时,Cipher 类会自动将输入数据填充到适当的分组大小。要禁用默认填充,请调用 cipher.setAutoPadding(false)

autoPaddingfalse 时,整个输入数据的长度必须是密码分组大小的倍数,否则 cipher.final() 将抛出错误。禁用自动填充对于非标准填充很有用,例如使用 0x0 代替 PKCS 填充。

必须在 cipher.final() 之前调用 cipher.setAutoPadding() 方法。

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

[历史]

版本变更
v6.0.0默认 inputEncodingbinary 变更为 utf8
v0.1.94新增于:v0.1.94

使用 data 更新密码。如果给出 inputEncoding 参数,则 data 参数是使用指定编码的字符串。如果没有给出 inputEncoding 参数,则 data 必须是 BufferTypedArrayDataView。如果 dataBufferTypedArrayDataView,则忽略 inputEncoding

outputEncoding 指定加密数据的输出格式。如果指定了 outputEncoding,则返回使用指定编码的字符串。如果没有提供 outputEncoding,则返回 Buffer

可以多次使用新数据调用 cipher.update() 方法,直到调用 cipher.final() 为止。在 cipher.final() 之后调用 cipher.update() 将导致抛出错误。

类: Decipher

新增于: v0.1.94

Decipher 类的实例用于解密数据。此类可以使用两种方式之一:

crypto.createDecipheriv() 方法用于创建 Decipher 实例。不应使用 new 关键字直接创建 Decipher 对象。

示例:将 Decipher 对象用作流:

js
import { Buffer } from 'node:buffer'
const { scryptSync, createDecipheriv } = await import('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'
// 密钥长度取决于算法。在本例中,对于 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)
  // 输出:some clear text data
})

// 使用相同的算法、密钥和 IV 加密。
const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'
decipher.write(encrypted, 'hex')
decipher.end()
js
const { scryptSync, createDecipheriv } = require('node:crypto')
const { Buffer } = require('node:buffer')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'
// 密钥长度取决于算法。在本例中,对于 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)
  // 输出:some clear text data
})

// 使用相同的算法、密钥和 IV 加密。
const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'
decipher.write(encrypted, 'hex')
decipher.end()

示例:使用 Decipher 和管道流:

js
import { createReadStream, createWriteStream } from 'node:fs'
import { Buffer } from 'node:buffer'
const { scryptSync, createDecipheriv } = await import('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'
// 使用异步 `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)
js
const { createReadStream, createWriteStream } = require('node:fs')
const { scryptSync, createDecipheriv } = require('node:crypto')
const { Buffer } = require('node:buffer')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'
// 使用异步 `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() 方法:

js
import { Buffer } from 'node:buffer'
const { scryptSync, createDecipheriv } = await import('node:crypto')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'
// 使用异步 `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)
// 输出:some clear text data
js
const { scryptSync, createDecipheriv } = require('node:crypto')
const { Buffer } = require('node:buffer')

const algorithm = 'aes-192-cbc'
const password = 'Password used to generate key'
// 使用异步 `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)
// 输出:some clear text data

decipher.final([outputEncoding])

新增于:v0.1.94

  • outputEncoding <string> 返回值的 编码
  • 返回值: <Buffer> | <string> 任何剩余的已解密内容。如果指定了 outputEncoding,则返回字符串。如果没有提供 outputEncoding,则返回 Buffer

一旦调用了 decipher.final() 方法,Decipher 对象就不能再用于解密数据。尝试多次调用 decipher.final() 将导致抛出错误。

decipher.setAAD(buffer[, options])

[历史]

版本变更
v15.0.0buffer 参数可以是字符串或 ArrayBuffer,并且限制为不超过 2 ** 31 - 1 字节。
v7.2.0此方法现在返回对 decipher 的引用。
v1.0.0新增于:v1.0.0

当使用经过身份验证的加密模式时(目前支持 GCMCCMOCBchacha20-poly1305),decipher.setAAD() 方法设置用于 附加认证数据 (AAD) 输入参数的值。

对于 GCMoptions 参数是可选的。当使用 CCM 时,必须指定 plaintextLength 选项,并且其值必须与以字节为单位的密文长度匹配。请参阅 CCM 模式

decipher.setAAD() 方法必须在 decipher.update() 之前调用。

当将字符串作为 buffer 传递时,请考虑 将字符串用作加密 API 输入时的注意事项

decipher.setAuthTag(buffer[, encoding])

[历史]

版本变更
v22.0.0, v20.13.0在创建 decipher 时,如果不指定 authTagLength 选项,则使用非 128 位的 GCM 标签长度已被弃用。
v15.0.0buffer 参数可以是字符串或 ArrayBuffer,并且大小限制为不超过 2 ** 31 - 1 字节。
v11.0.0如果 GCM 标签长度无效,此方法现在将抛出异常。
v7.2.0此方法现在返回对 decipher 的引用。
v1.0.0添加于:v1.0.0

当使用经过身份验证的加密模式(目前支持 GCMCCMOCBchacha20-poly1305)时,decipher.setAuthTag() 方法用于传入接收到的 身份验证标签。如果没有提供标签,或者如果密文已被篡改,则 decipher.final() 将抛出异常,表明由于身份验证失败应丢弃密文。如果标签长度根据 NIST SP 800-38D 无效或与 authTagLength 选项的值不匹配,则 decipher.setAuthTag() 将抛出错误。

在使用 CCM 模式之前必须调用 decipher.setAuthTag() 方法,在 GCMOCB 模式以及 chacha20-poly1305 模式之前必须调用 decipher.update() 方法。decipher.setAuthTag() 只能调用一次。

将字符串作为身份验证标签传递时,请考虑 将字符串作为输入传递给加密 API 时的注意事项

decipher.setAutoPadding([autoPadding])

新增于:v0.7.1

  • autoPadding <布尔值> 默认值: true
  • 返回值:<Decipher> 用于方法链调用的同一个 Decipher 对象。

当数据在加密时未使用标准块填充时,调用 decipher.setAutoPadding(false) 将禁用自动填充,以防止 decipher.final() 检查并移除填充。

关闭自动填充仅当输入数据的长度是密码块大小的倍数时才有效。

decipher.setAutoPadding() 方法必须在 decipher.final() 之前调用。

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

[历史记录]

版本变更
v6.0.0默认 inputEncodingbinary 变更为 utf8
v0.1.94新增于:v0.1.94

使用 data 更新解密器。如果提供了 inputEncoding 参数,则 data 参数是使用指定编码的字符串。如果没有提供 inputEncoding 参数,则 data 必须是 Buffer。如果 dataBuffer,则忽略 inputEncoding

outputEncoding 指定已解密数据的输出格式。如果指定了 outputEncoding,则返回使用指定编码的字符串。如果没有提供 outputEncoding,则返回 Buffer

decipher.update() 方法可以多次调用新数据,直到调用 decipher.final()。在 decipher.final() 之后调用 decipher.update() 将导致抛出错误。

即使底层密码实现了身份验证,此时返回的明文的真实性和完整性也可能不确定。对于经过身份验证的加密算法,真实性通常仅在应用程序调用 decipher.final() 时才能建立。

类: DiffieHellman

新增于: v0.5.0

DiffieHellman 类是一个用于创建 Diffie-Hellman 密钥交换的实用程序。

DiffieHellman 类的实例可以使用 crypto.createDiffieHellman() 函数创建。

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

// OK
assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'))
js
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)

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

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

新增于: v0.5.0

使用 otherPublicKey 作为对方的公钥计算共享密钥,并返回计算出的共享密钥。提供的密钥使用指定的 inputEncoding 解读,密钥使用指定的 outputEncoding 编码。如果未提供 inputEncoding,则 otherPublicKey 预期为 BufferTypedArrayDataView

如果 outputEncoding 给定一个字符串,则返回一个字符串;否则,返回一个 Buffer

diffieHellman.generateKeys([encoding])

新增于:v0.5.0

除非私钥和公钥已经生成或计算,否则生成 Diffie-Hellman 私钥和公钥值,并以指定的 encoding 返回公钥。此密钥应传输给另一方。如果提供了 encoding,则返回字符串;否则返回 Buffer

此函数是 DH_generate_key() 的一个薄包装器。特别是,一旦生成了或设置了私钥,调用此函数只会更新公钥,而不会生成新的私钥。

diffieHellman.getGenerator([encoding])

新增于:v0.5.0

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

diffieHellman.getPrime([encoding])

新增于:v0.5.0

返回指定 encoding 的 Diffie-Hellman 素数。如果提供了 encoding,则返回字符串;否则返回 Buffer

diffieHellman.getPrivateKey([encoding])

新增于:v0.5.0

返回指定 encoding 的 Diffie-Hellman 私钥。如果提供了 encoding,则返回字符串;否则返回 Buffer

diffieHellman.getPublicKey([encoding])

新增于:v0.5.0

返回指定 encoding 编码的 Diffie-Hellman 公钥。如果提供了 encoding,则返回字符串;否则返回 Buffer

diffieHellman.setPrivateKey(privateKey[, encoding])

新增于:v0.5.0

设置 Diffie-Hellman 私钥。如果提供了 encoding 参数,则 privateKey 预期为字符串。如果没有提供 encoding,则 privateKey 预期为 BufferTypedArrayDataView

此函数不会自动计算相关的公钥。可以使用 diffieHellman.setPublicKey()diffieHellman.generateKeys() 手动提供公钥或自动导出公钥。

diffieHellman.setPublicKey(publicKey[, encoding])

新增于: v0.5.0

设置 Diffie-Hellman 公钥。如果提供了 encoding 参数,则 publicKey 预期为字符串。如果没有提供 encoding,则 publicKey 预期为 BufferTypedArrayDataView

diffieHellman.verifyError

新增于: v0.11.12

一个位字段,包含在 DiffieHellman 对象初始化期间执行的检查所产生的任何警告和/或错误。

此属性的有效值如下(在 node:constants 模块中定义):

  • DH_CHECK_P_NOT_SAFE_PRIME
  • DH_CHECK_P_NOT_PRIME
  • DH_UNABLE_TO_CHECK_GENERATOR
  • DH_NOT_SUITABLE_GENERATOR

类: DiffieHellmanGroup

新增于: v0.7.5

DiffieHellmanGroup 类接收一个众所周知的 modp 组作为参数。它的工作方式与 DiffieHellman 相同,只是它不允许在创建后更改其密钥。换句话说,它不实现 setPublicKey()setPrivateKey() 方法。

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

支持以下组:

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

以下组仍然支持,但已弃用(参见警告):

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

这些已弃用的组可能会在未来的 Node.js 版本中移除。

类: ECDH

新增于: v0.11.14

ECDH 类是用于创建椭圆曲线 Diffie-Hellman (ECDH) 密钥交换的实用程序。

可以使用 crypto.createECDH() 函数创建 ECDH 类的实例。

js
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'))
// OK
js
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'))
// OK

静态方法: ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])

新增于: v10.0.0

将由 keycurve 指定的 EC Diffie-Hellman 公钥转换为 format 指定的格式。format 参数指定点编码,可以是 'compressed''uncompressed''hybrid'。提供的密钥使用指定的 inputEncoding 解读,返回的密钥使用指定的 outputEncoding 编码。

使用 crypto.getCurves() 获取可用曲线名称列表。在最新的 OpenSSL 版本上,openssl ecparam -list_curves 也会显示每个可用椭圆曲线的名称和描述。

如果未指定 format,则点将以 'uncompressed' 格式返回。

如果未提供 inputEncoding,则 key 预期为 BufferTypedArrayDataView

示例(解压缩密钥):

js
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'))
js
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])

[历史]

版本变更
v10.0.0将错误格式更改为更好地支持无效公钥错误。
v6.0.0默认的 inputEncodingbinary 更改为 utf8
v0.11.14新增于:v0.11.14

使用 otherPublicKey 作为对方的公钥计算共享密钥,并返回计算出的共享密钥。提供的密钥使用指定的 inputEncoding 解释,返回的密钥使用指定的 outputEncoding 编码。如果未提供 inputEncoding,则预期 otherPublicKeyBufferTypedArrayDataView

如果 outputEncoding 给定一个字符串,则返回一个字符串;否则返回一个 Buffer

otherPublicKey 位于椭圆曲线之外时,ecdh.computeSecret 将抛出 ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY 错误。由于 otherPublicKey 通常通过不安全的网络从远程用户处提供,因此务必相应地处理此异常。

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

新增于:v0.11.14

生成私钥和公钥 EC Diffie-Hellman 密钥值,并以指定的 formatencoding 返回公钥。此密钥应传输给对方。

format 参数指定点编码,可以是 'compressed''uncompressed'。如果未指定 format,则点将以 'uncompressed' 格式返回。

如果提供了 encoding,则返回字符串;否则返回 Buffer

ecdh.getPrivateKey([encoding])

新增于:v0.11.14

如果指定了encoding,则返回字符串;否则返回Buffer

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

新增于:v0.11.14

format参数指定点编码,可以是'compressed''uncompressed'。如果未指定format,则点将以'uncompressed'格式返回。

如果指定了encoding,则返回字符串;否则返回Buffer

ecdh.setPrivateKey(privateKey[, encoding])

Added in: v0.11.14

设置 EC Diffie-Hellman 私钥。如果提供了 encoding,则 privateKey 预期为字符串;否则 privateKey 预期为 BufferTypedArrayDataView

如果 privateKey 对创建 ECDH 对象时指定的曲线无效,则会抛出错误。设置私钥后,关联的公钥也会生成并设置在 ECDH 对象中。

ecdh.setPublicKey(publicKey[, encoding])

新增于:v0.11.14

自 v5.2.0 起已弃用

[稳定性: 0 - 已弃用]

稳定性: 0 - 已弃用

设置 EC Diffie-Hellman 公钥。如果提供了 encoding,则 publicKey 预期为字符串;否则预期为 BufferTypedArrayDataView

通常没有理由调用此方法,因为 ECDH 只需要私钥和另一方的公钥来计算共享密钥。通常会调用 ecdh.generateKeys()ecdh.setPrivateKey()ecdh.setPrivateKey() 方法尝试生成与正在设置的私钥关联的公钥/点。

示例(获取共享密钥):

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

新增于: v0.1.92

Hash 类是一个用于创建数据哈希摘要的实用程序。它可以通过两种方式使用:

  • 作为可读写,其中写入数据以在可读端生成计算出的哈希摘要,或者
  • 使用hash.update()hash.digest() 方法来生成计算出的哈希值。

crypto.createHash() 方法用于创建 Hash 实例。不应使用 new 关键字直接创建 Hash 对象。

示例:将 Hash 对象用作流:

js
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()
js
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 和管道流:

js
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)
js
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() 方法:

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

const hash = createHash('sha256')

hash.update('some data to hash')
console.log(hash.digest('hex'))
// 输出:
//   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
js
const { createHash } = require('node:crypto')

const hash = createHash('sha256')

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

hash.copy([options])

新增于:v13.1.0

创建一个新的 Hash 对象,其中包含当前 Hash 对象内部状态的深拷贝。

可选的 options 参数控制流行为。对于诸如 'shake256' 的 XOF 哈希函数,可以使用 outputLength 选项来指定所需的输出长度(以字节为单位)。

在调用其 hash.digest() 方法后尝试复制 Hash 对象将会抛出错误。

js
// 计算滚动哈希。
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'))

// 等等
js
// 计算滚动哈希。
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])

新增于: v0.1.92

计算传递到哈希函数的所有数据的摘要(使用 hash.update() 方法)。如果提供了 encoding,则返回字符串;否则返回 Buffer

在调用 hash.digest() 方法后,Hash 对象将无法再次使用。多次调用将导致抛出错误。

hash.update(data[, inputEncoding])

[历史记录]

版本变更
v6.0.0默认 inputEncodingbinary 变更为 utf8
v0.1.92新增于: v0.1.92

使用给定的 data 更新哈希内容,其编码在 inputEncoding 中给出。如果未提供 encoding,并且 data 是字符串,则强制使用 'utf8' 编码。如果 dataBufferTypedArrayDataView,则忽略 inputEncoding

这可以多次调用,并传入新的数据,因为它可以被流式传输。

类: Hmac

新增于: v0.1.94

Hmac 类是一个用于创建加密 HMAC 散列的实用程序。它可以以两种方式使用:

  • 作为可读和可写的,将数据写入流以在可读端生成计算出的 HMAC 散列,或者
  • 使用hmac.update()hmac.digest() 方法来生成计算出的 HMAC 散列。

crypto.createHmac() 方法用于创建 Hmac 实例。Hmac 对象不能直接使用 new 关键字创建。

示例:将 Hmac 对象用作流:

js
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()
js
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 和管道流:

js
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)
js
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() 方法:

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

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

hmac.update('some data to hash')
console.log(hmac.digest('hex'))
// 输出:
//   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
js
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])

新增于: v0.1.94

使用 hmac.update() 计算所有已传入数据的 HMAC 散列值。如果提供了 encoding,则返回字符串;否则返回 Buffer

在调用 hmac.digest() 后,Hmac 对象将无法再次使用。多次调用 hmac.digest() 将导致抛出错误。

hmac.update(data[, inputEncoding])

[历史记录]

版本变更
v6.0.0默认 inputEncodingbinary 变更为 utf8
v0.1.94新增于: v0.1.94

使用给定的 data 更新 Hmac 内容,其编码在 inputEncoding 中给出。如果未提供 encoding,并且 data 是字符串,则强制使用 'utf8' 编码。如果 dataBufferTypedArrayDataView,则忽略 inputEncoding

这可以多次调用,每次传入新的数据,就像数据流一样。

类: KeyObject

[历史]

版本变更
v14.5.0, v12.19.0此类的实例现在可以使用 postMessage 传递给工作线程。
v11.13.0此类现在已导出。
v11.6.0新增于:v11.6.0

Node.js 使用 KeyObject 类来表示对称密钥或非对称密钥,每种密钥都公开不同的函数。crypto.createSecretKey()crypto.createPublicKey()crypto.createPrivateKey() 方法用于创建 KeyObject 实例。不应使用 new 关键字直接创建 KeyObject 对象。

由于改进了安全功能,大多数应用程序应考虑使用新的 KeyObject API,而不是将密钥作为字符串或 Buffer 传递。

KeyObject 实例可以通过 postMessage() 传递给其他线程。接收方获得一个克隆的 KeyObject,并且 KeyObject 不需要列在 transferList 参数中。

静态方法: KeyObject.from(key)

新增于: v15.0.0

示例:将 CryptoKey 实例转换为 KeyObject

js
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 (以字节为单位的对称密钥大小)
js
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 (以字节为单位的对称密钥大小)
})()

keyObject.asymmetricKeyDetails

[历史]

版本变更
v16.9.0公开 RSA-PSS 密钥的 RSASSA-PSS-params 序列参数。
v15.7.0v15.7.0 版本中添加
  • <对象>
    • modulusLength: <数字> 密钥大小(以位为单位)(RSA、DSA)。
    • publicExponent: <大整数> 公开指数 (RSA)。
    • hashAlgorithm: <字符串> 消息摘要的名称 (RSA-PSS)。
    • mgf1HashAlgorithm: <字符串> MGF1 使用的消息摘要的名称 (RSA-PSS)。
    • saltLength: <数字> 最小盐长度(以字节为单位)(RSA-PSS)。
    • divisorLength: <数字> q 的大小(以位为单位)(DSA)。
    • namedCurve: <字符串> 曲线的名称 (EC)。

此属性仅存在于非对称密钥上。根据密钥的类型,此对象包含有关密钥的信息。通过此属性获得的任何信息都不能用于唯一标识密钥或危及密钥的安全。

对于 RSA-PSS 密钥,如果密钥材料包含 RSASSA-PSS-params 序列,则将设置 hashAlgorithmmgf1HashAlgorithmsaltLength 属性。

其他密钥详细信息可能通过此 API 使用附加属性公开。

keyObject.asymmetricKeyType

[历史]

版本变更
v13.9.0, v12.17.0新增对 'dh' 的支持。
v12.0.0新增对 'rsa-pss' 的支持。
v12.0.0此属性现在对于类型无法识别的 KeyObject 实例返回 undefined,而不是中止。
v12.0.0新增对 'x25519''x448' 的支持。
v12.0.0新增对 'ed25519''ed448' 的支持。
v11.6.0首次引入: v11.6.0

对于非对称密钥,此属性表示密钥的类型。支持的密钥类型包括:

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

对于无法识别的 KeyObject 类型和对称密钥,此属性为 undefined

keyObject.equals(otherKeyObject)

新增于: v17.7.0, v16.15.0

根据密钥是否具有完全相同的类型、值和参数返回 truefalse。此方法不是 恒定时间 的。

keyObject.export([options])

[历史]

版本变更
v15.9.0新增对 'jwk' 格式的支持。
v11.6.0新增于: v11.6.0

对于对称密钥,可以使用以下编码选项:

  • format: <string> 必须是 'buffer'(默认)或 'jwk'

对于公钥,可以使用以下编码选项:

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

对于私钥,可以使用以下编码选项:

  • type: <string> 必须是 'pkcs1'(仅限 RSA)、'pkcs8''sec1'(仅限 EC)之一。
  • format: <string> 必须是 'pem''der''jwk'
  • cipher: <string> 如果指定,则私钥将使用给定的 cipherpassphrase 使用 PKCS#5 v2.0 基于密码的加密进行加密。
  • passphrase: <string> | <Buffer> 用于加密的密码,请参见 cipher

结果类型取决于所选的编码格式,PEM 时结果为字符串,DER 时将是包含以 DER 编码的数据的缓冲区,JWK 时将是对象。

当选择 JWK 编码格式时,将忽略所有其他编码选项。

PKCS#1、SEC1 和 PKCS#8 类型密钥可以使用 cipherformat 选项的组合进行加密。PKCS#8 type 可与任何 format 一起使用,通过指定 cipher 来加密任何密钥算法(RSA、EC 或 DH)。只有在使用 PEM format 时,才能通过指定 cipher 来加密 PKCS#1 和 SEC1。为了最大限度地兼容,请对加密的私钥使用 PKCS#8。由于 PKCS#8 定义了自己的加密机制,因此在加密 PKCS#8 密钥时不支持 PEM 级加密。有关 PKCS#8 加密,请参见 RFC 5208,有关 PKCS#1 和 SEC1 加密,请参见 RFC 1421

keyObject.symmetricKeySize

新增于: v11.6.0

对于密钥,此属性表示密钥的大小(以字节为单位)。对于非对称密钥,此属性为 undefined

keyObject.toCryptoKey(algorithm, extractable, keyUsages)

新增于: v23.0.0

KeyObject 实例转换为 CryptoKey

keyObject.type

新增于: v11.6.0

取决于此 KeyObject 的类型,此属性为秘密(对称)密钥的 'secret'、公钥(非对称)密钥的 'public' 或私钥(非对称)密钥的 'private'

类: Sign

新增于: v0.1.92

Sign 类是用于生成签名的实用程序。它可以以两种方式之一使用:

crypto.createSign() 方法用于创建 Sign 实例。参数是要使用的哈希函数的字符串名称。不应使用 new 关键字直接创建 Sign 对象。

示例:将 SignVerify 对象用作流:

js
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
js
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() 方法:

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

[历史]

版本变更
v15.0.0privateKey 现在也可以是 ArrayBufferCryptoKey
v13.2.0, v12.16.0此函数现在支持 IEEE-P1363 DSA 和 ECDSA 签名。
v12.0.0此函数现在支持 RSA-PSS 密钥。
v11.6.0此函数现在支持密钥对象。
v8.0.0添加了对 RSASSA-PSS 和其他选项的支持。
v0.1.92在 v0.1.92 版本中添加

使用 sign.update()sign.write() 传递的所有数据计算签名。

如果 privateKey 不是 KeyObject,则此函数的行为就像 privateKey 已传递给 crypto.createPrivateKey() 一样。如果它是一个对象,则可以传递以下附加属性:

  • dsaEncoding <字符串> 对于 DSA 和 ECDSA,此选项指定生成的签名的格式。它可以是以下之一:

    • 'der' (默认):DER 编码的 ASN.1 签名结构编码 (r, s)
    • 'ieee-p1363':IEEE-P1363 中提出的签名格式 r || s
  • padding <整数> RSA 的可选填充值,可以是以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (默认)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

RSA_PKCS1_PSS_PADDING 将使用与用于签名消息的散列函数相同的 MGF1,如 RFC 4055 的第 3.1 节所指定,除非 MGF1 散列函数已在密钥中指定,符合 RFC 4055 的第 3.3 节。

  • saltLength <整数> 当填充为 RSA_PKCS1_PSS_PADDING 时的盐长度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN (默认) 将其设置为最大允许值。

如果提供了 outputEncoding,则返回字符串;否则返回 Buffer

sign.sign() 方法调用后,Sign 对象将无法再次使用。多次调用 sign.sign() 将导致抛出错误。

sign.update(data[, inputEncoding])

[历史]

版本变更
v6.0.0默认 inputEncodingbinary 变更为 utf8
v0.1.92v0.1.92 版本中添加

使用给定的 data 更新 Sign 内容,其编码在 inputEncoding 中给出。如果未提供 encoding,并且 data 是字符串,则强制使用 'utf8' 编码。如果 dataBufferTypedArrayDataView,则忽略 inputEncoding

这可以多次调用新的数据,因为它被流式传输。

类: Verify

新增于: v0.1.92

Verify 类是一个用于验证签名的实用程序。它可以通过两种方式使用:

crypto.createVerify() 方法用于创建 Verify 实例。不应使用 new 关键字直接创建 Verify 对象。

参见 Sign 获取示例。

verify.update(data[, inputEncoding])

[历史]

版本变更
v6.0.0默认 inputEncodingbinary 变为 utf8
v0.1.92新增于: v0.1.92

使用给定的 data 更新 Verify 内容,其编码在 inputEncoding 中给出。如果未提供 inputEncoding,并且 data 是字符串,则强制使用 'utf8' 编码。如果 dataBufferTypedArrayDataView,则忽略 inputEncoding

这可以多次调用新数据,因为它被流式传输。

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

[历史]

版本变更
v15.0.0object 也可以是 ArrayBufferCryptoKey
v13.2.0, v12.16.0此函数现在支持 IEEE-P1363 DSA 和 ECDSA 签名。
v12.0.0此函数现在支持 RSA-PSS 密钥。
v11.7.0密钥现在可以是私钥。
v8.0.0添加了对 RSASSA-PSS 和其他选项的支持。
v0.1.92v0.1.92 版本中添加

使用给定的 objectsignature 验证提供的数据。

如果 object 不是 KeyObject,则此函数的行为如同将 object 传递给 crypto.createPublicKey() 一样。如果它是一个对象,则可以传递以下附加属性:

  • dsaEncoding <字符串> 对于 DSA 和 ECDSA,此选项指定签名的格式。它可以是以下之一:

    • 'der' (默认): DER 编码的 ASN.1 签名结构编码 (r, s)
    • 'ieee-p1363': IEEE-P1363 中提出的签名格式 r || s
  • padding <整数> RSA 的可选填充值,可以是以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (默认)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

RSA_PKCS1_PSS_PADDING 将使用与用于验证消息的哈希函数相同的 MGF1,如 RFC 4055 的 3.1 节中所述,除非 MGF1 哈希函数已作为密钥的一部分指定,符合 RFC 4055 的 3.3 节。

  • saltLength <整数> 当填充为 RSA_PKCS1_PSS_PADDING 时的盐长度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_AUTO (默认) 会自动确定它。

signature 参数是先前为数据计算的签名,采用 signatureEncoding 格式。如果指定了 signatureEncoding,则 signature 预期为字符串;否则,signature 预期为 BufferTypedArrayDataView

verify 对象在调用 verify.verify() 后将无法再次使用。多次调用 verify.verify() 将导致抛出错误。

因为可以从私钥导出公钥,所以可以使用私钥代替公钥。

类: X509Certificate

新增于: v15.6.0

封装 X509 证书并提供对其信息的只读访问。

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

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

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

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

console.log(x509.subject)

new X509Certificate(buffer)

新增于: v15.6.0

x509.ca

新增于: v15.6.0

  • 类型: <boolean> 如果这是一个证书颁发机构 (CA) 证书,则为 true

x509.checkEmail(email[, options])

[历史]

版本变更
v18.0.0subject 选项现在默认为 'default'
v17.5.0, v16.15.0subject 选项现在可以设置为 'default'
v17.5.0, v16.14.1wildcards, partialWildcards, multiLabelWildcardssingleLabelSubdomains 选项已被移除,因为它们无效。
v15.6.0v15.6.0 版本中添加

检查证书是否与给定的电子邮件地址匹配。

如果 'subject' 选项未定义或设置为 'default',则只有在主题替代名称扩展名不存在或不包含任何电子邮件地址时,才考虑证书主题。

如果 'subject' 选项设置为 'always',并且主题替代名称扩展名不存在或不包含匹配的电子邮件地址,则考虑证书主题。

如果 'subject' 选项设置为 'never',则永远不会考虑证书主题,即使证书不包含主题替代名称也是如此。

x509.checkHost(name[, options])

[历史]

版本变更
v18.0.0subject 选项现在默认为 'default'
v17.5.0, v16.15.0subject 选项现在可以设置为 'default'
v15.6.0v15.6.0 版本新增

检查证书是否与给定的主机名匹配。

如果证书与给定的主机名匹配,则返回匹配的主题名称。返回的名称可能是完全匹配(例如,foo.example.com),也可能包含通配符(例如,*.example.com)。由于主机名比较不区分大小写,因此返回的主题名称也可能与给定的 name 在大小写方面有所不同。

如果 'subject' 选项未定义或设置为 'default',则只有当主题替代名称扩展名不存在或不包含任何 DNS 名称时,才会考虑证书主题。此行为与 RFC 2818(“HTTP Over TLS”)一致。

如果 'subject' 选项设置为 'always',并且主题替代名称扩展名不存在或不包含匹配的 DNS 名称,则会考虑证书主题。

如果 'subject' 选项设置为 'never',则永远不会考虑证书主题,即使证书不包含主题替代名称也是如此。

x509.checkIP(ip)

[历史]

版本变更
v17.5.0, v16.14.1由于 options 参数无效,已将其移除。
v15.6.0v15.6.0 版本中添加

检查证书是否与给定的 IP 地址(IPv4 或 IPv6)匹配。

仅考虑 RFC 5280 iPAddress 主题备选名称,并且它们必须与给定的 ip 地址完全匹配。证书的其它主题备选名称以及主题字段将被忽略。

x509.checkIssued(otherCert)

v15.6.0 版本中添加

检查此证书是否由给定的 otherCert 颁发。

x509.checkPrivateKey(privateKey)

新增于: v15.6.0

检查此证书的公钥是否与给定的私钥一致。

x509.extKeyUsage

新增于: v15.6.0

一个数组,详细说明此证书的密钥扩展用途。

x509.fingerprint

新增于: v15.6.0

此证书的 SHA-1 指纹。

由于 SHA-1 在密码学上已被攻破,并且 SHA-1 的安全性远低于通常用于签署证书的算法,因此请考虑改用 x509.fingerprint256

x509.fingerprint256

新增于: v15.6.0

此证书的 SHA-256 指纹。

x509.fingerprint512

新增于: v17.2.0, v16.14.0

此证书的 SHA-512 指纹。

由于计算 SHA-256 指纹通常更快,并且其大小只有 SHA-512 指纹的一半,因此 x509.fingerprint256 可能是更好的选择。虽然 SHA-512 通常可能提供更高的安全级别,但 SHA-256 的安全性与大多数用于签署证书的常用算法的安全性相当。

x509.infoAccess

[历史]

版本变更
v17.3.1, v16.13.2此字符串的某些部分可能被编码为 JSON 字符串字面量以响应 CVE-2021-44532。
v15.6.0新增于: v15.6.0

证书的授权信息访问扩展的文本表示。

这是一个换行符分隔的访问描述列表。每一行都以访问方法和访问位置的类型开头,后面跟着一个冒号和与访问位置关联的值。

在表示访问方法和访问位置类型的首缀之后,每行的其余部分可能会用引号括起来,以指示该值是 JSON 字符串字面量。为了向后兼容,Node.js 仅在必要时才会在此属性中使用 JSON 字符串字面量以避免歧义。第三方代码应准备好处理两种可能的条目格式。

x509.issuer

新增于: v15.6.0

此证书中包含的发行者标识。

x509.issuerCertificate

新增于: v15.9.0

发行者证书,如果发行者证书不可用则为 undefined

x509.publicKey

新增于: v15.6.0

此证书的公钥 <KeyObject>

x509.raw

新增于: v15.6.0

包含此证书的 DER 编码的 Buffer

x509.serialNumber

新增于: v15.6.0

此证书的序列号。

序列号由证书颁发机构分配,不能唯一标识证书。建议使用 x509.fingerprint256 作为唯一标识符。

x509.subject

新增于: v15.6.0

此证书的完整主体。

x509.subjectAltName

[历史记录]

版本变更
v17.3.1, v16.13.2为响应 CVE-2021-44532,此字符串的部分内容可能被编码为 JSON 字符串字面量。
v15.6.0新增于: v15.6.0

为此证书指定的主题替代名称。

这是一个逗号分隔的主题替代名称列表。每个条目以一个字符串开头,该字符串标识主题替代名称的类型,后跟一个冒号和与该条目关联的值。

早期版本的 Node.js 错误地假设以双字符序列 ', ' 分割此属性是安全的(参见 CVE-2021-44532)。但是,恶意和合法的证书都可能包含在表示为字符串时包含此序列的主题替代名称。

在表示条目类型的前缀之后,每个条目的其余部分可能用引号括起来,以指示该值是 JSON 字符串字面量。为了向后兼容,Node.js 仅在必要时才在此属性中使用 JSON 字符串字面量以避免歧义。第三方代码应准备好处理两种可能的条目格式。

x509.toJSON()

新增于:v15.6.0

X509 证书没有标准的 JSON 编码。toJSON() 方法返回一个包含 PEM 编码证书的字符串。

x509.toLegacyObject()

新增于:v15.6.0

使用旧版 证书对象 编码返回关于此证书的信息。

x509.toString()

新增于:v15.6.0

返回 PEM 编码的证书。

x509.validFrom

新增于:v15.6.0

此证书有效的日期/时间。

x509.validFromDate

新增于:v23.0.0

此证书有效的日期/时间,封装在 Date 对象中。

x509.validTo

新增于: v15.6.0

此证书有效的日期/时间。

x509.validToDate

新增于: v23.0.0

此证书有效的日期/时间,封装在一个 Date 对象中。

x509.verify(publicKey)

新增于: v15.6.0

验证此证书是否由给定的公钥签名。不对证书执行任何其他验证检查。

node:crypto 模块方法和属性

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

[历史]

版本变更
v18.0.0将无效的回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v15.8.0新增于: v15.8.0
  • candidate <ArrayBuffer> | <SharedArrayBuffer> | <TypedArray> | <Buffer> | <DataView> | <bigint> 一个可能的素数,编码为任意长度的大端字节序八位字节序列。

  • options <Object>

    • checks <number> 要执行的 Miller-Rabin 概率素性迭代次数。当值为 0(零)时,使用的检查次数产生的误报率对于随机输入最多为 2。选择检查次数时必须小心。有关更多详细信息,请参阅 OpenSSL 文档中 BN_is_prime_ex 函数的 nchecks 选项。默认值: 0
  • callback <Function>

    • err <Error> 如果检查过程中发生错误,则设置为 <Error> 对象。
    • result <boolean> 如果候选数是素数,且误差概率小于 0.25 ** options.checks,则为 true

检查 candidate 的素性。

crypto.checkPrimeSync(candidate[, options])

新增于: v15.8.0

  • candidate <ArrayBuffer> | <SharedArrayBuffer> | <TypedArray> | <Buffer> | <DataView> | <bigint> 一个可能的素数,编码为任意长度的大端字节序序列。

  • options <Object>

    • checks <number> 要执行的 Miller-Rabin 概率素性迭代次数。当值为 0(零)时,使用的检查次数产生的误报率对于随机输入最多为 2。选择检查次数时必须小心。有关更多详细信息,请参阅 OpenSSL 文档中 BN_is_prime_ex 函数的 nchecks 选项。默认值: 0
  • 返回值: <boolean> 如果候选数是素数,且误差概率小于 0.25 ** options.checks,则返回 true

检查 candidate 的素性。

crypto.constants

新增于:v6.3.0

一个包含常用加密和安全相关操作常量的对象。当前定义的特定常量在加密常量中描述。

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

[历史]

版本变更
v17.9.0, v16.17.0使用 chacha20-poly1305 密码时,authTagLength 选项现在是可选的,默认为 16 字节。
v15.0.0密码和 iv 参数可以是 ArrayBuffer,每个参数的最大限制为 2 ** 31 - 1 字节。
v11.6.0key 参数现在可以是 KeyObject
v11.2.0, v10.17.0现在支持密码 chacha20-poly1305(ChaCha20-Poly1305 的 IETF 变体)。
v10.10.0现在支持 OCB 模式的密码。
v10.2.0现在可以使用 authTagLength 选项在 GCM 模式下生成较短的认证标签,默认为 16 字节。
v9.9.0iv 参数现在可以为不需要初始化向量的密码设置为 null
v0.1.94新增于:v0.1.94

创建并返回一个 Cipher 对象,使用给定的 algorithmkey 和初始化向量 (iv)。

options 参数控制流行为,并且是可选的,除非使用 CCM 或 OCB 模式(例如 'aes-128-ccm')的密码。在这种情况下,authTagLength 选项是必需的,并指定认证标签的长度(以字节为单位),参见CCM 模式。在 GCM 模式下,authTagLength 选项不是必需的,但可以用来设置 getAuthTag() 将返回的认证标签的长度,默认为 16 字节。对于 chacha20-poly1305authTagLength 选项默认为 16 字节。

algorithm 依赖于 OpenSSL,例如 'aes192' 等。在最新的 OpenSSL 版本上,openssl list -cipher-algorithms 将显示可用的密码算法。

keyalgorithm 使用的原始密钥,iv初始化向量。这两个参数必须是 'utf8' 编码的字符串、BufferTypedArrayDataViewkey 可以选择是一个类型为 secretKeyObject。如果密码不需要初始化向量,则 iv 可以为 null

当为 keyiv 传递字符串时,请考虑使用字符串作为加密 API 输入时的注意事项

初始化向量应该是不可预测且唯一的;理想情况下,它们应该是加密随机的。它们不必保密:IV 通常只是添加到未加密的密文中。这听起来可能自相矛盾,即某些东西必须不可预测且唯一,但不必保密;请记住,攻击者不能提前预测给定的 IV 将是什么。

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

[历史]

版本变更
v17.9.0, v16.17.0使用 chacha20-poly1305 密码时,authTagLength 选项现在是可选的,默认为 16 字节。
v11.6.0key 参数现在可以是 KeyObject
v11.2.0, v10.17.0现在支持密码 chacha20-poly1305(ChaCha20-Poly1305 的 IETF 变体)。
v10.10.0现在支持 OCB 模式下的密码。
v10.2.0现在可以使用 authTagLength 选项来限制可接受的 GCM 身份验证标签长度。
v9.9.0对于不需要初始化向量的密码,iv 参数现在可以为 null
v0.1.94新增于:v0.1.94

创建并返回一个 Decipher 对象,该对象使用给定的 algorithmkey 和初始化向量 (iv)。

options 参数控制流行为,除非使用 CCM 或 OCB 模式下的密码(例如 'aes-128-ccm'),否则它是可选的。在这种情况下,需要 authTagLength 选项,并指定身份验证标签的长度(以字节为单位),请参阅 CCM 模式。对于 AES-GCM 和 chacha20-poly1305authTagLength 选项默认为 16 字节,如果使用不同长度,则必须将其设置为不同的值。

algorithm 依赖于 OpenSSL,例如 'aes192' 等。在最近的 OpenSSL 版本中,openssl list -cipher-algorithms 将显示可用的密码算法。

keyalgorithm 使用的原始密钥,iv初始化向量。这两个参数必须是 'utf8' 编码的字符串、BufferTypedArrayDataViewkey 可选地可以是类型为 secretKeyObject。如果密码不需要初始化向量,则 iv 可以为 null

当为 keyiv 传递字符串时,请考虑 使用字符串作为加密 API 的输入时的注意事项

初始化向量应该是不可预测且唯一的;理想情况下,它们将是密码学随机的。它们不必保密:IV 通常只是添加到未加密的密文中。听起来似乎自相矛盾,即某些东西必须不可预测且唯一,但不一定保密;请记住,攻击者不能提前预测给定的 IV 将是什么。

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

[历史]

版本变更
v8.0.0prime 参数现在可以是任何 TypedArrayDataView
v8.0.0prime 参数现在可以是 Uint8Array
v6.0.0编码参数的默认值已从 binary 更改为 utf8
v0.11.12新增于:v0.11.12

使用提供的 prime 和可选的特定 generator 创建 DiffieHellman 密钥交换对象。

generator 参数可以是数字、字符串或 Buffer。如果未指定 generator,则使用值 2

如果指定了 primeEncoding,则 prime 预期为字符串;否则,预期为 BufferTypedArrayDataView

如果指定了 generatorEncoding,则 generator 预期为字符串;否则,预期为数字、BufferTypedArrayDataView

crypto.createDiffieHellman(primeLength[, generator])

新增于:v0.5.0

创建一个 DiffieHellman 密钥交换对象,并使用可选的特定数值 generator 生成 primeLength 比特的素数。如果未指定 generator,则使用值 2

crypto.createDiffieHellmanGroup(name)

新增于:v0.9.3

crypto.getDiffieHellman() 的别名

crypto.createECDH(curveName)

新增于:v0.11.14

使用由 curveName 字符串指定的预定义曲线创建一个椭圆曲线 Diffie-Hellman (ECDH) 密钥交换对象。使用 crypto.getCurves() 获取可用曲线名称列表。在最新的 OpenSSL 版本中,openssl ecparam -list_curves 也会显示每个可用椭圆曲线的名称和描述。

crypto.createHash(algorithm[, options])

[历史]

版本变更
v12.8.0为 XOF 哈希函数添加了 outputLength 选项。
v0.1.92在 v0.1.92 中添加

创建并返回一个 Hash 对象,该对象可用于使用给定的 algorithm 生成哈希摘要。可选的 options 参数控制流行为。对于诸如 'shake256' 之类的 XOF 哈希函数,可以使用 outputLength 选项指定所需的输出长度(以字节为单位)。

algorithm 取决于平台上 OpenSSL 版本支持的可用算法。例如 'sha256''sha512' 等。在 OpenSSL 的最新版本上,openssl list -digest-algorithms 将显示可用的摘要算法。

示例:生成文件的 sha256 校验和

js
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}`)
  }
})
js
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])

[历史]

版本变更
v15.0.0key 也可以是 ArrayBufferCryptoKey。添加了 encoding 选项。key 的字节数不能超过 2 ** 32 - 1。
v11.6.0key 参数现在可以是 KeyObject
v0.1.94新增于:v0.1.94

创建并返回一个 Hmac 对象,该对象使用给定的 algorithmkey。可选的 options 参数控制流行为。

algorithm 取决于平台上 OpenSSL 版本支持的可用算法。例如 'sha256''sha512' 等。在最新版本的 OpenSSL 上,openssl list -digest-algorithms 将显示可用的摘要算法。

key 是用于生成密码 HMAC 哈希的 HMAC 密钥。如果它是 KeyObject,则其类型必须是 secret。如果它是字符串,请考虑使用字符串作为密码 API 输入时的注意事项。如果它是从密码安全的熵源(例如 crypto.randomBytes()crypto.generateKey())获得的,则其长度不应超过 algorithm 的块大小(例如,SHA-256 为 512 位)。

示例:生成文件的 sha256 HMAC

js
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}`)
  }
})
js
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(key)

[历史]

版本变更
v15.12.0密钥也可以是 JWK 对象。
v15.0.0密钥也可以是 ArrayBuffer。添加了 encoding 选项。密钥不能超过 2 ** 32 - 1 字节。
v11.6.0新增于:v11.6.0

创建并返回一个包含私钥的新密钥对象。如果 key 是字符串或 Buffer,则 format 假设为 'pem';否则,key 必须是一个具有上述属性的对象。

如果私钥已加密,则必须指定 passphrase。密码的长度限制为 1024 字节。

crypto.createPublicKey(key)

[历史]

版本变更
v15.12.0密钥也可以是 JWK 对象。
v15.0.0密钥也可以是 ArrayBuffer。添加了 encoding 选项。密钥大小不能超过 2 ** 32 - 1 字节。
v11.13.0key 参数现在可以是类型为 privateKeyObject
v11.7.0key 参数现在可以是私钥。
v11.6.0v11.6.0 中添加

创建并返回一个包含公钥的新密钥对象。如果 key 是字符串或 Buffer,则假定 format'pem';如果 key 是类型为 'private'KeyObject,则公钥将从给定的私钥派生;否则,key 必须是一个对象,包含上述属性。

如果格式为 'pem''key' 也可能是 X.509 证书。

由于可以从私钥派生公钥,因此可以传递私钥而不是公钥。在这种情况下,此函数的行为就像调用了 crypto.createPrivateKey() 一样,只是返回的 KeyObject 的类型将为 'public',并且无法从返回的 KeyObject 中提取私钥。同样,如果给定类型为 'private'KeyObject,则将返回类型为 'public' 的新 KeyObject,并且无法从返回的对象中提取私钥。

crypto.createSecretKey(key[, encoding])

[历史]

版本变更
v18.8.0, v16.18.0密钥现在可以为空。
v15.0.0密钥也可以是 ArrayBuffer 或字符串。添加了 encoding 参数。密钥不能超过 2 ** 32 - 1 个字节。
v11.6.0首次添加:v11.6.0

创建并返回一个新的密钥对象,其中包含用于对称加密或 Hmac 的密钥。

crypto.createSign(algorithm[, options])

Added in: v0.1.92

创建一个并返回一个使用给定 algorithmSign 对象。 使用 crypto.getHashes() 获取可用摘要算法的名称。 可选的 options 参数控制 stream.Writable 的行为。

在某些情况下,可以使用签名算法的名称(例如 'RSA-SHA256')而不是摘要算法的名称来创建一个 Sign 实例。这将使用相应的摘要算法。但这不适用于所有签名算法,例如 'ecdsa-with-SHA256',因此最好始终使用摘要算法名称。

crypto.createVerify(algorithm[, options])

Added in: v0.1.92

创建一个并返回一个使用给定算法的 Verify 对象。 使用 crypto.getHashes() 获取可用签名算法名称的数组。 可选的 options 参数控制 stream.Writable 的行为。

在某些情况下,可以使用签名算法的名称(例如 'RSA-SHA256')而不是摘要算法的名称来创建一个 Verify 实例。这将使用相应的摘要算法。但这不适用于所有签名算法,例如 'ecdsa-with-SHA256',因此最好始终使用摘要算法名称。

crypto.diffieHellman(options)

新增于:v13.9.0, v12.17.0

基于 privateKeypublicKey 计算 Diffie-Hellman 密钥。两个密钥必须具有相同的 asymmetricKeyType,它必须是 'dh'(用于 Diffie-Hellman)、'ec''x448''x25519'(用于 ECDH)之一。

crypto.fips

新增于:v6.0.0

自 v10.0.0 起已弃用

[稳定性: 0 - 已弃用]

稳定性: 0 稳定性: 0 - 已弃用

用于检查和控制当前是否正在使用符合 FIPS 的加密提供程序的属性。设置为 true 需要 Node.js 的 FIPS 版本。

此属性已弃用。请改用 crypto.setFips()crypto.getFips()

crypto.generateKey(type, options, callback)

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v15.0.0新增于:v15.0.0
  • type: <字符串> 生成的密钥的预期用途。当前接受的值为 'hmac''aes'

  • options: <对象>

    • length: <数字> 要生成的密钥的比特长度。这必须是一个大于 0 的值。
    • 如果 type'hmac',最小值为 8,最大长度为 2-1。如果该值不是 8 的倍数,则生成的密钥将被截断为 Math.floor(length / 8)
    • 如果 type'aes',长度必须为 128192256 之一。
  • callback: <函数>

异步生成给定 length 的新的随机密钥。type 将确定对 length 执行哪些验证。

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

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

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

生成的 HMAC 密钥的大小不应超过底层哈希函数的块大小。有关更多信息,请参阅 crypto.createHmac()

crypto.generateKeyPair(type, options, callback)

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v16.10.0添加了为 RSA-PSS 密钥对定义 RSASSA-PSS-params 序列参数的能力。
v13.9.0, v12.17.0添加对 Diffie-Hellman 的支持。
v12.0.0添加对 RSA-PSS 密钥对的支持。
v12.0.0添加生成 X25519 和 X448 密钥对的能力。
v12.0.0添加生成 Ed25519 和 Ed448 密钥对的能力。
v11.6.0generateKeyPairgenerateKeyPairSync 函数现在如果未指定编码,则会生成密钥对象。
v10.12.0v10.12.0 版本新增

生成给定 type 的新的非对称密钥对。目前支持 RSA、RSA-PSS、DSA、EC、Ed25519、Ed448、X25519、X448 和 DH。

如果指定了 publicKeyEncodingprivateKeyEncoding,则此函数的行为就像在其结果上调用了 keyObject.export() 一样。否则,密钥的相应部分将作为 KeyObject 返回。

建议将公钥编码为 'spki',将私钥编码为带有加密的 'pkcs8' 以进行长期存储:

js
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) => {
    // 处理错误并使用生成的密钥对。
  }
)
js
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) => {
    // 处理错误并使用生成的密钥对。
  }
)

完成后,将使用 err 设置为 undefined 以及表示生成的密钥对的 publicKey / privateKey 调用 callback

如果此方法作为其 util.promisify() 版本调用,它将返回一个 Promise,该 Promise 用于包含 publicKeyprivateKey 属性的 Object

crypto.generateKeyPairSync(type, options)

[历史]

版本变更
v16.10.0添加了为 RSA-PSS 密钥对定义 RSASSA-PSS-params 序列参数的功能。
v13.9.0, v12.17.0添加对 Diffie-Hellman 的支持。
v12.0.0添加对 RSA-PSS 密钥对的支持。
v12.0.0添加生成 X25519 和 X448 密钥对的功能。
v12.0.0添加生成 Ed25519 和 Ed448 密钥对的功能。
v11.6.0generateKeyPairgenerateKeyPairSync 函数现在如果未指定编码,则会生成密钥对象。
v10.12.0v10.12.0 版本中添加

生成给定 type 的新的非对称密钥对。目前支持 RSA、RSA-PSS、DSA、EC、Ed25519、Ed448、X25519、X448 和 DH。

如果指定了 publicKeyEncodingprivateKeyEncoding,则此函数的行为就像在其结果上调用了 keyObject.export() 一样。否则,密钥的相应部分将作为 KeyObject 返回。

编码公钥时,建议使用 'spki'。编码私钥时,建议使用带有强密码的 'pkcs8',并保密密码。

js
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',
  },
})
js
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)

新增于:v15.0.0

  • type: <字符串> 生成的密钥的预期用途。目前接受的值为 'hmac''aes'

  • options: <对象>

    • length: <数字> 要生成的密钥的比特长度。
    • 如果 type'hmac',最小值为 8,最大长度为 2-1。如果该值不是 8 的倍数,则生成的密钥将被截断为 Math.floor(length / 8)
    • 如果 type'aes',长度必须为 128192256 之一。
  • 返回值: <KeyObject>

同步生成给定 length 的新的随机密钥。type 将确定对 length 执行哪些验证。

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

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

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

生成的 HMAC 密钥的大小不应超过底层哈希函数的块大小。有关更多信息,请参见 crypto.createHmac()

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

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v15.8.0新增于:v15.8.0

生成一个大小为 size 比特的伪随机素数。

如果 options.safetrue,则素数将是一个安全素数——也就是说,(prime - 1) / 2 也将是一个素数。

options.addoptions.rem 参数可用于强制执行其他要求,例如,对于 Diffie-Hellman:

  • 如果 options.addoptions.rem 都已设置,则素数将满足 prime % add = rem 的条件。
  • 如果仅设置了 options.addoptions.safe 不是 true,则素数将满足 prime % add = 1 的条件。
  • 如果仅设置了 options.addoptions.safe 设置为 true,则素数将满足 prime % add = 3 的条件。这是必要的,因为对于 options.add > 2prime % add = 1 将与 options.safe 强制执行的条件相矛盾。
  • 如果没有给出 options.add,则忽略 options.rem

如果作为 ArrayBufferSharedArrayBufferTypedArrayBufferDataView 给出,则 options.addoptions.rem 都必须编码为大端序序列。

默认情况下,素数编码为 <ArrayBuffer> 中的八位字节的大端序序列。如果 bigint 选项为 true,则提供 <BigInt>

crypto.generatePrimeSync(size[, options])

新增于:v15.8.0

生成一个size比特的伪随机素数。

如果 options.safetrue,则素数将是一个安全素数——也就是说,(prime - 1) / 2 也将是一个素数。

options.addoptions.rem 参数可用于强制执行其他要求,例如,对于 Diffie-Hellman:

  • 如果同时设置了 options.addoptions.rem,则素数将满足条件 prime % add = rem
  • 如果仅设置了 options.addoptions.safe 不是 true,则素数将满足条件 prime % add = 1
  • 如果仅设置了 options.addoptions.safe 设置为 true,则素数将满足条件 prime % add = 3。这是必要的,因为对于 options.add \> 2prime % add = 1 将与 options.safe 强制执行的条件相矛盾。
  • 如果未给出 options.add,则忽略 options.rem

如果作为 ArrayBufferSharedArrayBufferTypedArrayBufferDataView 给出,则 options.addoptions.rem 都必须以大端序序列进行编码。

默认情况下,素数以大端序的八位字节序列编码为 <ArrayBuffer>。如果 bigint 选项为 true,则提供 <bigint>

crypto.getCipherInfo(nameOrNid[, options])

新增于: v15.0.0

  • nameOrNid: <字符串> | <数字> 要查询的密码的名称或 nid。

  • options: <对象>

  • 返回: <对象>

    • name <字符串> 密码的名称
    • nid <数字> 密码的 nid
    • blockSize <数字> 密码的块大小(以字节为单位)。当 mode'stream' 时,此属性将被省略。
    • ivLength <数字> 预期或默认的初始化向量长度(以字节为单位)。如果密码不使用初始化向量,则此属性将被省略。
    • keyLength <数字> 预期或默认的密钥长度(以字节为单位)。
    • mode <字符串> 密码模式。'cbc', 'ccm', 'cfb', 'ctr', 'ecb', 'gcm', 'ocb', 'ofb', 'stream', 'wrap', 'xts' 之一。

返回关于给定密码的信息。

某些密码接受可变长度的密钥和初始化向量。默认情况下,crypto.getCipherInfo() 方法将返回这些密码的默认值。要测试给定密钥长度或 iv 长度对于给定密码是否可接受,请使用 keyLengthivLength 选项。如果给定的值不可接受,则将返回 undefined

crypto.getCiphers()

Added in: v0.9.3

  • 返回值: <string[]> 一个包含受支持的密码算法名称的数组。
js
const { getCiphers } = await import('node:crypto')

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

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

crypto.getCurves()

Added in: v2.3.0

  • 返回值: <string[]> 一个包含受支持的椭圆曲线的名称的数组。
js
const { getCurves } = await import('node:crypto')

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

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

crypto.getDiffieHellman(groupName)

新增于: v0.7.5

创建一个预定义的 DiffieHellmanGroup 密钥交换对象。支持的组列在DiffieHellmanGroup 的文档中。

返回的对象模仿了由crypto.createDiffieHellman() 创建的对象的接口,但不允许更改密钥(例如,使用diffieHellman.setPublicKey())。使用此方法的优势在于,各方不必预先生成或交换组模数,从而节省了处理器和通信时间。

示例(获取共享密钥):

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

新增于:v10.0.0

  • 返回值: <number> 仅当当前使用符合 FIPS 的加密提供程序时返回 1,否则返回 0。未来的主版本 semver 版本可能会将此 API 的返回类型更改为 <boolean>

crypto.getHashes()

新增于:v0.9.3

  • 返回值: <string[]> 支持的哈希算法名称数组,例如 'RSA-SHA256'。哈希算法也称为“摘要”算法。
js
const { getHashes } = await import('node:crypto')

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

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

crypto.getRandomValues(typedArray)

新增于: v17.4.0

[crypto.webcrypto.getRandomValues()](/zh/api/webcrypto#cryptogetrandomvaluestypedarray) 的便捷别名。此实现不符合 Web Crypto 规范,要编写与 Web 兼容的代码,请改用 crypto.webcrypto.getRandomValues()

crypto.hash(algorithm, data[, outputEncoding])

新增于:v21.7.0, v20.12.0

[稳定性:1 - 实验性]

稳定性:1 稳定性:1.2 - 预发布版本

用于创建数据的一次性哈希摘要的实用程序。当哈希少量(<= 5MB)且 readily available 的数据时,它可能比基于对象的 crypto.createHash() 更快。如果数据可能很大或被流式传输,则仍然建议使用 crypto.createHash()

algorithm 取决于平台上 OpenSSL 版本支持的可用算法。例如 'sha256''sha512' 等。在 OpenSSL 的最新版本中,openssl list -digest-algorithms 将显示可用的摘要算法。

示例:

js
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'))
js
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)

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v18.8.0, v16.18.0输入密钥材料现在可以为零长度。
v15.0.0新增于: v15.0.0

HKDF 是 RFC 5869 中定义的一种简单的密钥派生函数。给定的 ikmsaltinfodigest 一起用于派生 keylen 字节的密钥。

提供的 callback 函数将调用两个参数:errderivedKey。如果在派生密钥时发生错误,则设置 err;否则 errnull。成功生成的 derivedKey 将作为 <ArrayBuffer> 传递给回调函数。如果任何输入参数指定无效值或类型,则会抛出错误。

js
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'
})
js
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)

[历史]

版本变更
v18.8.0, v16.18.0输入密钥材料现在可以为零长度。
v15.0.0新增于:v15.0.0

提供 RFC 5869 中定义的同步 HKDF 密钥派生函数。给定的 ikmsaltinfodigest 一起用于派生 keylen 字节的密钥。

成功生成的 derivedKey 将作为 <ArrayBuffer> 返回。

如果任何输入参数指定无效的值或类型,或者无法生成派生密钥,则会抛出错误。

js
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'
js
const { hkdfSync } = require('node:crypto')
const { Buffer } = require('node:buffer')

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

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

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v15.0.0passwordsalt 参数也可以是 ArrayBuffer 实例。
v14.0.0iterations 参数现在限制为正值。早期版本将其他值视为 1。
v8.0.0digest 参数现在始终是必需的。
v6.0.0现在不传递 digest 参数调用此函数已被弃用,并将发出警告。
v6.0.0如果 password 是字符串,则其默认编码已从 binary 更改为 utf8
v0.5.5在 v0.5.5 中添加

提供异步密码基密钥派生函数 2 (PBKDF2) 实现。由 digest 指定的选定 HMAC 摘要算法用于从 passwordsaltiterations 派生请求字节长度 (keylen) 的密钥。

提供的 callback 函数将用两个参数调用:errderivedKey。如果在派生密钥时发生错误,则设置 err;否则 err 将为 null。默认情况下,成功生成的 derivedKey 将作为 Buffer 传递给回调。如果任何输入参数指定无效的值或类型,则会抛出错误。

iterations 参数必须设置为尽可能高的数字。迭代次数越高,派生的密钥越安全,但完成所需的时间越长。

salt 应尽可能唯一。建议盐是随机的,并且至少 16 字节长。有关详细信息,请参阅 NIST SP 800-132

当为 passwordsalt 传递字符串时,请考虑使用字符串作为加密 API 输入时的注意事项

js
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'
})
js
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)

[历史]

版本变更
v14.0.0iterations 参数现在仅限于正值。早期版本将其他值视为 1。
v6.0.0现在不传递 digest 参数调用此函数已弃用,并将发出警告。
v6.0.0如果 password 是字符串,其默认编码已从 binary 更改为 utf8
v0.9.3v0.9.3 版本中添加

提供同步密码基密钥派生函数 2 (PBKDF2) 实现。digest 指定的选定 HMAC 散列算法用于从 passwordsaltiterations 派生请求字节长度 (keylen) 的密钥。

如果发生错误,将抛出 Error,否则派生的密钥将作为 Buffer 返回。

iterations 参数必须设置为尽可能高的数字。迭代次数越高,派生的密钥越安全,但完成所需的时间也越长。

salt 应尽可能唯一。建议 salt 为随机值,且至少 16 字节长。有关详细信息,请参阅 NIST SP 800-132

当为 passwordsalt 传递字符串时,请考虑 使用字符串作为加密 API 输入时的注意事项

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

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

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

可以使用 crypto.getHashes() 获取支持的散列函数数组。

crypto.privateDecrypt(privateKey, buffer)

[历史]

版本变更
v21.6.2, v20.11.1, v18.19.1除非 OpenSSL 版本支持隐式拒绝,否则 RSA_PKCS1_PADDING 填充将被禁用。
v15.0.0添加字符串、ArrayBuffer 和 CryptoKey 作为允许的密钥类型。oaepLabel 可以是 ArrayBuffer。buffer 可以是字符串或 ArrayBuffer。所有接受 buffer 的类型都限制为最大 2 ** 31 - 1 字节。
v12.11.0添加了 oaepLabel 选项。
v12.9.0添加了 oaepHash 选项。
v11.6.0此函数现在支持密钥对象。
v0.11.14新增于:v0.11.14

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

如果 privateKey 不是 KeyObject,则此函数的行为就像 privateKey 已传递给 crypto.createPrivateKey() 一样。如果它是对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_OAEP_PADDING

crypto.privateDecrypt() 中使用 crypto.constants.RSA_PKCS1_PADDING 需要 OpenSSL 支持隐式拒绝 (rsa_pkcs1_implicit_rejection)。如果 Node.js 使用的 OpenSSL 版本不支持此功能,则尝试使用 RSA_PKCS1_PADDING 将失败。

crypto.privateEncrypt(privateKey, buffer)

[历史记录]

版本变更
v15.0.0添加字符串、ArrayBuffer 和 CryptoKey 作为允许的密钥类型。密码可以是 ArrayBuffer。缓冲区可以是字符串或 ArrayBuffer。所有接受缓冲区的类型都限制为最大 2 ** 31 - 1 字节。
v11.6.0此函数现在支持密钥对象。
v1.1.0新增于:v1.1.0

使用 privateKey 加密 buffer。可以使用对应的公钥解密返回的数据,例如使用 crypto.publicDecrypt()

如果 privateKey 不是 KeyObject,则此函数的行为就像 privateKey 已传递给 crypto.createPrivateKey() 一样。如果它是对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_PADDING

crypto.publicDecrypt(key, buffer)

[历史]

版本变更
v15.0.0添加字符串、ArrayBuffer 和 CryptoKey 作为允许的密钥类型。密码可以是 ArrayBuffer。缓冲区可以是字符串或 ArrayBuffer。所有接受缓冲区的类型都限制为最大 2 ** 31 - 1 字节。
v11.6.0此函数现在支持密钥对象。
v1.1.0v1.1.0 版本中添加

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

如果 key 不是 KeyObject,则此函数的行为就像 key 已传递给 crypto.createPublicKey() 一样。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_PADDING

因为 RSA 公钥可以从私钥派生,所以可以传递私钥而不是公钥。

crypto.publicEncrypt(key, buffer)

[历史]

版本变更
v15.0.0新增字符串、ArrayBuffer 和 CryptoKey 作为允许的密钥类型。oaepLabel 和 passphrase 可以是 ArrayBuffer。buffer 可以是字符串或 ArrayBuffer。所有接受 buffer 的类型都限制为最大 2 ** 31 - 1 字节。
v12.11.0添加了 oaepLabel 选项。
v12.9.0添加了 oaepHash 选项。
v11.6.0此函数现在支持密钥对象。
v0.11.14添加于:v0.11.14

使用 key 加密 buffer 的内容,并返回一个包含加密内容的新 Buffer。可以使用相应的私钥解密返回的数据,例如使用 crypto.privateDecrypt()

如果 key 不是 KeyObject,则此函数的行为如同将 key 传递给 crypto.createPublicKey() 一样。如果它是对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_OAEP_PADDING

因为 RSA 公钥可以从私钥推导出来,所以可以传递私钥而不是公钥。

crypto.randomBytes(size[, callback])

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v9.0.0null 作为 callback 参数传递现在抛出 ERR_INVALID_CALLBACK
v0.5.8v0.5.8 版本中添加

生成密码学安全的伪随机数据。size 参数是一个数字,指示要生成的字节数。

如果提供了 callback 函数,则异步生成字节,并使用两个参数调用 callback 函数:errbuf。如果发生错误,err 将是一个 Error 对象;否则为 nullbuf 参数是一个包含生成的字节的 Buffer

js
// 异步
const { randomBytes } = await import('node:crypto')

randomBytes(256, (err, buf) => {
  if (err) throw err
  console.log(`${buf.length} 字节的随机数据: ${buf.toString('hex')}`)
})
js
// 异步
const { randomBytes } = require('node:crypto')

randomBytes(256, (err, buf) => {
  if (err) throw err
  console.log(`${buf.length} 字节的随机数据: ${buf.toString('hex')}`)
})

如果未提供 callback 函数,则同步生成随机字节并将其作为 Buffer 返回。如果生成字节时出现问题,则会抛出错误。

js
// 同步
const { randomBytes } = await import('node:crypto')

const buf = randomBytes(256)
console.log(`${buf.length} 字节的随机数据: ${buf.toString('hex')}`)
js
// 同步
const { randomBytes } = require('node:crypto')

const buf = randomBytes(256)
console.log(`${buf.length} 字节的随机数据: ${buf.toString('hex')}`)

crypto.randomBytes() 方法只有在有足够的熵可用时才会完成。这通常不应该花费超过几毫秒的时间。只有在启动后立即,整个系统熵仍然很低时,生成随机字节才有可能阻塞更长的时间。

此 API 使用 libuv 的线程池,这可能会对某些应用程序产生令人惊讶的负面性能影响;有关更多信息,请参阅 UV_THREADPOOL_SIZE 文档。

crypto.randomBytes() 的异步版本在一个线程池请求中执行。为了最大限度地减少线程池任务长度的变化,在将此作为满足客户端请求的一部分时,请对大型 randomBytes 请求进行分区。

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

[历史]

版本变更
v18.0.0将无效的回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v9.0.0buffer 参数可以是任何 TypedArrayDataView
v7.10.0, v6.13.0新增于:v7.10.0, v6.13.0

此函数类似于 crypto.randomBytes(),但要求第一个参数为一个将被填充的 Buffer。它也要求传入一个回调函数。

如果未提供 callback 函数,则会抛出错误。

js
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'))
})
js
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'))
})

任何 ArrayBufferTypedArrayDataView 实例都可以作为 buffer 传递。

虽然这包括 Float32ArrayFloat64Array 实例,但不应使用此函数生成随机浮点数。结果可能包含 +Infinity-InfinityNaN,即使数组仅包含有限数字,它们也不是从均匀随机分布中抽取的,也没有有意义的下限或上限。

js
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'))
})
js
const { randomFill } = require('node:crypto')
const { Buffer } = require('node:buffer')

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

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

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

此 API 使用 libuv 的线程池,这可能会对某些应用程序产生令人惊讶的负面性能影响;有关更多信息,请参阅 UV_THREADPOOL_SIZE 文档。

crypto.randomFill() 的异步版本在一个线程池请求中执行。为了最大限度地减少线程池任务长度的变化,在将此作为满足客户端请求的一部分时,请对大型 randomFill 请求进行分区。

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

[历史]

版本变更
v9.0.0buffer 参数可以是任何 TypedArrayDataView
v7.10.0, v6.13.0添加于:v7.10.0, v6.13.0

crypto.randomFill() 的同步版本。

js
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'))
js
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'))

任何 ArrayBufferTypedArrayDataView 实例都可以作为 buffer 传递。

js
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'))
js
const { randomFillSync } = require('node:crypto')
const { Buffer } = require('node:buffer')

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

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

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

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

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v14.10.0, v12.19.0新增于:v14.10.0, v12.19.0
  • min <整数> 随机范围的开始(包含)。默认值: 0
  • max <整数> 随机范围的结束(不包含)。
  • callback <函数> function(err, n) {}

返回一个随机整数 n,使得 min <= n < max。此实现避免了 模偏差

范围 (max - min) 必须小于 2。minmax 必须是 安全整数

如果未提供 callback 函数,则同步生成随机整数。

js
// 异步
const { randomInt } = await import('node:crypto')

randomInt(3, (err, n) => {
  if (err) throw err
  console.log(`从 (0, 1, 2) 中选择的随机数:${n}`)
})
js
// 异步
const { randomInt } = require('node:crypto')

randomInt(3, (err, n) => {
  if (err) throw err
  console.log(`从 (0, 1, 2) 中选择的随机数:${n}`)
})
js
// 同步
const { randomInt } = await import('node:crypto')

const n = randomInt(3)
console.log(`从 (0, 1, 2) 中选择的随机数:${n}`)
js
// 同步
const { randomInt } = require('node:crypto')

const n = randomInt(3)
console.log(`从 (0, 1, 2) 中选择的随机数:${n}`)
js
// 使用 `min` 参数
const { randomInt } = await import('node:crypto')

const n = randomInt(1, 7)
console.log(`骰子掷出的点数:${n}`)
js
// 使用 `min` 参数
const { randomInt } = require('node:crypto')

const n = randomInt(1, 7)
console.log(`骰子掷出的点数:${n}`)

crypto.randomUUID([options])

新增于:v15.6.0, v14.17.0

  • options <Object>

    • disableEntropyCache <boolean> 默认情况下,为了提高性能,Node.js 会生成并缓存足够多的随机数据以生成最多 128 个随机 UUID。要生成不使用缓存的 UUID,请将 disableEntropyCache 设置为 true默认值:false
  • 返回值:<string>

生成一个随机的 RFC 4122 版本 4 UUID。UUID 使用密码学伪随机数生成器生成。

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

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v15.0.0密码和盐参数也可以是 ArrayBuffer 实例。
v12.8.0, v10.17.0maxmem 值现在可以是任何安全整数。
v10.9.0已添加 costblockSizeparallelization 选项名称。
v10.5.0新增于:v10.5.0

提供一个异步的 scrypt 实现。Scrypt 是一种基于密码的密钥派生函数,旨在在计算和内存方面代价高昂,以使暴力攻击得不偿失。

salt 应该尽可能唯一。建议盐是随机的,并且至少 16 字节长。有关详细信息,请参阅 NIST SP 800-132

当为 passwordsalt 传递字符串时,请考虑 将字符串用作加密 API 输入时的注意事项

callback 函数使用两个参数调用:errderivedKey。当密钥派生失败时,err 是一个异常对象,否则 errnullderivedKey 作为 Buffer 传递给回调函数。

当任何输入参数指定无效值或类型时,都会抛出异常。

js
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'
})
js
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(password, salt, keylen[, options])

[历史]

版本变更
v12.8.0, v10.17.0maxmem 值现在可以是任何安全整数。
v10.9.0添加了 costblockSizeparallelization 选项名称。
v10.5.0v10.5.0 版本中添加

提供同步的 scrypt 实现。Scrypt 是一种基于密码的密钥派生函数,旨在在计算和内存方面成本高昂,以使暴力攻击得不偿失。

salt 应尽可能唯一。建议盐是随机的,并且至少 16 字节长。详情请参见 NIST SP 800-132

当为 passwordsalt 传递字符串时,请考虑 将字符串作为输入传递给加密 API 时的注意事项

密钥派生失败时会抛出异常,否则派生的密钥将作为 Buffer 返回。

当任何输入参数指定无效值或类型时,都会抛出异常。

js
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'
js
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'

crypto.secureHeapUsed()

新增于:v15.6.0

  • 返回值: <对象>
    • total <数字> 使用 --secure-heap=n 命令行标志指定的已分配安全堆的总大小。
    • min <数字> 使用 --secure-heap-min 命令行标志指定的来自安全堆的最小分配量。
    • used <数字> 当前从安全堆分配的总字节数。
    • utilization <数字> 计算出的已使用字节数与已分配总字节数的比率。

crypto.setEngine(engine[, flags])

[历史]

版本变更
v22.4.0, v20.16.0OpenSSL 3 中的自定义引擎支持已弃用。
v0.11.11新增于:v0.11.11

加载并设置某些或所有 OpenSSL 函数的 engine(由 flags 选择)。从 OpenSSL 3 开始,对 OpenSSL 中自定义引擎的支持已弃用。

engine 可以是引擎的共享库的 ID 或路径。

可选的 flags 参数默认使用 ENGINE_METHOD_ALLflags 是一个位字段,可以取以下标志之一或多种组合(在 crypto.constants 中定义):

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

crypto.setFips(bool)

新增于: v10.0.0

  • bool <boolean> 设置为 true 以启用 FIPS 模式。

在启用了 FIPS 的 Node.js 版本中启用符合 FIPS 的加密提供程序。如果 FIPS 模式不可用,则抛出错误。

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

[历史记录]

版本变更
v18.0.0将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v15.12.0添加了可选的回调参数。
v13.2.0, v12.16.0此函数现在支持 IEEE-P1363 DSA 和 ECDSA 签名。
v12.0.0新增于: v12.0.0

使用给定的私钥和算法计算并返回 data 的签名。如果 algorithmnullundefined,则算法取决于密钥类型(尤其是 Ed25519 和 Ed448)。

如果 key 不是 KeyObject,则此函数的行为就像 key 已传递给 crypto.createPrivateKey() 一样。如果它是一个对象,则可以传递以下附加属性:

  • dsaEncoding <string> 对于 DSA 和 ECDSA,此选项指定生成的签名的格式。它可以是以下之一:

    • 'der' (默认): DER 编码的 ASN.1 签名结构编码 (r, s)
    • 'ieee-p1363': 如 IEEE-P1363 中所建议的签名格式 r || s
  • padding <integer> RSA 的可选填充值,以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (默认)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

RSA_PKCS1_PSS_PADDING 将使用与用于签名消息的散列函数相同的 MGF1,如 RFC 4055 的第 3.1 节中所述。

  • saltLength <integer> 当填充为 RSA_PKCS1_PSS_PADDING 时的盐长度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN (默认) 将其设置为最大允许值。

如果提供了 callback 函数,则此函数使用 libuv 的线程池。

crypto.subtle

新增于:v17.4.0

crypto.webcrypto.subtle 的便捷别名 <SubtleCrypto>

crypto.timingSafeEqual(a, b)

[历史]

版本变更
v15.0.0ab 参数也可以是 ArrayBuffer
v6.6.0新增于:v6.6.0

此函数使用恒定时间算法比较表示给定 ArrayBufferTypedArrayDataView 实例的底层字节。

此函数不会泄漏时间信息,这些信息会允许攻击者猜测其中一个值。这适用于比较 HMAC 散列或秘密值,例如身份验证 Cookie 或 capability urls

ab 必须都是 BufferTypedArrayDataView,并且它们必须具有相同的字节长度。如果 ab 的字节长度不同,则会抛出错误。

如果 ab 中至少一个是每项超过一个字节的 TypedArray(例如 Uint16Array),则结果将使用平台字节序计算。

当两个输入都是Float32ArrayFloat64Array时,由于浮点数的 IEEE 754 编码,此函数可能会返回意外的结果。特别是,x === yObject.is(x, y)都不能意味着两个浮点数xy的字节表示是相等的。

使用 crypto.timingSafeEqual 并不能保证周围的代码是时间安全的。应注意确保周围的代码不会引入时间漏洞。

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

[历史]

版本变更
v18.0.0将无效回调传递给 callback 参数现在会抛出 ERR_INVALID_ARG_TYPE 而不是 ERR_INVALID_CALLBACK
v15.12.0添加了可选的回调参数。
v15.0.0data、key 和 signature 参数也可以是 ArrayBuffer。
v13.2.0, v12.16.0此函数现在支持 IEEE-P1363 DSA 和 ECDSA 签名。
v12.0.0新增于:v12.0.0

使用给定的密钥和算法验证给定数据的签名。如果 algorithmnullundefined,则算法取决于密钥类型(尤其是 Ed25519 和 Ed448)。

如果 key 不是 KeyObject,则此函数的行为就好像 key 已传递给 crypto.createPublicKey() 一样。如果它是一个对象,则可以传递以下附加属性:

  • dsaEncoding <字符串> 对于 DSA 和 ECDSA,此选项指定签名的格式。它可以是以下之一:

    • 'der' (默认): DER 编码的 ASN.1 签名结构编码 (r, s)
    • 'ieee-p1363': 签名格式 r || s,如 IEEE-P1363 中所述。
  • padding <整数> RSA 的可选填充值,以下之一:

    • crypto.constants.RSA_PKCS1_PADDING (默认)
    • crypto.constants.RSA_PKCS1_PSS_PADDING

RSA_PKCS1_PSS_PADDING 将使用 MGF1 和与用于签署消息的哈希函数相同的函数,如 RFC 4055 的第 3.1 节中所述。

  • saltLength <整数> 当填充为 RSA_PKCS1_PSS_PADDING 时的盐长度。特殊值 crypto.constants.RSA_PSS_SALTLEN_DIGEST 将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN (默认) 将其设置为最大允许值。

signature 参数是先前为 data 计算的签名。

因为公钥可以从私钥派生,所以可以为 key 传递私钥或公钥。

如果提供了 callback 函数,则此函数使用 libuv 的线程池。

crypto.webcrypto

新增于:v15.0.0

类型: <Crypto> Web Crypto API 标准的实现。

详情请参阅 Web Crypto API 文档

注意

将字符串作为输入传递给加密 API

由于历史原因,Node.js 提供的许多加密 API 接受字符串作为输入,而底层加密算法则使用字节序列进行操作。这些实例包括明文、密文、对称密钥、初始化向量、密码、盐、身份验证标签和附加身份验证数据。

将字符串传递给加密 API 时,请考虑以下因素。

  • 并非所有字节序列都是有效的 UTF-8 字符串。因此,当从长度为 n 的字符串派生字节序列时,其熵通常低于随机或伪随机 n 字节序列的熵。例如,没有 UTF-8 字符串会产生字节序列 c0 af。密钥几乎应该完全是随机或伪随机字节序列。
  • 类似地,当将随机或伪随机字节序列转换为 UTF-8 字符串时,不表示有效代码点的子序列可能会被 Unicode 替换字符(U+FFFD)替换。因此,生成的 Unicode 字符串的字节表示可能不等于创建该字符串的字节序列。密码、哈希函数、签名算法和密钥派生函数的输出是伪随机字节序列,不应作为 Unicode 字符串使用。
  • 当从用户输入获取字符串时,某些 Unicode 字符可以用多种等效方式表示,从而产生不同的字节序列。例如,将用户密码传递给密钥派生函数(例如 PBKDF2 或 scrypt)时,密钥派生函数的结果取决于字符串是否使用组合字符或分解字符。Node.js 不会规范化字符表示。在将用户输入传递给加密 API 之前,开发人员应考虑使用 String.prototype.normalize()

旧版流 API(Node.js 0.10 之前)

Crypto 模块是在 Node.js 统一流 API 概念出现之前以及用于处理二进制数据的 Buffer 对象出现之前添加的。因此,许多 crypto 类具有在实现 API 的其他 Node.js 类中通常找不到的方法(例如 update()final()digest())。此外,许多方法默认情况下接受并返回 'latin1' 编码的字符串而不是 Buffer。此默认值在 Node.js v0.8 之后更改为默认情况下使用 Buffer 对象。

对弱或已损坏算法的支持

node:crypto 模块仍然支持一些已经遭到破坏且不建议使用的算法。该 API 还允许使用密钥大小过小、安全性不足的密码和哈希算法。

用户应根据其安全需求对选择加密算法和密钥大小承担全部责任。

根据 NIST SP 800-131A 的建议:

  • 在需要抗碰撞性的地方(例如数字签名)不再接受 MD5 和 SHA-1。
  • 建议 RSA、DSA 和 DH 算法使用的密钥至少为 2048 位,ECDSA 和 ECDH 的曲线密钥至少为 224 位,才能确保在未来几年内安全使用。
  • modp1modp2modp5 的 DH 组密钥大小小于 2048 位,不建议使用。

有关其他建议和详细信息,请参阅参考文档。

一些已知存在弱点且在实践中几乎没有意义的算法只能通过 旧版提供程序 使用,该提供程序默认情况下未启用。

CCM 模式

CCM 是受支持的AEAD 算法之一。使用此模式的应用程序在使用密码 API 时必须遵守某些限制:

  • 必须在密码创建期间通过设置 authTagLength 选项来指定身份验证标签长度,并且必须为 4、6、8、10、12、14 或 16 字节之一。
  • 初始化向量 (nonce) N 的长度必须在 7 到 13 字节之间 (7 ≤ N ≤ 13)。
  • 明文长度限制为 2 ** (8 * (15 - N)) 字节。
  • 解密时,必须在调用 update() 之前通过 setAuthTag() 设置身份验证标签。否则,解密将失败,并且 final() 将根据 RFC 3610 的 2.6 节抛出错误。
  • 在 CCM 模式下使用流方法(例如 write(data)end(data)pipe())可能会失败,因为 CCM 每个实例只能处理一个数据块。
  • 当传递附加的已验证数据 (AAD) 时,必须通过 plaintextLength 选项将实际消息的长度(以字节为单位)传递给 setAAD()。许多加密库将身份验证标签包含在密文中,这意味着它们生成的密文长度为 plaintextLength + authTagLength。Node.js 不包含身份验证标签,因此密文长度始终为 plaintextLength。如果未使用 AAD,则不需要此操作。
  • 由于 CCM 同时处理整个消息,因此必须准确调用一次 update()
  • 即使调用 update() 足以加密/解密消息,应用程序也必须调用 final() 来计算或验证身份验证标签。
js
import { Buffer } from 'node:buffer'
const { createCipheriv, createDecipheriv, randomBytes } = await import('node:crypto')

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

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

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

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

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

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

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

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

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

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

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

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

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

console.log(receivedPlaintext)

FIPS 模式

使用 OpenSSL 3 时,Node.js 在与合适的 OpenSSL 3 提供程序(例如 OpenSSL 3 的 FIPS 提供程序)一起使用时支持 FIPS 140-2,该提供程序可按照 OpenSSL 的 FIPS 自述文件中的说明安装。

要在 Node.js 中获得 FIPS 支持,您需要:

  • 正确安装的 OpenSSL 3 FIPS 提供程序。
  • OpenSSL 3 FIPS 模块配置文件
  • 一个引用 FIPS 模块配置文件的 OpenSSL 3 配置文件。

Node.js 需要使用指向 FIPS 提供程序的 OpenSSL 配置文件进行配置。一个示例配置文件如下所示:

text
nodejs_conf = nodejs_init

.include /<absolute path>/fipsmodule.cnf

[nodejs_init]
providers = provider_sect

[provider_sect]
default = default_sect
# fips 部分名称应与包含的 fipsmodule.cnf 内部的部分名称匹配。 {#the-fips-section-name-should-match-the-section-name-inside-the}
fips = fips_sect

[default_sect]
activate = 1

其中 fipsmodule.cnf 是从 FIPS 提供程序安装步骤生成的 FIPS 模块配置文件:

bash
openssl fipsinstall

设置 OPENSSL_CONF 环境变量以指向您的配置文件,并将 OPENSSL_MODULES 设置为 FIPS 提供程序动态库的位置。例如:

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

然后可以通过以下方法在 Node.js 中启用 FIPS 模式:

  • 使用 --enable-fips--force-fips 命令行标志启动 Node.js。
  • 以编程方式调用 crypto.setFips(true)

或者,可以通过 OpenSSL 配置文件在 Node.js 中启用 FIPS 模式。例如:

text
nodejs_conf = nodejs_init

.include /<absolute path>/fipsmodule.cnf

[nodejs_init]
providers = provider_sect
alg_section = algorithm_sect

[provider_sect]
default = default_sect
# fips 部分名称应与包含的 fipsmodule.cnf 内部的部分名称匹配。 {#included-fipsmodulecnf}
fips = fips_sect

[default_sect]
activate = 1

[algorithm_sect]
default_properties = fips=yes

加密常量

crypto.constants导出的以下常量适用于node:cryptonode:tlsnode:https模块的各种用途,通常特定于 OpenSSL。

OpenSSL 选项

有关详细信息,请参阅SSL OP 标志列表

常量描述
SSL_OP_ALL在 OpenSSL 中应用多个 bug 修复程序。详情请参见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 based 密钥交换模式
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 禁用版本回滚攻击检测。

OpenSSL 引擎常量

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

其他 OpenSSL 常量

常量描述
DH_CHECK_P_NOT_SAFE_PRIME
DH_CHECK_P_NOT_PRIME
DH_UNABLE_TO_CHECK_GENERATOR
DH_NOT_SUITABLE_GENERATOR
RSA_PKCS1_PADDING
RSA_SSLV23_PADDING
RSA_NO_PADDING
RSA_PKCS1_OAEP_PADDING
RSA_X931_PADDING
RSA_PKCS1_PSS_PADDING
RSA_PSS_SALTLEN_DIGEST在签名或验证时,将 RSA_PKCS1_PSS_PADDING 的盐长度设置为摘要大小。
RSA_PSS_SALTLEN_MAX_SIGN在签名数据时,将 RSA_PKCS1_PSS_PADDING 的盐长度设置为最大允许值。
RSA_PSS_SALTLEN_AUTO在验证签名时,自动确定 RSA_PKCS1_PSS_PADDING 的盐长度。
POINT_CONVERSION_COMPRESSED
POINT_CONVERSION_UNCOMPRESSED
POINT_CONVERSION_HYBRID

Node.js 加密常量

常量描述
defaultCoreCipherList指定 Node.js 使用的内置默认密码列表。
defaultCipherList指定当前 Node.js 进程使用的活动默认密码列表。