TDLR I’m working on a node js server that uses the Crypto module to create a public and private RSA key. I need to be able to export the public key so my React app can communicate with the node server. The problem is that react uses a different module. I’m able to encrypt the message from React but when it gets to the server it’s either a mess of bits or the server outputs a padding error.
I’ve been trying to get it to work but the node js server keeps telling me the padding is wrong. I tried different combinations of paddings but it still had the same error.
Ps, They communicate through a WebSocket channel.
Error:
function: 'RSA_padding_check_PKCS1_OAEP_mgf1',
reason: 'oaep decoding error',
code: 'ERR_OSSL_RSA_OAEP_DECODING_ERROR'
Node Server code
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'Bob'
}
})
this.rsa = privateKey.toString('hex')
this.rsap = publicKey.toString('hex')
...
var decryptodata = crypto.privateDecrypt({
'key': this.rsa,
passphrase: 'Bob',
'padding': crypto.constants.RSA_PKCS1_OAEP_PADDING
},
Buffer.from(data, "base64")
)
return decryptodata.toString()
Subtle code
var publicKey =`HAS THE PUBLIC KEY AS A STRING`
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "------END PUBLIC KEY-----";
const kBase64Digits ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
function atob(input) {
// The implementation here has not been performance optimized in any way and
// should not be.
// Refs: https://github.com/nodejs/node/pull/38433#issuecomment-828426932
input = `${input}`;
var result = ``
for (let n = 0; n < input.length; n++) {
if (kBase64Digits.includes(input[n])) result += input[n];
}
return Buffer.from(result, 'base64').toString('latin1');
}
const pemContents = publicKey.substring(pemHeader.length, publicKey.length - pemFooter.length);
const binaryDerString = atob(pemContents);
const binaryDer = str2ab(binaryDerString);
this.publicKey = await window.crypto.subtle.importKey(
"spki",
binaryDer,
{
name: "RSA-OAEP",
hash: "SHA-256"
},
true,
["encrypt"]
)
...
const enc = new TextEncoder()
var msg = await window.crypto.subtle.encrypt({
name: "RSA-OAEP"
}, this.publicKey, enc.encode(message)
);
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
const encryptedBase64 = window.btoa(ab2str(msg));
console.log(encryptedBase64.replace(/(.{64})/g, "$1n"));