Nodejs decrypt but some character gets corrupted while decrypting - node.js

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

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
}

AES-256-GCM decryption in nodejs

i am trying to decrypt the data stored in my database before sending it to the client side.
I am using the builtin crypto module with AES-256-GCM encryption.
I have successfully implemented the encryption and it is working properly my problem is i am trying to decrypt the data in a different file but i keep getting an error.
this is the error:
(node:35798) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "iv" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined
1.js
router.post(
"/",
async(req, res) => {
function getFullAddress({housenumber, address1, address2, city, postcode, country}) {
return [housenumber, address1, ...(address2 ? [address2]: []), city, postcode, country].join(", ");
}
const aes256gcm = (key) => {
const encrypt = (str) => {
const iv = new crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
let enc = cipher.update(str, 'utf8', 'base64');
enc += cipher.final('base64');
return Buffer.concat([Buffer.from(enc), iv, cipher.getAuthTag()]).toString("base64");
};
return {
encrypt,
};
};
const aesCipher = aes256gcm(key);
const hashedPasscode = await bcrypt.hash(req.body.passcode, 12);
await User.create({
email: req.body.email,
mobilenumber: aesCipher.encrypt(req.body.mobilenumber),
passcode: hashedPasscode,
address: aesCipher.encrypt(getFullAddress(req.body))
})
2.js
router.get(
"/",
async(req, res) => {
const aes256gcm = (key) => {
const decrypt = (enc, iv, authTag) => {
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(authTag);
let str = decipher.update(enc, 'base64', 'utf8');
str += decipher.final('utf8');
return str;
};
return {
decrypt,
};
};
const aesCipher = aes256gcm(key);
const decrypted_MobileNumber = aesCipher.decrypt(user.mobilenumber);
const decrypted_address = aesCipher.decrypt(user.address);
console.log('decrypted_MobileNumber',decrypted_MobileNumber)
console.log('decrypted_address',decrypted_address)
here is an example of the data stored in my database
mobilenumber: 'Sm4xQjA2bmUwUUdEdW4zQkZ3PT3QEq5fBbTJ9ht4TgpQXTLmPYBSoQA836977j0rr3GYwg==',
This is what you do during encryption:
Buffer.concat([Buffer.from(enc), iv, cipher.getAuthTag()]).toString("base64");
Now, you need to reverse this during decryption:
enc = Buffer.from(enc, "base64");
const iv = enc.slice(enc.length-32, enc.length-16);
const tag = enc.slice(enc.length-16);
enc = enc.slice(0, enc.length-32);
The second issue is that a nonce/iv for GCM mode should be 12 bytes long. I've changed that and so some of the indices from the previous issue should change too.
The third issue is that you cannot concatenate encrypted and Base64-encoded chunks. You have to concatenate them before Base64 encoding so that there is no Base64 padding in the middle of the string. This shouldn't be much of an issue for GCM because the call to cipher.final('base64'); should return an empty string.
The fourth and clear issue is that during encryption you're encoding twice, but you only need to encode once.
And together this would look like this:
const crypto = require('crypto');
const aes256gcm = (key) => {
const encrypt = (str) => {
const iv = new crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
let enc1 = cipher.update(str, 'utf8');
let enc2 = cipher.final();
return Buffer.concat([enc1, enc2, iv, cipher.getAuthTag()]).toString("base64");
};
const decrypt = (enc) => {
enc = Buffer.from(enc, "base64");
const iv = enc.slice(enc.length - 28, enc.length - 16);
const tag = enc.slice(enc.length - 16);
enc = enc.slice(0, enc.length - 28);
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
let str = decipher.update(enc, null, 'utf8');
str += decipher.final('utf8');
return str;
};
return {
encrypt,
decrypt,
};
};
const cipher = aes256gcm(Buffer.alloc(32)); // just a test key
const ct = cipher.encrypt('test');
const pt = cipher.decrypt(ct);
console.log(pt);

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╚╚╚

Resources