How do I properly encrypt/decrypt data between node.js with the crypto module (server side) and crypto-js (client side, react-native)?
NOTE: I'm using cryptojs in a react-native project, thus I can't use crypto on client. replacing crypto server side is not an option for me.
Server-side code:
var Crypto = require("crypto");
var Cipher = {
pass: "0123456789abcdef0123456789abcdef",
iv: "0123456789abcdef",
encript: function (msg) {
try {
var cipher = Crypto.createCipheriv("aes-256-cbc", this.pass, this.iv);
var hash = cipher.update(msg, 'utf8', "hex");
var hex = hash + cipher.final("hex");
return hex;
} catch (err) {
console.error(err);
return "";
}
},
decript: function (hex){
try {
var decipher = Crypto.createDecipheriv("aes-256-cbc", this.pass, this.iv);
var dec = decipher.update(hex, "hex", 'utf8');
return dec + decipher.final('utf8');
} catch (err) {
console.error(err);
return "";
}
}
}
Cipher.encript("i have an apple"); // 577267026f88f82ea286baf6bf089acb
Cipher.decript("577267026f88f82ea286baf6bf089acb"); // i have an apple
Client-side code
var CryptoJS = require("crypto-js");
var Cipher = {
pass: CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef"),
iv: CryptoJS.enc.Hex.parse("0123456789abcdef"),
encript: function (msg) {
try {
var options = { mode: CryptoJS.mode.CBC, iv: this.iv};
var json = CryptoJS.AES.encrypt(msg, this.pass, options);
return json.ciphertext.toString(CryptoJS.enc.Hex);
} catch (err) {
console.error(err);
return "";
}
},
decript: function (hex){
try {
// ???????????????????????????????????
// ???????????????????????????????????
} catch (err) {
console.error(err);
return "";
}
}
}
Cipher.encript("i have an apple"); // 405552d9a77ea9e29442057d27cd7aee
Cipher.decript(?????); // I have no Idea
How do I properly encrypt/decrypt data between node.js with the crypto module (server side) and crypto-js (client side, react-native)?
NOTE: I'm using cryptojs in a react-native project, thus I can't use crypto on client. replacing crypto server side is not an option for me.
Server-side code:
var Crypto = require("crypto");
var Cipher = {
pass: "0123456789abcdef0123456789abcdef",
iv: "0123456789abcdef",
encript: function (msg) {
try {
var cipher = Crypto.createCipheriv("aes-256-cbc", this.pass, this.iv);
var hash = cipher.update(msg, 'utf8', "hex");
var hex = hash + cipher.final("hex");
return hex;
} catch (err) {
console.error(err);
return "";
}
},
decript: function (hex){
try {
var decipher = Crypto.createDecipheriv("aes-256-cbc", this.pass, this.iv);
var dec = decipher.update(hex, "hex", 'utf8');
return dec + decipher.final('utf8');
} catch (err) {
console.error(err);
return "";
}
}
}
Cipher.encript("i have an apple"); // 577267026f88f82ea286baf6bf089acb
Cipher.decript("577267026f88f82ea286baf6bf089acb"); // i have an apple
Client-side code
var CryptoJS = require("crypto-js");
var Cipher = {
pass: CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef"),
iv: CryptoJS.enc.Hex.parse("0123456789abcdef"),
encript: function (msg) {
try {
var options = { mode: CryptoJS.mode.CBC, iv: this.iv};
var json = CryptoJS.AES.encrypt(msg, this.pass, options);
return json.ciphertext.toString(CryptoJS.enc.Hex);
} catch (err) {
console.error(err);
return "";
}
},
decript: function (hex){
try {
// ???????????????????????????????????
// ???????????????????????????????????
} catch (err) {
console.error(err);
return "";
}
}
}
Cipher.encript("i have an apple"); // 405552d9a77ea9e29442057d27cd7aee
Cipher.decript(?????); // I have no Idea
Share
Improve this question
edited Jun 27, 2016 at 9:31
gevorg
5,0655 gold badges38 silver badges54 bronze badges
asked Feb 21, 2016 at 5:28
Jesus Leonardo ZorrillaJesus Leonardo Zorrilla
331 gold badge1 silver badge3 bronze badges
2 Answers
Reset to default 5Your "password" (it is used as a key instead of a password) has two different encodings on client-side and server-side. On the client, you're parsing it as Hex, but on the server, you're passing it as a binary string, which is used as-is.
You either need parse it on the server (now it is AES-128 and not AES-256):
pass: new Buffer("0123456789abcdef0123456789abcdef", "hex"),
Or change the encoding on the client (from AES-128 to AES-256):
pass: CryptoJS.enc.Utf8.parse("0123456789abcdef0123456789abcdef"),
encript: function (msg) {
try {
var options = { mode: CryptoJS.mode.CBC, iv: this.iv};
var json = CryptoJS.AES.encrypt(msg, this.pass, options);
return json.ciphertext.toString(CryptoJS.enc.Hex);
} catch (err) {
console.error(err);
return "";
}
},
decript: function (hex){
try {
var options = { mode: CryptoJS.mode.CBC, iv: this.iv};
var json = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(hex)
}, this.pass, options);
return json.toString(CryptoJS.enc.Utf8);
} catch (err) {
console.error(err);
return "";
}
}
You still have security problems:
The IV has to be randomly chosen for every encryption under the same key to achieve semantic security. It doesn't have to be secret, so you can simply send it along with the ciphertext. It's mon to prepend it to the ciphertext and slice it off before decryption.
It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme with a strong MAC like HMAC-SHA256, which CryptoJS provides.
Here is the example node js crypto ( https://nodejs/api/crypto.html) and related encryption and decryption in crypto.js (https://github./brix/crypto-js).
Gist - https://gist.github./yoavniran/c78a0991e0152b306c25
//CryptoJS example
var key = "H98zM6i/55yNJfkFsbu0HrzlFo17FtR9";
var iv = key.slice(0, 16);
//Create Key
key = CryptoJS.enc.Utf8.parse(key);
//Get Iv
iv = CryptoJS.enc.Utf8.parse(iv);
var encrypted = CryptoJS.AES.encrypt("testtest", key,{ iv: iv});
//Encrypt string
var encrypted_data = encrypted.toString();
console.log(encrypted_data)
var decrypted = CryptoJS.AES.decrypt(encrypted_data, key,{ iv: iv});
var decrypted_data = decrypted.toString(CryptoJS.enc.Utf8)
console.log(decrypted_data)
////Node JS example
var key = "H98zM6i/55yNJfkFsbu0HrzlFo17FtR9";
var iv = key.slice(0, 16);
function encryptText(cipher_alg, key, iv, text, encoding) {
var cipher = crypto.createCipheriv(cipher_alg, key, iv);
encoding = encoding || "binary";
var result = cipher.update(text,'utf8', encoding);
result += cipher.final(encoding);
return result;
}
function decryptText(cipher_alg, key, iv, text, encoding) {
var decipher = crypto.createDecipheriv(cipher_alg, key, iv);
encoding = encoding || "binary";
var result = decipher.update(text, encoding);
result += decipher.final();
return result;
}
var encText = encryptText('aes256', key, iv, "testtest1", "base64");
console.log("encrypted text = " + encText);
var decText = decryptText('aes256', key, iv, encText, "base64");
console.log("decrypted text = " + decText);