I'm using JavaScript and Node.js to work on a sort of messaging project. When a user is created, the server uses the Node.js crypto
library to generate an RSA keypair. The private key is encrypted using the users password. On the webapp, when User A sends a message to User B, the data is encrypted using User B's public key. When User B receives the message, it is decrypted using their private key and password.
My problem is that while the app appears to encrypt the data, I am unable to decrypt the data. The error message that is thrown is literally "unable to decrypt data" which is not helpful.
Server-side code for generating keypairs:
// Generate public/private keypairs
exports.generateKeyPair = (password) => {
return new Promise((resolve, reject) => {
crypto.generateKeyPair('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: password
}
}, (err, publicKey, privateKey) => {
if (err) reject(err);
else resolve([publicKey, privateKey]);
});
})
}
Client-side code for decrypting and encrypting (Node crypto library is sent to client using Browserify):
var crypto = require('crypto');
window.encrypt = function (data, publicKey) {
let buffer = Buffer.from(data);
let encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString('base64');
}
window.decrypt = function(data, privateKey, password) {
let buffer = Buffer.from(data, 'base64');
let decrypted = crypto.privateDecrypt({
key: privateKey,
passphrase: password
}, buffer);
return decrypted.toString('utf8');
}
Client-side code that interacts with the UI:
var sendMsg = function() {
let token = $('#token').val();
let toUser = $('#toUser').val();
let message = btoa($('#sendMessage').val());
fetch(`/keypairs/public/${toUser}?token=${token}`)
.then((res) => res.json())
.then((json) => {
if (json.code != 200) throw 'Error';
else return json.data.pubKey;
})
.then((pubKey) => encrypt(message, pubKey))
.then((encrypted) => $('#send-result').html(encrypted))
.catch((err) => alert(err));
};
var decryptMsg = function() {
let token = $('#token').val();
let encrypted = $('#decrypt-text').val();
let password = $('#decrypt-pass').val();
fetch(`/keypairs/private?token=${token}`)
.then((res) => res.json())
.then((json) => {
if (json.code != 200) throw 'Error';
else return json.data.privKey;
})
.then((privKey) => decrypt(encrypted, privKey, password))
.then((decrypted) => $('#decrypt-result').html(decrypted))
.catch((err) => (console.error(err), alert(err))); // <-- this line gives useless info
};
I paste the encrypted data into a field #'decrypt-text
. I also pass the User B password. The token is retrieved during the sign-in process to associate the user with a key in the database. As I mentioned, the only error I get is "Unable to decrypt data". Any ideas? Perhaps I need to generate keys with pkcs1
type?