RSA is one of the first public-key cryptosystems and is widely used for secure data transmission. It consist of two keys: Public key and private key. It allows anyone with public key to encrypt message which can be decrypt only by person having private key.
Usually, encryption at client side is done to send user’s data securely to the server so that hacker can’t get it in the data transmission. In this example, I have used JSEncrypt library in react to encrypt the message and NodeJS built-in crypto library at server side.
Add jsencrypt.min.js file in static folder. Add it as a script using script tag in your react component.
Below is encryption code.
function encryptMessage(message, publicKey) {
const jsEncrypt = new JSEncrypt();
jsEncrypt.setPublicKey(publicKey); return jsEncrypt.encrypt(message);
}
You don’t need to write import statement. It will be available when running the code in the browser. Downside is that you can’t write test for this function. If you try to import js file, you will get error ReferenceError: KJUR is not defined
which is mapped to this issue.
Encrypted data is binary data encoded in base64.
Public key will look something like below:
-----BEGIN PUBLIC KEY-----
MIGfMA0ABCDGSIb3DQEBAQUAA4GNADCBiQKBgQCUoxX5qq9w2iZeqeuDnBDujOfp
2cf6NFd3ioY7e6cg5wNTyr+wkTLZiIzEd8Uv8zwc+jvcFKeYXVh8dfdP0r/z/puT
E0m1YAGG+260rthPcqlhpqhRr9ISFN6SeWSfLaV7IYL0NIjesz0f45MwRA/fhKKw
1zw0Bvf1U8BMcPPamwIDAQAB
-----END PUBLIC KEY-----
This is 1024 bit public key created using openssl. As 1024 bit key is more vulnerable and easier to crack, people have started using 2048 bit key.
Commands to create public and private keys
> openssl genrsa -out rsa_2048_private_key.pem 2048> openssl rsa -pubout -in rsa_2048_private_key.pem -out rsa_2048_public_key.pem
function decryptMessage(encryptedMessage, privateKey) {
const rsaPrivateKey = {
key: privateKey,
passphrase: '',
padding: crypto.constants.RSA_PKCS1_PADDING,
}; const decryptedMessage = crypto.privateDecrypt(
rsaPrivateKey,
Buffer.from(encryptedMessage, 'base64'),
);
return decryptedMessage.toString('utf8');
}
From client, you will receive encrypted message present in base64 encoded format. You can pass privateKey
as string
or buffer
or KeyObject
type to create RsaPrivateKey
object. passphrase
should be same as the one provided while creating private key. We are using pkcs1 padding to decrypt the message because JSEncrypt uses pkcs1 padding for encryption.
If you are passing private key as string then it should be passed in pem format
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCUoxX5qq9w2iZeqeuDnBDujOfp2cf6NFd3ioY7e6cg5wNTyr+w
...
...
hLh1EnmuVtKBCummpyQ4rBrIV+b7tN0jeUWGQzQCBw==
-----END RSA PRIVATE KEY-----
If you have private key as single line then convert it into key object
const privateKeyInString =
'MIICWwIBAAKBgQCUoxX5qq9w2iZeqeuDnBD...........eUWGQzQCBw=='// Pass this to decryptMessage
const privateKey= crypto.createPrivateKey({
key: Buffer.from(privateKeyInString, 'base64'),
format: "der",
type: 'pkcs1',
})
It better to have private key in single line as it becomes easier to pass it as environment variable to the server.