nodejs 加密模块 privateEncrypt() 总是 return 相同的结果

nodejs crypto module privateEncrypt() always return same result

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

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

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

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 运行良好,符合我的预期。由于填充方案,它总是 return 不同的结果。

但是 PRIVATE ENCRYPT -> PUBLICDECRYPT 始终是 return 相同的消息,尽管使用了填充方案。

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

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

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

加解密用publicEncrypt() and privateDecrypt(), you have selected the RSA_PKCS1_PADDING mode. This translates to the RSAES-PKCS1-v1_5, a scheme that includes random elements, which cause the different outputs that you observe in your repeated runs. According to the documentation, crypto uses RSA_PKCS1_OAEP_PADDING padding by default. This stands for Optimal asymmetric encryption padding也是非确定性的

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


更新:您可能希望使用 Sign class instead of the privateEncrypt() and publicDecrypt() functions. Its 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')

每次签名都会不同。注意你不能"decrypt"它,它是一种单向操作。您只能使用 public 密钥和 Verify class:

来验证它
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'))