在 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.publicEncrypt
和crypto.privateDecrypt
这是未来的文档 https://github.com/joyent/node/blob/7c0419730b237dbfa0ec4e6fb33a99ff01825a8f/doc/api/crypto.markdown#cryptopublicencryptpublic_key-buffer
【讨论】:
更新时间(没有“更新:”,“编辑:”等)?以上是关于在 Node.js 中使用公钥加密数据的主要内容,如果未能解决你的问题,请参考以下文章
windows server+express+node.js配置https