Node.js加密模块的privateEncrypt()函数为什么每次都返回相同的结果?

4

我正在使用Node.js的加密模块进行RSA加密。

我想用私钥加密消息并用公钥解密。 同时,使用填充方案(如使用公钥加密)始终生成不同的结果。

因此,我使用了基本的加密模块,如下所示:

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

公钥加密 -> 私钥解密的操作效果很好,因为填充方案的缘故,它总是返回不同的结果。
但是私钥加密 -> 公钥解密总是返回相同的消息,尽管使用了填充方案。
有没有办法在Nodejs的crypto模块中使它返回不同的消息?

你需要 RSA-OAEP - kelalaka
@kelalaka RSA-OAEP 用于加密和解密,实际上是被支持的并且是 crypto 的默认选项。 "问题" 在于签名,所需的是 RSA-PSS。请参见我的答案以获取详细信息 - Reinier Torenbeek
是的,如果我们谈论签名作为私人加密。签名!=私人加密。 - kelalaka
@kelalaka,我已经更新了我的答案,并解释了签名(而不是私人加密)的原因。这应该会更清楚一些。关于您的评论,我想知道是否有使用privateEncrypt()以外的目的。 - Reinier Torenbeek
@ReinierTorenbeek 如果您查看OpenSSL RSA sign.c,它们有RSA_sign函数。问题出现在教育不正确上。请参见Cornell Univ.'s correction。Crypto上有一篇文章列出了仅基于公钥的签名和加密算法,只有RSA存在这个问题。在密码学上,签名!=加密。即使不建议使用相同的密钥 - kelalaka
1
@kelalaka 谢谢,很有趣的阅读。问题还被一些实现者加剧了。例如,您提到的 RSA_sign 函数可能会调用函数 RSA_private_encrypt() :-) - Reinier Torenbeek
1个回答

8
这是OpenSSL实现的RSA签名和加密填充方案的预期行为,它被crypto所利用
我不确定您想要使用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 填充。这代表 最优非对称加密填充,也是不确定性的。
有关 PKCS#1 定义的方案摘要,请参见 PKCS#1 方案

更新:您可能想使用Sign类而不是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。 - Reinier Torenbeek
嗯..我可以再问一个问题吗? 我计划将公钥嵌入客户端应用程序中,将私钥嵌入管理员应用程序中。管理员应用程序用户加密某种代码(加密代码必须是不同的随机数),并将其提供给客户端应用程序。客户端只能解密代码,但不应知道如何加密它。在这种情况下,如果管理员使用公钥,客户端使用私钥,则客户端可以使用私钥制作公钥。这是一个问题。我能否自定义privateEncrypt()使用RSASSA-PKCS1-v1_5 --> RSAES-PKCS1-v1_5? - cockroach54
@cockroach54 这个问题太大了,无法在评论中回答,请将其作为一个新问题提交,以获得适当的答案... - Reinier Torenbeek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接