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

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

我正在加载 .pem 文件:

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

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

【问题讨论】:

    标签: node.js public-key-encryption encryption-asymmetric


    【解决方案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
    

    【讨论】:

    【解决方案4】:

    【讨论】:

    • 也许我需要更熟悉 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

    细分:

    不是加密库

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

    【讨论】:

    • 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

    【讨论】:

    • 更新时间(没有“更新:”,“编辑:”等)?
    猜你喜欢
    • 2011-12-08
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    相关资源
    最近更新 更多