Nodejs encrypt and decrypt using crypto decrypt badly only firsts characters - node.js

I have a js script that crypt and decrypt a file using these two functions
Encryption
function encryptFile(fileName) {
const input = fs.createReadStream(fileName);
const output = fs.createWriteStream(fileName + '.crypt');
var aes = crypto.createCipheriv(algorithm, Buffer.from(key), initVect);
input
.pipe(aes)
.pipe(output)
.on('finish', function () {
console.log('FILE ENCRYPTED!');
}).on('error', error => {
console.log(error);
});
}
Decryption
function decryptFile(fileName) {
const input = fs.createReadStream(fileName);
const output = fs.createWriteStream(fileName + '.clear');
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(key), initVect);
input
.pipe(decipher)
.pipe(output)
.on('finish', () => {
console.log('FILE DECRYPTED!');
})
.on('error', error => {
console.log(error);
});
}
Some assumption:
I use aes-256-cbc as algorithm
key is a 32 char string
initVect is a crypto.randomBytes(16);
Using these two function to crypt and decrypt a file I obtain a bad decryption. No error while execution but when I open the decrypted file the firsts 9 characters is still encrypted. Indeed, if I insert at the begin of my file 9 random charachters, the whole content of my file was decrypted correctly but there are the firsts chars encrypted.
Any solution?
UPDATE
I also use these two function passing them the content of the file
Encryption
function encrypt(text) {
const cipher = crypto.createCipheriv(algorithm, Buffer.from(key), initVect);
let encrypted = cipher.update(text, 'utf8', 'base64')
encrypted += cipher.final('base64');
return encrypted;
};
Decryption
function decrypt(crypted_text) {
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(key), initVect);
let decrypted = decipher.update(crypted_text, 'base64');
decrypted += decipher.final();
return decrypted;
}
Using simple string these function work fine, saving the crypted (return of encrypt()) in a file, reading it and decrypt it the result decrypted (return of decrypt()) has the same problem.

Related

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

NodeJS Decrypt Data Corrupt Original Data

I use AES-266-CBC to encrypt data:
const iv = crypto.randomBytes(8).toString('hex');
const encrypt = (text: string): string => {
log('encrypt');
const cipher = crypto.createCipheriv('aes-256-cbc', ENCRYPTION_KEY, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
};
const decrypt = (text: string): string => {
log('decrypt');
const decipher = crypto.createDecipheriv('aes-256-cbc', ENCRYPTION_KEY, iv);
let decrypted = decipher.update(text, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
};
And everything works perfectly that means if i use this:
const data = JSON.stringify({
user: 'MHF',
info: {
age: 23,
family: 'HF'
}
});
const encrypted = encrypt(data);
console.log('encrypted: %s', encrypted);
const decrypted = decrypt(encrypted);
console.log('decrypted: %s', decrypted);
The problem is that when i send my encrypted string by a post request http like this:
POST {{baseUrl}}/v1/user-register
Content-Type: application/json
Content-Encrypted: AES
{"payLoad": "3f1d1584b0e1976ccea311b5fbe0b2aee1034198a582a3b8bcc773c175e91bb0ceda6b9fb88aff11a892fa7adb83d432"}
I have a decrypted data by some incorrect chars like this:
'r!!(h\x7F!o#L\x19\x10~\x7F"jnfo":{"age":23,"family":"HF"}}'
Why When i do a post request by encrypted data i have this result?
What is this: 'r!!(h\x7F!o#L\x19\x10~\x7F"j'?
Thanks to #Topaco and #Michael Fehr
It was my big mistake about generating and using IV

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

Cant decrypt data after encryption with crypto

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'

Resources