Node JS - Encrypt / Decrypt - node.js

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
}

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

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

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 decrypt Triple DES in Node.js

This code worked for me to encrypt, but how can I reverse it?
I have hashed the password in the database and I need to decrypt. I have both a key and a hash.
const crypto = require('crypto');
const md5 = text => {
return crypto
.createHash('md5')
.update(text)
.digest();
}
const encrypt = (text, secretKey) => {
secretKey = md5(secretKey);
console.log(secretKey.toString('base64'));
secretKey = Buffer.concat([secretKey, secretKey.slice(0, 8)]); // properly expand 3DES key from 128 bit to 192 bit
const cipher = crypto.createCipheriv('des-ede3', secretKey, '');
const encrypted = cipher.update(text, 'utf8', 'base64');
return encrypted + cipher.final('base64');
};
const encrypted = encrypt('testtext', 'testkey');
console.log(encrypted);
This code should do what you need. We'll create a decrypt function that decrypts using the same algorithm (and key obviously!):
const crypto = require('crypto');
const md5 = text => {
return crypto
.createHash('md5')
.update(text)
.digest();
}
const encrypt = (text, secretKey) => {
secretKey = md5(secretKey);
console.log(secretKey.toString('base64'));
secretKey = Buffer.concat([secretKey, secretKey.slice(0, 8)]); // properly expand 3DES key from 128 bit to 192 bit
const cipher = crypto.createCipheriv('des-ede3', secretKey, '');
const encrypted = cipher.update(text, 'utf8', 'base64');
return encrypted + cipher.final('base64');
};
const decrypt = (encryptedBase64, secretKey) => {
secretKey = md5(secretKey);
secretKey = Buffer.concat([secretKey, secretKey.slice(0, 8)]); // properly expand 3DES key from 128 bit to 192 bit
const decipher = crypto.createDecipheriv('des-ede3', secretKey, '');
let decrypted = decipher.update(encryptedBase64, 'base64');
decrypted += decipher.final();
return decrypted;
};
const encrypted = encrypt('testtext', 'testkey');
console.log("Decrypted text:", decrypt(encrypted, 'testkey'));

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