Symmetric encryption with NodeJS - node.js

I am totally confused why this isn't working, I am getting Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
var crypto = require('crypto');
var key = "ciw7p02f70000ysjon7gztjn7";
var pt = "72721827b4b4ee493ac09c635827c15ce014c3c3";
var encrypt = crypto.createCipher('aes256', key);
encrypt.update(pt, 'utf8', 'hex');
var encrypted = encrypt.final('hex')
var decrypt = crypto.createDecipher('aes256', key);
decrypt.update(encrypted, 'hex', 'utf8')
decrypt.final()
You can see it action using RunKit ... https://runkit.com/fredyc/bidirectional-encryption-with-nodejs

Solution via https://github.com/nodejs/node-v0.x-archive/issues/6386
// https://github.com/nodejs/node-v0.x-archive/issues/6386#issuecomment-31817919
// with createCipher / createDecipher (both deprecated) replaced with
// createCipheriv / createDecipheriv and a generated IV passed along.
var assert = require('assert');
var crypto = require('crypto');
var algorithm = 'aes256';
var inputEncoding = 'utf8';
var outputEncoding = 'hex';
var ivlength = 16 // AES blocksize
var key = Buffer.from('ciw7p02f70000ysjon7gztjn7c2x7GfJ', 'latin1'); // key must be 32 bytes for aes256
var iv = crypto.randomBytes(ivlength);
var text = '72721827b4b4ee493ac09c635827c15ce014c3c3';
console.log('Ciphering "%s" with key "%s" using %s', text, key, algorithm);
var cipher = crypto.createCipheriv(algorithm, key, iv);
var ciphered = cipher.update(text, inputEncoding, outputEncoding);
ciphered += cipher.final(outputEncoding);
var ciphertext = iv.toString(outputEncoding) + ':' + ciphered
console.log('Result in %s is "%s"', outputEncoding, ciphertext);
var components = ciphertext.split(':');
var iv_from_ciphertext = Buffer.from(components.shift(), outputEncoding);
var decipher = crypto.createDecipheriv(algorithm, key, iv_from_ciphertext);
var deciphered = decipher.update(components.join(':'), outputEncoding, inputEncoding);
deciphered += decipher.final(inputEncoding);
console.log(deciphered);
assert.equal(deciphered, text, 'Deciphered text does not match!');
the usage error is here:
// yours (incorrect)
var encrypt = crypto.createCipher('aes256', key);
encrypt.update(pt, 'utf8', 'hex');
var encrypted = encrypt.final('hex')
// correct
var encrypt = crypto.createCipher('aes256', key);
var encrypted = encrypt.update(pt, 'utf8', 'hex');
encrypted += encrypt.final('hex')
// yours (incorrect)
var decrypt = crypto.createDecipher('aes256', key);
decrypt.update(encrypted, 'hex', 'utf8')
decrypt.final()
// correct
var decrypt = crypto.createDecipher('aes256', key);
var decrypted = decrypt.update(encrypted, 'hex', 'utf8')
decrypted += decrypt.final()
but because cipher.createCipher() and cipher.createDecipher() are now deprecated and insecure, the solution above uses cipher.createCipheriv() and cipher.createDecipheriv(), instead.
The addition of a random IV protects you from leaking information if you encrypt multiple plaintexts that share the first same 16 bytes (or multiple of 16 bytes) at the start of the message. See Encrypting using AES 256, do I need IV?

Related

NodeJS: createCipheriv should give same output like earlier createCipher

Currently, I am using an old version of the crypto.js to encrypt and decrypt the strings. Below is my code for encryption -
const encrypt = (password, algorithm, encMethod) => (value) => {
const cipher = crypto.createCipher(algorithm, password);
return cipher.update(JSON.stringify(value), 'utf8', encMethod)
+ cipher.final(encMethod);
};
Using the above code my string (E-mailID) p1#yopmail.com is converted to 29c68f3bad0068c44122e734367f64557112e058c8222e3fd3908e68402ce6d5
Now as createCipher is deprecated what should I do with createCipheriv to give the same output as above.
I tried to pass null as IV to function createCipheriv, but I got the error Missing IV for cipher aes-256-cbc-hmac-sha1
Yes, Finally I resolved the same using some hacks as below -
const bytesToKey = require('evp_bytestokey');
const encryptionToken = bytesToKey(SomePasswordString, null, 256, 16);
//Ciphering
const cipher = crypto.createCipheriv('aes-256-cbc-hmac-sha1', encryptionToken.key, encryptionToken.iv);
return cipher.update(JSON.stringify(##VALUEtoENCRYPT##), 'utf8', 'hex') + cipher.final('hex');
//De-Ciphering
const decipher = crypto.createDecipheriv('aes-256-cbc-hmac-sha1', encryptionToken.key, encryptionToken.iv);
return JSON.parse(decipher.update(##VALUEtoDECRYPT##, 'hex', 'utf8') + decipher.final('utf8'));
Thanks to #topaco for suggesting me to use NPM package evp_bytestokey
Not sure if this is the right / good way to do it, we can use the same key and iv to return the same encrypted and decrypted values each time. And if you do not have a key and iv in mind, you can try using 0 filled buffers as key and iv.
var crypto = require('crypto');
var algo = 'aes-256-ctr';
var key = Buffer.alloc(32);
key.fill(0);
var iv = Buffer.alloc(16);
iv.fill(0);
const encrypt = (text) => {
var cipher = crypto.createCipheriv(algo, key, iv);
var crypted = cipher.update(text, 'utf8', 'base64');
crypted += cipher.final('base64');
return crypted
};
const decrypt = (text) => {
var decipher = crypto.createDecipheriv(algo, key, iv);
var crypted = decipher.update(text, 'base64', 'utf8');
crypted += decipher.final('utf8');
return crypted;
};
var encrypted = encrypt('yourpassword');
console.log(encrypted); //pfq1CtIh+vraJ9Bw
var decrypted = decrypt('pfq1CtIh+vraJ9Bw');
console.log(decrypted); //yourpassword

Encrypt in PHP 7 and decrypt in Node.js

I need to encrypt data in PHP and decrypt in Node.js.
I encrypt this in PHP:
$encrypt_method = "AES-256-CBC";
$secret_key = '7CEsPlLfVXcHf2S4wsnPnfNqYa+N/D/1zCXExN4aJSs=';
$secret_iv = 'StqUaIcbO9LFZ9QiuguXR6M/BepqZDV8p1now0FA/C4=';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
result:
VU5pckRaWHA4bjNaUjU3dGhscys3QT09
And decrypt in Node.js:
var crypto = require("crypto");
const decrypt = (textBase64, keyBase64, ivBase64) => {
const algorithm = 'AES-256-CBC';
const ivBuffer = Buffer.from(ivBase64, 'base64');
const keyBuffer = Buffer.from(keyBase64, 'base64');
const decipher = crypto.createDecipheriv(algorithm, keyBuffer, ivBuffer);
decipher.setAutoPadding(false);
let decrypted = decipher.update(textBase64, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const encryptedMessage = 'VU5pckRaWHA4bjNaUjU3dGhscys3QT09';
const key = '7CEsPlLfVXcHf2S4wsnPnfNqYa+N/D/1zCXExN4aJSs=';
const iv = Buffer.from('StqUaIcbO9LFZ9QiuguXR6M/BepqZDV8p1now0FA/C4=', 'base64').slice(0, 16);
// the message comes from the bytes AFTER the IV - this is what you should decrypt
const message = Buffer.from(encryptedMessage, 'base64').slice(16);
const result = decrypt(message, key, iv);
res.send("Decrypted: " + result);
Error: error:0606508A:digital envelope routines:EVP_DecryptFinal_ex:data not multiple of block length
I do not understand the error message, help to make a working example.

NodeJS decryption fails while using Crypto. What is the issue?

var decipher = Crypto.createDecipheriv('aes-256-cfb', 'testtesttesttesttesttest', 'testtesttesttest')
Error: Invalid key length
at new Decipheriv (crypto.js:267:16)
at Object.createDecipheriv (crypto.js:627:10)
This is the error I get. Where am I going wrong?
¿if we try another way ? as in this example:
function encryptdata(key, text) {
const hash = crypto.createHash('sha256');
hash.update(key);
const keyBytes = hash.digest();
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cfb', keyBytes, iv);
let enc = [iv, cipher.update(text, 'utf8')];
enc.push(cipher.final());
return Buffer.concat(enc).toString('base64');
}
The key needs to be exactly 32 bytes in length.
Please try the below code to see if it works.
var crypto = require('crypto');
var key = 'testtesttesttesttesttesttesttest';
try{
var cipher = crypto.createCipheriv('aes-256-cfb', key, 'testtesttesttest');
var encryptedData = cipher.update("hello", 'utf8', 'hex') + cipher.final('hex');
console.log(encryptedData);
var decipher = crypto.createDecipheriv('aes-256-cfb', key, 'testtesttesttest');
var decryptedData = decipher.update(encryptedData, 'hex', 'utf8') + decipher.final('utf8');
console.log(decryptedData);
} catch(exception) {
console.error(exception);
}

Nodejs decrypt AES256 help needed

Hi guys I am wondering if anyone has experience using nodejs to decrypt using aes256.
The encrypted string is base64 encoded and the first 16 bytes has the IV.
I am trying to extract the IV like below but having problems:
var crypto = require('crypto'),
algorithm = 'aes-256-cbc',
key = '6IAVE+56U5t7USZhb+9wCcqrTyJHqAu09j0t6fBngNo=';
function decrypt(text) {
var buf = Buffer.from(text, 'base64');
var iv = buf.toString('binary', 0, 16);
//console.log(iv.length);
//var crypt = buf.toString('base64', 16);
var decipher = crypto.createDecipheriv(algorithm, key, iv);
decipher.setAutoPadding(false);
var dec = decipher.update(crypt, 'base64', 'utf-8');
dec += decipher.final('utf-8');
return dec;
}
console.log(decrypt('mIBOVqk3bDCQPupFcIWNReXrdNRnb2P+iKl35yYRgbA='));
I keep getting the "Invalid IV Length" error.
I believe the problem is that your key is in base64, when createDecipheriv is expecting another type.
From the docs:
The key is the raw key used by the algorithm and iv is an initialization vector. Both arguments must be 'utf8' encoded strings, Buffers, TypedArray, or DataViews. If the cipher does not need an initialization vector, iv may be null.
Also, from the encrypted data, you get the IV first from the first 16 bytes, then decrypt the rest of the data.
Here's what I believe you need, though the result is a little confused:
const crypto = require('crypto');
const decrypt = (textBase64, keyBase64, ivBase64) => {
const algorithm = 'aes-256-cbc';
const ivBuffer = Buffer.from(ivBase64, 'base64');
const keyBuffer = Buffer.from(keyBase64, 'base64');
const decipher = crypto.createDecipheriv(algorithm, keyBuffer, ivBuffer);
decipher.setAutoPadding(false);
let decrypted = decipher.update(textBase64, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const encryptedMessage = 'mIBOVqk3bDCQPupFcIWNReXrdNRnb2P+iKl35yYRgbA=';
const key = '6IAVE+56U5t7USZhb+9wCcqrTyJHqAu09j0t6fBngNo=';
const iv = Buffer.from(encryptedMessage, 'base64').slice(0, 16);
// the message comes from the bytes AFTER the IV - this is what you should decrypt
const message = Buffer.from(encryptedMessage, 'base64').slice(16);
const result = decrypt(message, key, iv);
console.log(result);
Where the result is:
I AM CONFUSED╚╚╚

Can't decrypt with node.js v0.10.18 # Windows 7 64Bit

I can't get crypto to work.
windows 7 64Bit
node.js v0.10.18
Encryption seems to work:
var fs = require('fs');
var img = new Buffer (fs.readFileSync('./image.png'), 'binary');
var crypto = require('crypto')
, key = 'salt_from_the_user_document'
, plaintext = img
, cipher = crypto.createCipher('aes-256-cbc', key)
, decipher = crypto.createDecipher('aes-256-cbc', key);
cipher.update(plaintext, 'binary', 'base64');
var encryptBinary = cipher.final('base64')
console.log('encrypted :', encryptBinary);
... but decryption not.
decipher.update(encryptBinary, 'base64', 'binary');
var decryptBinary = decipher.final('binary');
console.log('decrypted :', decryptBinary);
Same decryption problem with node-efs.
var efs = require('efs').init('aes-128-cbc', 'password');
// encrypt and write file
efs.writeFileSync('/tmp/example', 'hello world');
// decrypt and read file
efs.readFileSync('/tmp/example');
Same problem with file-encryptor.
This works (with strings only):
var crypto = require('crypto')
, key = 'salt_from_the_user_document'
, plaintext = 'password'
, cipher = crypto.createCipher('aes-256-cbc', key)
, decipher = crypto.createDecipher('aes-256-cbc', key);
cipher.update(plaintext, 'utf8', 'base64');
var encryptedPassword = cipher.final('base64')
decipher.update(encryptedPassword, 'base64', 'utf8');
var decryptedPassword = decipher.final('utf8');
console.log('encrypted :', encryptedPassword);
console.log('decrypted :', decryptedPassword);
The call to update also returns encrypted data, the call to final only returns the rest. Hence you need to concatenate output of each call to update and finally add the output of final. This is true for encryption as well as for decryption (and hashing, by the way).
Hence it needs to be something such as:
var encrypted = cipher.update(plaintext, 'binary', 'base64');
encrypted += cipher.final('base64');
Then it'll work.
Please note that the update and final functions are deprecated and the crypto module is now also stream-based and you might want to switch to the more modern approach anyway.

Resources