Cant decrypt data after encryption with crypto - node.js

I want to encrypt data and write it in my database. This works fine. After I get the data back from my database I want to decrypt this data, but the decryption doesn't work correctly.
I saved the string "test" in the database. The encryption works correctly and the encrypted string is
3ac5d5d6beeb44c5a58ac54e7fc0ad07ea3c819ff6489aae16d490667a309751378ae10800c072551e3a97596f3a2ae0
after i run the decrypt function i get back this:
8ea2e28e0086ef2ad22c2d7805a34111
but it should be "test"
const crypto = require("crypto");
const algorithm = "aes-256-cbc";
const key = new Buffer("11111111111111111111111111111111");
const iv = new Buffer("12345678");
module.exports = {
//my encyrpt function
encrypt(text) {
let ivstring = iv.toString("hex");
let cipher = crypto.createCipheriv(algorithm, key, ivstring);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
// return { iv: iv.toString("hex"), encryptedData: encrypted.toString("hex") };
return encrypted.toString("hex");
},
// my decrypt data
decrypt(text) {
let ivstring = iv.toString("hex");
let encryptedText = Buffer.from(text, "hex");
let decipher = crypto.createDecipheriv(algorithm, key, ivstring);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
};

It seems that you have applied the encryption twice:
encrypt(encrypt('test'))
// returns '3ac5d5d6beeb44c5a58ac54e7fc0ad07ea3c819ff6489aae16d490667a309751378ae10800c072551e3a97596f3a2ae0'
So you can decipher it by calling decrypt twice on the ciphertext:
const cipherText = '3ac5d5d6beeb44c5a58ac54e7fc0ad07ea3c819ff6489aae16d490667a309751378ae10800c072551e3a97596f3a2ae0'
decrypt(decrypt(cipherText))
// returns 'test'

Related

encrypt long string with node js module crypto

i am trying to encrypt long tokens but i get error
Error: Trying to add data in unsupported state
import * as crypto from 'crypto';
import { APP_CONFIG } from "#app-config";
const algorithm = 'aes-256-cbc';
const cipher = crypto.createCipheriv(algorithm, Buffer.from(APP_CONFIG.ENCRYPTION.ENCRYPTION_KEY), APP_CONFIG.ENCRYPTION.IV);
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(APP_CONFIG.ENCRYPTION.ENCRYPTION_KEY), APP_CONFIG.ENCRYPTION.IV);
class cryptoHelper {
constructor() {
}
encrypt(text) {
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return encrypted.toString('hex');
}
decrypt(encryptedData) {
let encryptedText = Buffer.from(encryptedData, 'hex');
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
}
export const CryptoHelper = new cryptoHelper();
CryptoHelper.encrypt("long string"); // 1200 length for example
// encrypt will fail
i am trying to encrypt google auth tokens(access_token and refresh_token)
is there any way to encrypt long strings?

Node JS - Encrypt / Decrypt

I have an encryption function like this
const encryptWithInitVector = (string, keyBase64, ivBase64) => {
const key = Buffer.from(keyBase64, 'base64')
const iv = Buffer.from(ivBase64, 'base64')
const cipher = crypto.createCipheriv(getAlgorithm(keyBase64), key, iv)
let encrypted = cipher.update(string, 'utf8', 'base64')
encrypted += cipher.final('base64')
return encrypted
}
that receives a string to be encoded, an AESKey and an initializationVector.
How can I make the reverse path? I want to decode the response of the function encryptWithInitVector
https://nodejs.org/api/crypto.html#crypto_crypto_createdecipheriv_algorithm_key_iv_options
Create decipher using crypto.createDecipheriv
const decryptWithInitVector = (string, keyBase64, ivBase64) => {
const key = Buffer.from(keyBase64, 'base64')
const iv = Buffer.from(ivBase64, 'base64')
const decipher = crypto.createDecipheriv(getAlgorithm(keyBase64), key, iv)
let decrypted = decipher.update(string,'base64','utf-8');
decrypted += decipher.final('utf-8');
return decrypted
}

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

While doing decryption using crypto, getting bad decrypt error using Node.js

I am storing information in the database in an encrypted format. When I am retrieving it from the database and applying decrypt on it, I am getting error like "bad decrypt"
Here is my code:
const crypto = require("crypto");
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
function encrypt(text) {
let cipher = crypto.createCipheriv("aes-256-cbc", Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return { iv: iv.toString("hex"), encryptedData: encrypted.toString("hex") };
}
function decrypt(text) {
let iv = Buffer.from(text.iv, "hex");
let encryptedText = Buffer.from(text.encryptedData, "hex");
let decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(key), iv);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
/********** following is the api **************/
exports.viewTrade = async (req, res) => {
console.log("viewTrade api ", req.query);
let maindData = [];
var hw = {
iv: "fc4ca9a17d97d7a7772449cfea3a99b8",
encryptedData: "e966509fd17785b4fe8304ef2f531806",
};
console.log(decrypt(hw));
const tradeList = await trade.find({
createdBy: req.query.id,
});
if (tradeList.length) {
for (tradeInfo of tradeList) {
// let nameInfo = tradeInfo.name;
// // let value = decrypt(nameInfo);
// console.log("name info.. ", nameInfo);
// // console.log("value.. ", value);
}
}
};
By calling the above API, it is throwing error.
When I try out your code I'm getting a error like this: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt.
This probably means that the key used to decrypt is not the same as the encryption key.
I suspect this is because the code above re-creates the key on each run.
I would suggest you use a fixed key, maybe coming from an environment variable, or secure secrets store. To test this you can just initialize your key like so:
const key = Buffer.from("232f150296ffd446fc0b39fa32d1c1d42c2e232ccd3203df729b7f3c3c63a5da2", "hex");
Then encrypt a message and see that it will decrypt correctly like so:
const encrypted = encrypt("We love Stack Overflow");
const decrypted = decrypt(encrypted);
console.log("encrypted data:", encrypted);
console.log("decrypted data:", decrypted);
You'll notice that if you copy the encrypted data from one run of the program to the next, it should work with a fixed key, but give you the bad_decrypt error if you generate the key on each run.
Key Generation code:
const key = crypto.randomBytes(32).toString("hex");

CrytoJS AES: Encrypted string gets decrypted to empty string

I was tinkering with crypto-js and AES.
I have a seemingly straightforward piece of code which takes a plainText and encrypts it using AES with a key and an initial vector.
When I try to decrypt the encrypted text, it gets decrypted to empty string for some reason.
This is the snippet:
const { enc, AES } = require("crypto-js");
const KEY = enc.Utf8.parse("this is a key");
const IV = enc.Utf8.parse("this is initial vector");
const originalText = "someone#example.com";
const hash = AES.encrypt(originalText, KEY, { iv: IV });
const hashText = hash.toString();
console.log(`"${originalText}" was encrypted to "${hashText}"`);
const hashTextCopy = `${hashText}`;
const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
const decryptText = decrypt.toString(enc.Utf8);
console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
The output I get is:
"someone#example.com" was encrypted to "IgyDXGNVD8IokknoZqjamG0QecGvBM/dyxx4il8gCHA="
"IgyDXGNVD8IokknoZqjamG0QecGvBM/dyxx4il8gCHA=" was decrypted to ""
Can someone explain what is going on? I have seen quite a few examples of it over the Internet and they all seem to working just fine. But here, the text is not getting decrypted.
PS: The version I am using is "crypto-js": "^3.1.9-1",
Maybe try changing your code ever so slightly, this works for me.
As stated in the comments, I believe the problem with your initial example was the key length.
const { enc, AES } = require("crypto-js");
// Keep as a string..
const KEY = "this is a key";
const IV = enc.Utf8.parse("this is initial vector");
const originalText = "someone#example.com";
const hash = AES.encrypt(originalText, KEY, { iv: IV });
const hashText = hash.toString();
console.log(`"${originalText}" was encrypted to "${hashText}"`);
const hashTextCopy = `${hashText}`;
const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
const decryptText = decrypt.toString(enc.Utf8);
console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
This also works:
const { enc, AES } = require("crypto-js");
// 128-bit key works nicely
const KEY = enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
const IV = enc.Utf8.parse("this is initial vector");
const originalText = "someone#example.com";
const hash = AES.encrypt(originalText, KEY, { iv: IV });
const hashText = hash.toString();
console.log(`"${originalText}" was encrypted to "${hashText}"`);
const hashTextCopy = `${hashText}`;
const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
const decryptText = decrypt.toString(enc.Utf8);
console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
The key:
const KEY = enc.Utf8.parse("abcdfghi");
Will also work correctly (since it's 128-bits). 256 would work too.
const KEY = enc.Utf8.parse("abcdfghijklmnopq");
If you just use a pass phrase, a 256-bit key will be generated from it.

Resources