【问题标题】:nodejs crypto module privateEncrypt() always return same resultnodejs 加密模块 privateEncrypt() 总是返回相同的结果
【发布时间】:2019-06-09 03:53:51
【问题描述】:

我正在使用带有 nodejs 加密模块的 RSA 加密。

我想用 PRIVATE KEY 加密消息并用 PUBLIC KEY 解密。 也总是使用填充方案(如使用公钥加密)对相同的消息产生不同的结果。

所以我使用了下面的基本加密模块

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


var PRIVKEY = fs.readFileSync(path.join(__dirname, 'private.key'), 'utf8');
var PUBKEY = fs.readFileSync(path.join(__dirname, 'pub.key'), 'utf8');

// RSA PRIVATE ENCRYPT -> PUBLIC DECRYPT //
myMSG = "apple";
console.log('myMSG SIZE:', myMSG.length);

function privENC_pubDEC(originMSG){
 encmsg = crypto.privateEncrypt(PRIVKEY, Buffer.from(originMSG, 'utf8') ).toString('base64');
 msg = crypto.publicDecrypt(PUBKEY, Buffer.from(encmsg, 'base64'));
 console.log("Encrypted with private key : "+encmsg);
 console.log(msg.toString());
}

// RSA PUBLIC ENCRYPT -> PRVATE DECRYPT //
function pubENC_privDEC(originMSG){
 encmsg = crypto.publicEncrypt({key:PUBKEY, padding:crypto.constants.RSA_PKCS1_PADDING}, Buffer.from(originMSG, 'utf8') ).toString('base64');
 msg = crypto.privateDecrypt({key:PRIVKEY, padding:crypto.constants.RSA_PKCS1_PADDING}, Buffer.from(encmsg, 'base64'));
 console.log("\nEncrypted with public key : "+encmsg);
 console.log(msg.toString());
}

privENC_pubDEC(myMSG);
pubENC_privDEC(myMSG);

结果

C:\Users\LSW>node crypto.js
myMSG SIZE: 5
Encrypted with private key : fbUZwj+UZP92HQYRc+EJTqSztJTY/Sit5axPZ0NVBuDAC8ZwvvC96pxxDGpra4Yg8MjcXyjvnT8rrrgHu0T0wA==
apple

Encrypted with public key : ze+5TdWtR8hkpNPIVa5HSasOxs3Pr8FA/1/zUGqDUQmIhs/miWt5pgU9kIAiryKfgGa0+p9RfHPMwZ1VMSA7Bw==
apple

C:\Users\LSW>node crypto.js
myMSG SIZE: 5
Encrypted with private key : fbUZwj+UZP92HQYRc+EJTqSztJTY/Sit5axPZ0NVBuDAC8ZwvvC96pxxDGpra4Yg8MjcXyjvnT8rrrgHu0T0wA==
apple

Encrypted with public key : OdEpjloUDWI8+YjWkE5cmBC/fJL2QnRLKBXfjaP5h5qyB1OMcm9JGGNSTiAAL2u8O5jjdQAavB9Rn+cdRDjLyA==
apple

C:\Users\LSW>node crypto.js
myMSG SIZE: 5
Encrypted with private key : fbUZwj+UZP92HQYRc+EJTqSztJTY/Sit5axPZ0NVBuDAC8ZwvvC96pxxDGpra4Yg8MjcXyjvnT8rrrgHu0T0wA==
apple

Encrypted with public key : INspxkyFu2AWGVYwSvOGOPH1fhE3qVVxiqz+SmyHU8wTDNKHj4gVVHqO+8AZOJvi4NfyekI2MMwpFDU4mUjEXA==
apple

PUBLIC ENCRYPT -> PRVATE DECRYPT 运行良好,我预期。由于填充方案,它总是返回不同的结果。

但是 PRIVATE ENCRYPT -> PUBLIC DECRYPT 总是返回相同的消息,尽管使用了填充方案。

是否有任何解决方案使其与 Nodejs 加密模块的消息不同???

【问题讨论】:

  • 你需要RSA-OAEP
  • @kelalaka RSA-OAEP 用于加密和解密,实际支持,默认为crypto。 “问题”在于签名,需要的是RSA-PSS。见my answer for details
  • 是的,如果我们将私有加密称为签名。签名!= 私有加密。
  • @kelalaka 我已经用关于签名的解释更新了我的答案(而不是私有加密)。这应该更清楚。关于您的评论,我想知道是否有理由将privateEncrypt() 用于签名以外的目的。
  • @kelalaka 谢谢,有趣的阅读。一些实施者加剧了这个问题。例如,您引用的RSA_sign 函数may invoke a function RSA_private_encrypt() :-)

标签: javascript node.js encryption rsa cryptojs


【解决方案1】:

根据 OpenSSL 实现的 RSA 签名和加密填充方案which crypto leverages,这是预期行为。

我不确定你想用函数privateEncrypt()publicDecrypt() 做什么。如果您的意图是签署数据,请参阅下面的更新。无论如何,对于这些功能,crypto 文档解释说它只公开了RSA_PKCS1_PADDING,OpenSSL 将其映射到引擎盖下的确定性 RSASSA-PKCS1-v1_5 填充方案。这意味着对于相同的键和相同的数据,结果数据将是相同的。

对于加密和解密,使用publicEncrypt()privateDecrypt(),您选择了RSA_PKCS1_PADDING 模式。这转化为 RSAES-PKCS1-v1_5,一种包含随机元素的方案,这会导致您在重复运行中观察到不同的输出。根据文档,crypto 默认使用RSA_PKCS1_OAEP_PADDING 填充。这代表Optimal asymmetric encryption padding,它也是非确定性的。

有关 PKCS#1 定义方案的摘要,请参阅PKCS#1 Schemes


更新:您可能希望使用 Sign class 而不是 privateEncrypt()publicDecrypt() 函数。它的sign() 函数确实支持概率填充模式,OpenSSL 通过 RSASSA-PSS 支持这种模式。使用您的示例代码作为起点,它看起来像这样:

const sign = crypto.createSign('SHA256')
sign.update(Buffer.from(originMSG, 'utf8'))
signature = sign.sign({key:PRIVKEY, padding:crypto.constants.RSA_PKCS1_PSS_PADDING}).toString('base64')

签名每次都会不同。请注意,您不能“解密”它,它是一种单向操作。您只能使用带有Verify 类的公钥来验证它:

const verify = crypto.createVerify('SHA256')
verify.update(Buffer.from(originMSG, 'utf8'))
verifyRes = verify.verify({key:PUBKEY, padding:crypto.constants.RSA_PKCS1_PSS_PADDING}, Buffer.from(signature, 'base64'))

【讨论】:

  • @cockroach54 很高兴,您的问题提出的很好,欢迎来到 StackOverflow。
  • 嗯..我可以再问你一个吗???我打算在客户端应用程序中嵌入公钥,在管理应用程序中嵌入私钥。管理员应用程序用户加密某种代码(加密的代码必须随机不同)并将其提供给客户端应用程序。客户端只解密代码但不应该知道如何加密它。在这种情况下,如果管理员使用 PUBLIC KEY 而客户端使用 PRIVATE KEY,则客户端可以使用 PRIVATE KEY 制作 PUBLIC KEY。这是个问题。我可以自定义 privateEncrypt() 使用 RSASSA-PKCS1-v1_5 --> RSAES-PKCS1-v1_5 ???
  • @cockroach54 这太大了,无法在评论中回复,请将其作为新问题提交以获得正确答案...
猜你喜欢
  • 1970-01-01
  • 2017-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-12
相关资源
最近更新 更多