NodeJS 为签名和验证消息生成有效的 PEM 密钥

Posted

技术标签:

【中文标题】NodeJS 为签名和验证消息生成有效的 PEM 密钥【英文标题】:NodeJS Generate Valid PEM keys for Signing and Verifying messages 【发布时间】:2019-01-27 07:06:50 【问题描述】:

上下文

来自关于 Node v10.9.0 (2018-AUG) 的 TLS/SSL 的 NodeJS 文档

https://nodejs.org/api/tls.html#tls_tls_ssl_concepts

openssl genrsa -out ryans-key.pem 2048

将产生:

-----BEGIN RSA PRIVATE KEY-----
base64 encoded magic here...
-----END RSA PRIVATE KEY-----

然后我可以成功地使用Sign 类对消息进行加密签名:

https://nodejs.org/api/crypto.html#crypto_class_sign

const crypto = require('crypto');
const sign = crypto.createSign('RSA-SHA256');

sign.update('some data to sign');

const privateKey = `Insert magic value from above`;
console.log(sign.sign(privateKey, 'base64'));

我尝试了以下方法但没有成功:

const crypto = require('crypto');
const dhke = crypto.createDiffieHellman(2048);
dhke.generateKeys();
const private_pem = `-----BEGIN RSA PRIVATE KEY-----
$dhke.getPrivateKey('base64')
-----END RSA PRIVATE KEY-----`;
console.log(private_pem);

const sign = crypto.createSign('RSA-SHA256');
sign.update('some data to sign');

const signature = sign.sign(private_pem, 'base64');
console.log(signature);

得到以下错误:

Error: error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long
    at Sign.sign (internal/crypto/sig.js:84:26)
...

问题

如何使用 NodeJS 中的 crypto 库来实现 openssl 命令行工具正在执行的操作(或另一个 NPM 模块)以创建 @987654334 所需的有效 PEM 格式的公钥/私钥对@班级?

类似的未解决问题

Generate Key for signing within nodejs

解决方案

感谢来自JacobTDC 的the accepted answer,NodeJS v10.12.0 添加了此功能,这是一个开始到结束的工作解决方案。

const crypto = require('crypto'); const sign = crypto.createSign('RSA-SHA256');

sign.update('some data to sign');

// $ openssl genrsa -out ryans-key.pem 2048 
// const privateKey = `Insert magic value from above`;

const  generateKeyPairSync  = require('crypto'); 
const  publicKey, privateKey  = generateKeyPairSync('rsa', 
   modulusLength: 2048,  // the length of your key in bits   
    publicKeyEncoding: 
      type: 'spki',       // recommended to be 'spki' by the Node.js docs
      format: 'pem'   
    ,   
    privateKeyEncoding: 
      type: 'pkcs8',      // recommended to be 'pkcs8' by the Node.js docs
      format: 'pem',
      //cipher: 'aes-256-cbc',   // *optional*
      //passphrase: 'top secret' // *optional*   
   
); 
console.log(privateKey); 
console.log(sign.sign(privateKey, 'base64'));

【问题讨论】:

我想知道这是否可以进一步扩展以使用纯节点生成自签名证书? 【参考方案1】:

从 Node.js v10.12.0 开始,您可以使用 crypto.generateKeyPair 和 crypto.generateKeyPairSync。

我在下面的 Node.js 文档中提供了一个示例(添加了 cmets):

const  generateKeyPairSync  = require('crypto');
const  publicKey, privateKey  = generateKeyPairSync('rsa', 
  modulusLength: 4096,  // the length of your key in bits
  publicKeyEncoding: 
    type: 'spki',       // recommended to be 'spki' by the Node.js docs
    format: 'pem'
  ,
  privateKeyEncoding: 
    type: 'pkcs8',      // recommended to be 'pkcs8' by the Node.js docs
    format: 'pem',
    cipher: 'aes-256-cbc',   // *optional*
    passphrase: 'top secret' // *optional*
  
);

【讨论】:

【参考方案2】:

这里的问题是 DH 密钥不是 RSA 密钥并且不完全兼容。

不幸的是,node 没有能力通过crypto 模块生成真正的 RSA 对,这有点令人失望。您需要与本地 openssl 库进行交互来执行此操作,或者根据您的要求与第三方模块进行交互。

就第三方模块而言,keypair 是一个简单的库,可以在您的特定情况下工作

const keypair = require('keypair');
const keys:  private: string, public: string  = keypair( bits : 2056 ); // 2056 is the default but added for example

我还发现 openpgpjs 的效果很好,它功能更多,同时也专注于成为一个平台无关模块。如果您正在考虑在浏览器和节点中进行加密,那么这可能是一个不错的选择。

【讨论】:

以上是关于NodeJS 为签名和验证消息生成有效的 PEM 密钥的主要内容,如果未能解决你的问题,请参考以下文章

如何在 NodeJS 中生成 ECDSA 签名而不需要 PEM 密钥格式?

Nodejs搭建wss服务器

JAVA中的签名验证和签名长度

如何将公钥从字符串类型转换为 PEM

iOS RSA加密解密及签名验证

生成 JWT 表单头和有效负载