I am using RSA encryption with nodejs crypto module.
I want encrypt message with PRIVATE KEY and decrypt with PUBLIC KEY. also always make different result with same message using padding scheme like encryption using public key.
So I used basic crypto module like below
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);
Result
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 is operated well I expected. it always return different result because of padding scheme.
But PRIVATE ENCRYPT -> PUBLIC DECRYPT is always return same message although used padding scheme.
Is there any solution make it different message with Nodejs crypto module???
This is expected behavior according to the padding schemes for RSA signing and encryption as implemented by OpenSSL, which crypto
leverages.
I am not sure what you want to use the functions privateEncrypt()
and publicDecrypt()
for. If your intent is to sign data, then see my update below. Anyway, for these functions, the crypto
documentation explains that it only exposes RSA_PKCS1_PADDING
which OpenSSL maps to the deterministic RSASSA-PKCS1-v1_5 padding scheme under the hood. This means that for the same key and the same data, the resulting data will be the same.
For encryption and decryption, with 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, which is non-deterministic as well.
For a summary of the PKCS#1-defined schemes, see PKCS#1 Schemes.
Update: You may want to use the Sign class
instead of the privateEncrypt()
and publicDecrypt()
functions. Its sign
() function does support a probabilistic padding mode, which OpenSSL supports via RSASSA-PSS. Using your example code as a starting point, it would look something like this:
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')
The signature will be different every time. Note that you can not "decrypt" it, it is a one-way operation. You can only verify it, using the public key with the 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'))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With