In the browser on the client I encrypt a rand_key variable using jsencrypt.js and a public key.
The encrypted key is send via the body in a mail to the server. (This is the only way within my reach given the IT structure.)
In my browser I have:
<!DOCTYPE html>
<html lang="en">
<head>
<script type="application/javascript" src="jsencrypt.js"></script>
</head>
<body>
<script>
var pubkey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALDjeFwFNhMCjMwcRVVKG1VvfsntEVPR3lNTujJnNk1+iSqZ4Tl5Lwq9GbwO+qlYVwXHNmeqG7rkEhL9uyDIZVECAwEAAQ=="
var rand_key = 'vpeq91mckhntgldi';
// Encrypt rand_key
var encrypt = new JSEncrypt();
//console.log('encrypt obj', encrypt);
encrypt.setPublicKey(pubkey);
var encrypted_rand_key = encrypt.encrypt(rand_key, 'base64');
console.log('encrypted_rand_key', encrypted_rand_key);
</script>
</body>
</html>
On my PC running node (where I receive the email):
var CryptoJS = require("crypto-js");
// encrypted string copied from browser console
var encrypted = 'IuRaUfDHDIJsO0JZbEj7RS/1Sw0iSZPB267MN9lmF5Fn/kuMMRyKlAjplwvUJ9qvirajOcAQNnRZs9A+gVcWLQ=='
IuRaUfDHDIJsO0JZbEj7RS/1Sw0iSZPB267MN9lmF5Fn/kuMMRyKlAjplwvUJ9qvirajOcAQNnRZs9A+gVcWLQ==
var key_pri = new NodeRSA('-----BEGIN RSA PRIVATE KEY-----MIIBPAIBAAJBALDjeFwFNhMCjMwcRVVKG1VvfsntEVPR3lNTujJnNk1+iSqZ4Tl5Lwq9GbwO+qlYVwXHNmeqG7rkEhL9uyDIZVECAwEAAQJBAIS8vYX4FyLex/8mu9SLvsU23KL0dgs7MqW+77uA/hvZt5eb/C0EfUekap3LBuAF3XqVkOwIjsDyj74adrB6J1ECIQDfxT74mqu+xZjdlrfNZcchu/MrrW631aMF4rsRZccTbQIhAMpdneTSAATCwE8vt4bS6BBnv8Y8ZceNO6wGOvcW30b1AiAY2MEGP75kP3Ka4Dpmfy+eSk1VAzvxA7LHW4akBuYU/QIhAMk7gtGSCjaxuy6DUssdW2tE4C0uzj87sIUFxQkEk48pAiEAkHxKin7tcB4pVU2yurSbGkB+TbaCOfkIzR4griXq00k=-----END RSA PRIVATE KEY-----');
var decrypted = key_pri.decrypt(encrypted, 'utf8');
console.log('decrypted: ', decrypted);
Unfortunately I get an error message:
Error: Error during decryption (probably incorrect key). Original error: Error: error:040A1079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
How can I fix the decription on the server (pc) side ?
Thanks !
The error gives you the information that the padding is wrong. JSencrypt is based on JSBN and only supports PKCS#1 v1.5 padding, but not OAEP. You have to configure NodeRSA to use the appropriate padding:
var key_pri = new NodeRSA(privateKeyString, {
encryptionScheme: 'pkcs1'
});
Then, you're passing a Base64-encoded string to key_pri.decrypt, but it expects the actual data as a Buffer, so you first need to parse that:
var decrypted = key_pri.decrypt(new Buffer(encrypted, 'base64'), 'utf8');
Related
i want to use NaCl library in the client side and libsodium in php to encrypt/decrypt messages between the client and the server using keypair(public,private).
When i encrypt with libsodium and decrypt with NaCl everything works, But when i try to encrypt with NaCl and decrypt with libsodium i get no result.
Encrypting with NaCl in the client side
var message = "Sample Message";
var bytes = nacl.util.decodeUTF8(message);
var client_public = nacl.util.hex2bytearray('35e9f8477b60f61747722698d98791c4e0818ff75da3943a30e13dc0a457d402');
var client_private = nacl.util.hex2bytearray('6382cd5ef713375b6fe3835a763c72dfdc7ddcade7b8bcb9640065582708ef2c');
var server_public = nacl.util.hex2bytearray('1f348bac3b60d3076fc1a32d4e205df67356a9ef16d4b3f391c0e4817f3b987f');
var sharedkey = nacl.box.before(server_public, client_private);
var nonce = nacl.util.hex2bytearray('c031122a5f57e253686d9f6082d1061a1546e5567290c7f0'); // 24 bytes
var cipher = nacl.box.after(bytes, nonce, sharedkey );
var cihper_with_nonce = nacl.util.bytearray2hex(nonce) + bytearray2hex(cipher); // will be sent to the server
//c031122a5f57e253686d9f6082d1061a1546e5567290c7f0b2c05c9fb1483fe9b1bd2d4ae261832a54569748dd7925511b3d236e23e8
nacl.util.hex2bytearray = hexString => new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
nacl.util.bytearray2hex = bytes => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
nacl.util.decodeUTF8=function(e){;var n,r=unescape(encodeURIComponent(e)),t=new Uint8Array(r.length);for(n=0;n<r.length;n++)t[n]=r.charCodeAt(n);return t}
Decrypting with libsodium in PHP
$cihper_with_nonce = 'c031122a5f57e253686d9f6082d1061a1546e5567290c7f0b2c05c9fb1483fe9b1bd2d4ae261832a54569748dd7925511b3d236e23e8';// received from the client
$server_public = hex2bin('1f348bac3b60d3076fc1a32d4e205df67356a9ef16d4b3f391c0e4817f3b987f');// generated with libsodium
$server_private = hex2bin('cea48d3c14bc9ad26bf3f62932db5d7336b8212866c14dec64670f295ec89d5d');// generated with libsodium
$client_public = hex2bin('35e9f8477b60f61747722698d98791c4e0818ff75da3943a30e13dc0a457d402');// generated with NaCl
$sharedkey = sodium_crypto_box_keypair_from_secretkey_and_publickey($server_private, $client_public );
$nonce = hex2bin(substr($cihper_with_nonce, 0, 48));//24 bytes
$cihper = hex2bin(substr($cihper_with_nonce, 48));
$message = sodium_crypto_box_open($cihper , $nonce, $sharedkey );
var_dump($message);// bool(false)
Am i using the Library the Wrong way or there is something i am doing it wrong?
Because when i encrypt with php and decrypt with NaCl everything works and i did the same way in reverse for the Decryption.
all the bytes(hex) used are generated with the same library.
NaCl Source nacl util
libsodium Source libsodium
So, I have some encryption/decryption issues …
I encrypt data in javascript thanks to node-forge and I try to decrypt it into PHP thanks to openssl_private_decrypt.
On the PHP side, I use the «OPENSSL_PKCS1_OAEP_PADDING» padding. So, on the javascript side I tried to configure forge to encrypt data with RSA-OAEP.
And when I try to decsypt the message on the PHP side, I have these errors :
error:04099079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
error:04065072:rsa routines:rsa_ossl_private_decrypt:padding check failed
I've tried to configure the encryption with sha1 message digest and sha1 for mgf1 option. I've also tried without any option (if I remember, forge use SHA256 by default). But there is nothing to do, I always have the same error …
javascript
const pubkey = `-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
`;
const privkey = `-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
`;
let publicKey = forge.pki.publicKeyFromPem(pubkey);
let key = forge.random.getBytesSync(32);
let encKey = publicKey.encrypt(key, 'RSA-OAEP', {
md: forge.md.sha1.create(),
mgf1: {
md: forge.md.sha1.create()
}
});
let b64Key = encodeURIComponent(btoa(enckey));
Next, I send the key in url with the "xcem" param, thanks to HttpClient. And I receive it in PHP.
php
$privKey = "";
$b64Key = urldecode($_GET['xcem']);
$encKey = base64_decode($b64Key);
$key = null;
if (!openssl_private_decrypt($encKey, $key, file_get_contents('/keys/openssl_private.key'), OPENSSL_PKCS1_OAEP_PADDING))
{
$errorssl = [];
while ($error = openssl_error_string()) {
$errorssl[] = $error;
}
throw new Exception("Erreur lors du décryptage du message ! " . json_encode($errorssl));
}
When I send Data between 2 PHP servers, there is no problem …
But I can't make it work between JS and PHP … I need some help ^^
Sooo …
After some tests, and headaches I found the problem … In my original code (not the one here) I sent the key, the init vector, the signature and the encrypted data …
But in my PHP, I tried to decode the signature … I didn't send data in the right order …
My bad …
I am generating a token using CyrptoJS which correctly encodes and decodes in jwt.io test form. Using HMACSha256.
The process throws the exception:
IDX12709: CanReadToken() returned false. JWT is not well formed: '[PII is hidden]'.
The token needs to be in JWS or JWE Compact Serialization Format.
(JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'.
(JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.
Token received in api is :
eyAiYWxnIjogIkhTMjU2IiwgInR5cGUiOiJKV1QifQ==.eyAiYWN0b3IiOiAiam9uZXMiLCAibmFtZSI6ICJDYXNlRWRpdCJ9.JRi5hfqItl2gne1dUJxq1dfgdgJ1zD9xn2aUJopglbI=
The code I am using to Validate the token is:
public static Boolean ValidateToken(string jwtToken, string key)
{
var securityKey = new SymmetricSecurityKey(Convert.FromBase64String(key));
var validationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = securityKey
};
SecurityToken validatedToken;
var claimPrincipal = new JwtSecurityTokenHandler().ValidateToken(jwtToken, validationParameters, out validatedToken);
return validatedToken.ValidFrom <= DateTime.Now;
}
Issue was with the encoding from CryptoJS this helped me sort it out https://www.jonathan-petitcolas.com/2014/11/27/creating-json-web-token-in-javascript.html I was not url encoding the values. removing the =
I'm having an issue where I was given a file to decrypt along with the Key, IV and encryption method (aes-256-ctr). I have been struggling to decrypt this using node.js and keep running into an error saying the IV length is invalid. I was also given the method to decrypt the file using the BouncyCaste library in C#. The C# method seems to work fine with no issues with the IV. What do I need to do differently in node than what is being done here in C# to avoid this error?
Working C# Decryption (Note: IV is in the filename)
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace c_app
{
class Program
{
static void Main(string[] args)
{
var baseFolder = Directory.GetCurrentDirectory();
// Create parameters
var myDi = new DirectoryInfo(baseFolder);
string keyString = "xxxxxxxxxxxxx32BitKeyxxxxxxxxxxx";
byte[] keyBytes = ASCIIEncoding.UTF8.GetBytes(keyString);
var c = CipherUtilities.GetCipher("AES/CTR/NoPadding");
KeyParameter sk = ParameterUtilities.CreateKeyParameter("AES", keyBytes);
// Get the IV
var files = myDi.GetFiles("001398.20180823.000_1966151284357350418");
var fileInfo = files[0];
var pathSplit = fileInfo.FullName.Split('_');
var filePath = pathSplit[0];
var iv = long.Parse(pathSplit[1]);
// Decrypt the file
var base64String = File.ReadAllText(fileInfo.FullName);
c.Init(false, new ParametersWithIV(sk, BitConverter.GetBytes(iv)));
var inputBytesToDecrypt = Convert.FromBase64String(base64String);
var decryptedBytes = c.DoFinal(inputBytesToDecrypt);
var decryptedText = ASCIIEncoding.UTF8.GetString(decryptedBytes);
// Write file back to current directory
File.WriteAllBytes(string.Format(#"{0}/decrypted.csv", myDi.FullName), decryptedBytes);
}
}
}
My attempt in Node.js
var crypto = require('crypto');
var fs = require('fs');
var iv = Buffer.from('1966151284357350418', 'base64'); // Experimenting with encoding types like base64
var key = Buffer.from('xxxxxxxxxxxxx32BitKeyxxxxxxxxxxx');
fs.readFile('./001398.20180823.000_1966151284357350418', (err, encryptedText) => {
if (err) throw err;
var decipher = crypto.createDecipheriv('aes-256-ctr', key, iv); // <--- Error thrown here
decrypted = decipher.update(encryptedText, 'binary', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
});
In case it is helpful I was also given the method for encrypting the file using BouncyCastle, which can be found here: https://pastebin.com/PWNzDum3
So I've been trying to use node with node-rsa and javascript with jsencrypt to create a website (for an assignment) where the javascript client gets the public key generated by the server (node-rsa), encrypts the message (jsencrypt) that the user has entered, sends it to the server and gets the server to decrypt it (node-rsa). The generation of the keys works, the encryption works however the decryption doesn't. When I start the node script I do the following for the encryption...
var NodeRSA = require('node-rsa');
var myDecrypter = new NodeRSA({b: 512});
When the client requests the key (I am using express) the following is ran.
app.get('/getPublicKey', function(req, res){
var publicKeyJson = {"Key": ""};
console.log(myDecrypter.exportKey('public'));
publicKeyJson.Key = myDecrypter.exportKey('public');
res.json(JSON.stringify(publicKeyJson));
});
The client then saves that key like this...
var myEncrypter = new JSEncrypt();
var myJson = "";
$.getJSON( "getPublicKey", function( data ) {
myJson = JSON.parse(data).Key;
setKey();
});
function setKey() {
myEncrypter.setPublicKey(myJson);
}
When I got to encrypt and send the message on the client I do this...
function messageEncrypt() {
message = document.getElementById("message").value;
var encrypted = myEncrypter.encrypt(message);
myMessage = {"username": "", "userId": 0.0, "message": ""};
myMessage.username = me.username;
myMessage.userId = me.userId;
myMessage.message = encrypted;
console.log(encrypted);
$.post("sendMessage", myMessage);
}
When the server receives a message this is what happens, this is where I get the errors.
app.post('/sendMessage', function(req, res){
var message = req.body;
var user = message.username;
var id = message.userId;
console.log("What a mess, " + user + " said " + message.message + " what on earth does that mean");
//This line below errors
var clearMessage = myDecrypter.decrypt(message.message, 'utf8');
console.log(user + " said " + clearMessage);
});
The error I get is ...
Error: Error during decryption (probably incorrect key). Original error: Error: error:040A1079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
at Error (native)
at NodeRSA.module.exports.NodeRSA.$$decryptKey (/home/node_modules/node-rsa/src/NodeRSA.js:295:19)
at NodeRSA.module.exports.NodeRSA.decrypt (/home/node_modules/node-rsa/src/NodeRSA.js:243:21)
at /home/securechat/securechat.js:36:36
at Layer.handle [as handle_request] (/home/node_modules/express/lib/router/layer.js:95:5)
at next (/home/node_modules/express/lib/router/route.js:131:13)
at Route.dispatch (/home/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/node_modules/express/lib/router/layer.js:95:5)
at /home/node_modules/express/lib/router/index.js:277:22
at Function.process_params (/home/node_modules/express/lib/router/index.js:330:12)
Here however is where it gets interesting, to get that error message above I had a private key of...
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAIhdx31QICGN1LKRW4WngeL3RtzPh7cEHmhFJB8m4bQUSTcSi4eg
sUvMeZkWyaF9gOxtZKzk5TI6q+8hg8TY6S8CAwEAAQJASds423cVH/c4NsqhXh8e
KvYwjBFeeNIjQegIq1KctbHmKNM5MMb4jnDqdY/S5XHHS22EGvLNheLgV8tlRjwG
UQIhANpNmbl215eOsGPJ0jqz1XPMBrO35V6I3P04kvr66R1JAiEAn+oL0jtAFETR
4PRfenye5MAu9US3V5MoDN8xUoEvKrcCIQDQT2ZWNNIrHAyzXB2QyJPxqInoqp1j
5QPDWl3ewtj5iQIgY3E1nKw/stsA8LTGUvMAFBv2l4r9wDXAaBC7KSUwYY0CIAj4
0gA9etDbPm3H/XDwK4WXs9mXkKroyxewkWoOoAw/
-----END RSA PRIVATE KEY-----
and the public key sent to the client was...
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIhdx31QICGN1LKRW4WngeL3RtzPh7cE
HmhFJB8m4bQUSTcSi4egsUvMeZkWyaF9gOxtZKzk5TI6q+8hg8TY6S8CAwEAAQ==
-----END PUBLIC KEY-----
The encrypted messages (stackoverflow) was ...
XDViV0InCSnpyBxbNu5Herut0JYSsp87buvhzM4g2f9z3khIx2zA8Ou0Uq0TtmqtvBBVtZi5wZbcS6em/vB78g==
The interesting thing is that when I used the demo on jsencrypt website and enter my private key as well as the encrypted message I get the correct decrypted message.
So my question is...
What am I doing wrong with my node-rsa decryption???
If you need anymore information/code please put it in the comments below.
To answer your question #Curious_Programmer be default node-rsa uses pkcs1_oaep for encryption and decryption while jsencrypt uses pkcs1. Thankfully node lets you change the encryptionScheme, what you need to do is add ...
myDecrypter.setOptions({encryptionScheme: 'pkcs1'});
under
var myDecrypter = new NodeRSA({b: 512});
and all will work like a charm, I hoped I helped you ;)
It seems that the ciphertext is a buffer, i.e. binary data. Then it is transported using JSON, which consists of text. You need to use a text encoding over the binary data to transport it over a text based interface.
Check the following definition of the encrypt method:
key.encrypt(buffer, [encoding], [source_encoding]);
with the reminder that the default is 'buffer' for [encoding].
So you should be using:
var encrypted = myEncrypter.encrypt(message, 'base64', 'utf-8');
where 'base64' is for the ciphertext encoding and 'utf-8' is for the plaintext encoding.
The decryption routine should automatically use base64 decoding of the ciphertext:
var clearMessage = myDecrypter.decrypt(message.message, 'utf8');
should be just fine.
I had the same issue.
encrypt.setOptions({encryptingScheme:'pkcs1'}); //Can be 'pkcs1_oaep' or 'pkcs1'. Default 'pkcs1_oaep'.
But, it still failed.
I have changed the lib from node-rsa to ursa, like this:
privateKey.decrypt(thirdEncrypted, 'base64', 'utf8',ursa.RSA_PKCS1_PADDING);
The problem has been resolved in ursa.