在 Node.js 中使用公钥加密数据

Posted

技术标签:

【中文标题】在 Node.js 中使用公钥加密数据【英文标题】:Encrypting data with a public key in Node.js 【发布时间】:2012-02-03 18:23:06 【问题描述】:

我需要使用公钥(.pem 文件)加密字符串,然后使用私钥(也是 .pem)对其进行签名。

我正在加载 .pem 文件:

publicCert = fs.readFileSync(publicCertFile).toString();

但经过数小时的 Google 搜索后,我似乎找不到使用公钥加密数据的方法。在 php 中,我只是调用 openssl_public_encrypt(),但在 Node.js 或任何模块中都看不到任何相应的函数。

【问题讨论】:

【参考方案1】:

库不是必需的。输入crypto。

这是一个 janky 小模块,您可以使用 RSA 密钥来加密/解密字符串:

var crypto = require("crypto");
var path = require("path");
var fs = require("fs");

var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) 
    var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
    var publicKey = fs.readFileSync(absolutePath, "utf8");
    var buffer = Buffer.from(toEncrypt);
    var encrypted = crypto.publicEncrypt(publicKey, buffer);
    return encrypted.toString("base64");
;

var decryptStringWithRsaPrivateKey = function(toDecrypt, relativeOrAbsolutePathtoPrivateKey) 
    var absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey);
    var privateKey = fs.readFileSync(absolutePath, "utf8");
    var buffer = Buffer.from(toDecrypt, "base64");
    var decrypted = crypto.privateDecrypt(privateKey, buffer);
    return decrypted.toString("utf8");
;

module.exports = 
    encryptStringWithRsaPublicKey: encryptStringWithRsaPublicKey,
    decryptStringWithRsaPrivateKey: decryptStringWithRsaPrivateKey

我建议尽可能不要使用同步 fs 方法,您可以使用promises 来改善这一点,但对于简单的用例,这是我见过的可行的方法,并且会采用.

【讨论】:

值得一提的是,您只能使用公钥加密少量(最多 245 字节)数据,而对于大量数据,您应该使用 AES256 和使用公私对加密的私钥。看到这个答案:security.stackexchange.com/questions/33434/… "crypto.publicEncrypt" 在 node.js 中不起作用,与 'crypto' 中的许多功能相同 Amazing :D 还有一件事,密钥文件应该是 .pem 格式:openssl rsa -in ~/.ssh/id_rsa -outform pem > id_rsa.pem 如果我在 .der 文件中有密钥怎么办? 如果 privateKey 是 enocder 并使用密码加密怎么办?我找不到 crypto.privateDecrypt() 的正确方法调用【参考方案2】:

我在 Node.js 10 中对此进行了测试,您可以使用加密/解密函数(Jacob's answer 上的小改动):

const crypto = require('crypto')
const path = require('path')
const fs = require('fs')

function encrypt(toEncrypt, relativeOrAbsolutePathToPublicKey) 
  const absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey)
  const publicKey = fs.readFileSync(absolutePath, 'utf8')
  const buffer = Buffer.from(toEncrypt, 'utf8')
  const encrypted = crypto.publicEncrypt(publicKey, buffer)
  return encrypted.toString('base64')


function decrypt(toDecrypt, relativeOrAbsolutePathtoPrivateKey) 
  const absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey)
  const privateKey = fs.readFileSync(absolutePath, 'utf8')
  const buffer = Buffer.from(toDecrypt, 'base64')
  const decrypted = crypto.privateDecrypt(
    
      key: privateKey.toString(),
      passphrase: '',
    ,
    buffer,
  )
  return decrypted.toString('utf8')


const enc = encrypt('hello', `public.pem`)
console.log('enc', enc)

const dec = decrypt(enc, `private.pem`)
console.log('dec', dec)

对于密钥,您可以使用它们生成它们

const  writeFileSync  = require('fs')
const  generateKeyPairSync  = require('crypto')

function generateKeys() 
  const  privateKey, publicKey  = generateKeyPairSync('rsa', 
    modulusLength: 4096,
    publicKeyEncoding: 
      type: 'pkcs1',
      format: 'pem',
    ,
    privateKeyEncoding: 
      type: 'pkcs1',
      format: 'pem',
      cipher: 'aes-256-cbc',
      passphrase: '',
    ,
  )

  writeFileSync('private.pem', privateKey)
  writeFileSync('public.pem', publicKey)

【讨论】:

我花了好几天的时间,但我终于找到了一个解释,为什么这在俄语中不起作用,所以我想在这里补充一点 qaru.site/questions/16043509/… 它声明 publicEncrypt 使用 openssl,它只是 RSA,所以不使用 crypto.createECDH secp384r1 将在 publicEncrypt 中导致“unhandledRejection Error:error:0906D06C:PEMroutines:PEM_read_bio:no start line”错误有什么建议如何使用更高位的椭圆密钥?还指出 Chrome 也不会与 EC 一起使用 512。这是从 nodejs 11.6 nodejs.org/api/crypto.html 此外,当尝试从节点加密到浏览器时,需要在浏览器中生成密钥,并将公钥导入节点。 感谢您的回答,这教会了我如何使用 JSON 对象将“密码”传递给 privateDecrypt 函数。【参考方案3】:

更新的公共/私人解密和加密模块是URSA。 node-rsa 模块已经过时了。

这个 Node 模块为 OpenSSL 的 RSA 公钥/私钥加密功能。

npm install ursa

【讨论】:

Ursa 已经有一段时间没有维护了。这些较新的实现可能会有所帮助:github.com/tracker1/cryptico-js 和 github.com/rzcoder/node-rsa【参考方案4】:

使用node-rsa module。这是test.js file that demonstrates usage的链接。

【讨论】:

也许我需要更熟悉 RSA 加密。我阅读了十几次关于加密的文档,试图了解如何做我需要的事情,但我没有找到任何东西。你说 createCipheriv() 会做我需要的,但我什至不知道“iv”是什么。我猜是因为它在 PHP 和其他语言中更加抽象。我会尝试一下这个功能,看看我能不能让它工作。 在阅读了有关 createCipheriv 的更多信息后,它看起来不是非对称加密(公钥/私钥加密)。我不认为它会满足我的需求。 Crypto 确实能够使用私钥对加密字符串进行签名,这让我想知道为什么我不能使用公钥进行加密。看起来很奇怪,否则我完全错过了一些东西。 iv 是一个初始化向量。 en.wikipedia.org/wiki/Initialization_vector 我没有看到您编辑了答案。这实际上看起来可能会完成这项工作!我会测试一下看看。【参考方案5】:

TL;DR:URSA 是您的最佳选择。 Node.js 的 crypto 没有标准,这真的很时髦。

我发现的所有其他解决方案要么在 Windows 中不起作用,要么实际上不是加密库。 URSA,recommended by Louie,看起来是最好的选择。如果你不关心 Windows,你就更金了。

关于 Ursa 的注意事项:我必须安装 OpenSSL 以及名为“Visual C++ 2008 Redistributables”的东西才能让 npm install 工作。在这里获取垃圾:http://slproweb.com/products/Win32OpenSSL.html

细分:

Windows 的额外手动安装步骤烦人 https://github.com/Obvious/ursa - 可能是最好的了 与 Windows 不兼容 https://npmjs.org/package/rsautl - BADPLATFORM 说 https://github.com/katyo/node-rsa - node-waf 在 Windows 上不可用 https://github.com/paspao/simple_rsa_encrypt - unistd.h 不在 Windows 上 https://npmjs.org/package/pripub - 大量链接器错误,GitHub 上也没有

不是加密库

https://github.com/substack/secure-peer https://github.com/substack/rsa-json - 只生成密钥,但不使用它们 https://github.com/substack/rsa-unpack - 解压 PEM 字符串

这就是我能找到的所有东西。

【讨论】:

node-rsa 不再依赖 node-waf。它与浏览器兼容。【参考方案6】:

Node.js 版本 v0.11.13 或更低版本本身不支持此功能,但似乎下一版本的 Node.js(又名 v0.12)将支持此功能。

这是线索:https://github.com/joyent/node/blob/v0.12/lib/crypto.js#L358

crypto.publicEncryptcrypto.privateDecrypt

这是未来的文档 https://github.com/joyent/node/blob/7c0419730b237dbfa0ec4e6fb33a99ff01825a8f/doc/api/crypto.markdown#cryptopublicencryptpublic_key-buffer

【讨论】:

更新时间(没有“更新:”,“编辑:”等)?

以上是关于在 Node.js 中使用公钥加密数据的主要内容,如果未能解决你的问题,请参考以下文章

Nodejs 使用node-rsa 加密数据

windows server+express+node.js配置https

RSA Java 加密和 Node.js 解密不起作用

Node.js 和 webcrypto 之间的 RSA 加密

非对称加密中,公钥在啥情况下用于加密,啥情况用于解密?

使用非对称加密保护文件