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

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);
}

Related

Nodejs decrypt but some character gets corrupted while decrypting

I created a function to decrypt but some character gets corrupted while decrypting. What could this problem be caused by?
{"text":"aynısı"}
UYtydz+463tLN2HDon9c+Q/pYeL2JDcJEXAsKsGIIgY=
{"text":"aynıs��"}
const encryptionType = 'aes-256-cbc';
const encryptionEncoding = 'base64';
const encryptionEncodingHex = 'hex';
const bufferEncryption = 'utf-8';
const decryptJwt = (cipherText) => {
const buff = Buffer.from(cipherText, encryptionEncoding);
const KEY = Buffer.from(SECRET, bufferEncryption);
const IV = Buffer.alloc(16);
const decipher = crypto.createDecipheriv(encryptionType, KEY, IV);
const deciphered = decipher.update(buff).toString(bufferEncryption) + decipher.final().toString(bufferEncryption);
return deciphered;
};
I fixed:
let decrypted = decipher.update(buff, 'hex', 'utf8');
// Getting decrypted data
decrypted += decipher.final('utf8');

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

NodeJS crypto for encrypt/decrypt

I'm working on a database with some encrypted data that was generated in ColdFusion using the code below:
key = "nQw7y6QejwGFh/SNrul20Q==";
encrypt(myText, key, "AES/CBC/PKCS5Padding", "HEX");
It generates an encrypted string like: 6F795025756EC54D60808EA98AC163D9143C2FCFEC1065FCCAB7AB0CD577E535. I can decrypt it using my code below
I managed to create my NodeJS class to decrypt this data.
const crypto = require('crypto');
const key = Buffer.from('nQw7y6QejwGFh/SNrul20Q==', 'base64');
module.exports = class Encrypt {
decryptText(text) {
try {
const ivCiphertext = Buffer.from(text, 'hex');
const iv = ivCiphertext.slice(0, 16);
const ciphertext = ivCiphertext.slice(16);
var decipher = crypto.createDecipheriv('AES-128-CBC', key, iv);
var value =
decipher.update(ciphertext, '', 'utf8') +
decipher.final('utf8');
return value;
} catch (err) {
console.log(err);
}
}
};
I'm trying to create a encrypt method in this class, to encrypt the data in the same format that it was being generated in ColdFusion.
encrypt(text) {
const iv = crypto.randomBytes(16);
let cipher = crypto.createCipheriv(
'AES-128-CBC', key, iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return encrypted.toString('hex');
}
I did the following test:
const encrypt = new Encrypt();
const test = encrypt.encrypt('803315808');
console.log(test);
console.log(encrypt.decryptText(test));
First log:
fdcec1c7098c0fc91a11ada1e849b543
Second log:
Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

How to encrypt and decrypt string/object in nodejs

I would like to encrypt an object then decrypt it. The encryption works very well but the decryption fails. Below my code :
crypto_ext.js
const crypto = require("crypto")
const password = "shared_key"
const algorithm = "aes256"
export const encrypt = (text) => {
if(!text) return ''
const cipher = crypto.createCipher(algorithm, password);
let crypted = cipher.update(text, 'utf-8', 'base64');
crypted += cipher.final('base64');
return crypted;
}
export const decrypt = (text) => {
if(!text) return ''
const decipher = crypto.createDecipher(algorithm, password);
let decrypted = decipher.update(text, 'base64', 'utf-8');
decrypted += decipher.final('utf-8');
return decrypted;
}
and in my test.js, I have :
import {encrypt, decrypt} from './crypto_ext.js'
let test = {key1: val1, key2: val2}
test = encrypt(JSON.stringify(test)) || test
console.log("Encrypt : ", test)
console.log("Decrypt : ", decrypt(test)) // I should have my object as string here
And this is what I'm getting as error :
Uncaught Error: unable to decrypt data
at unpad (decrypter.js:83)
at Decipher.webpackJsonp../node_modules/browserify-aes/decrypter.js.Decipher._final (decrypter.js:38)
at Decipher.webpackJsonp../node_modules/cipher-base/index.js.CipherBase._finalOrDigest (index.js:76)
at decrypt (crypto_ext.js:17)
...
Can you please tell me what I'm doing wrong ?
Method createCipher deprecated. Use createCipheriv instead.
Try to use aes192 algorithm.
Dependencies: crypto package
You can achieve encoding and decoding with below codes:-
const crypto = require('crypto');
var password = 'ojisdasjdsjabdjs';
var iv = 'kiamdksndn';
function sha1(input) {
return crypto.createHash('sha1').update(input).digest();
}
function password_derive_bytes(password, salt, iterations, len) {
var key = Buffer.from(password + salt);
for (var i = 0; i < iterations; i++) {
key = sha1(key);
}
if (key.length < len) {
var hx = password_derive_bytes(password, salt, iterations - 1, 20);
for (var counter = 1; key.length < len; ++counter) {
key = Buffer.concat([key, sha1(Buffer.concat([Buffer.from(counter.toString()), hx]))]);
}
}
return Buffer.alloc(len, key);
}
async function encode(string) {
var key = password_derive_bytes(password, '', 100, 32);
var cipher = crypto.createCipheriv('aes-256-cbc', key, Buffer.from(iv));
var part1 = cipher.update(string, 'utf8');
var part2 = cipher.final();
const encrypted = Buffer.concat([part1, part2]).toString('base64');
return encrypted;
}
async function decode(string) {
var key = password_derive_bytes(password, '', 100, 32);
var decipher = crypto.createDecipheriv('aes-256-cbc', key, Buffer.from(iv));
var decrypted = decipher.update(string, 'base64', 'utf8');
decrypted += decipher.final();
return decrypted;
}
And then call below functions for encode and decode
For encode
await encode(JSON.stringify({'title': 'some text'}));
For decode
await decode('encoded_string_to_decode');
Try to use 'bcrypt' package it will help you in the encryption for passwords.
If you want to encryption for Data. Then use crypto or node-rsa
Link npm bcrypt package
Node-RSA

Symmetric encryption with NodeJS

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?

Resources