Encrypt and Decrypt files using Node.js Crypto Stream - node.js

I am making a Desktop application using Electron and react.js in which I have to encrypt and decrypt files (.txt, .pdf, .jpg, .png) using Crypto library.
I am using streams to do that.
So I just get the file from FileAPI and pass the file path to create readStream.
export function encrypt (passphrase) {
const crypto = require('crypto');
const fs = require('fs');
const cipher = crypto.createCipher('aes192', passphrase);
const input = fs.createReadStream(file_path);
const output = fs.createWriteStream('test.enc');
input.pipe(cipher).pipe(output);}
export function decrypt (passphrase) {
const crypto = require('crypto');
const fs = require('fs');
const cipher = crypto.createDecipher('aes192', passphrase);
const input = fs.createReadStream(file_path);
const output = fs.createWriteStream('test.pdf');}
input.pipe(cipher).pipe(output);
This code works fine for only for .txt files.
Any help to make this work for other file formats?

so here is a function that works.. just call on the function using 'data' in which ever format you need.. it seems best using strings or buffers.
function Encrypt_AES(data, pubkey) {
const algorithm = 'aes-192-cbc';
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(pubkey, 'salt', 24);
// Use `crypto.randomBytes` to generate a random iv instead of the static iv
// shown here.
const iv = Buffer.alloc(16, 0); // Initialization vector.
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(data, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
function Decrypt_AES(data, pubkey) {
const algorithm = 'aes-192-cbc';
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(pubkey, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.
const decipher = crypto.createDecipheriv(algorithm, key, iv);
// Encrypted using same algorithm, key and iv.
let decrypted = decipher.update(data, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}

Related

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 store encrypted password in an environment variable in node.js?

So the idea is simple but I am not sure if I am doing it correctly.
In my application, I need to use a username/password for some database connections.
The information is stored in my .bashrc file and exports, env vars.
I dont want to store them in clear text so I want to store them encrypted.
At runtime, I read the env variables, decrypt them and use them.
What I currently have is an node.js application that does the encryption,
code snippet:
const crypto = require('crypto');
const emailPassword = CLEAR_TEXT_PASSWORD;
const algorithm = 'aes-192-cbc';
const password = 'p3241';
const key = crypto.scryptSync(password, 'salt', 24);
const iv = Buffer.alloc(16, 0);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(emailPassword, 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log(encrypted);
The result of the above becomes my env variable.
Now in my consumer application, to use the env variable, I have a reverse routine from decryption before usage.
It looks like
export const decipher = (input: string) : string => {
const algorithm = 'aes-192-cbc';
const password = 'p3241';
const key = crypto.scryptSync(password, 'salt', 24);
const iv = Buffer.alloc(16, 0);
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(input, 'hex', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
return decrypted;
}
but what I don't is all the parameters for encrypt/decrypt are in clear text in my code on the server.
Is there a better way of doing this or am I overly paranoid?

How do i decrypt after wards in npm

I have the example from nodejs.org for the file encryption
const fs = require('fs');
const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(password, 'salt', 24);
// Use `crypto.randomBytes()` to generate a random iv instead of the static iv
// shown here.
const iv = Buffer.alloc(16, 0); // Initialization vector.
const cipher = crypto.createCipheriv(algorithm, key, iv);
const input = fs.createReadStream('test.js');
const output = fs.createWriteStream('test.enc');
input.pipe(cipher).pipe(output);
}
How do i do the oposite and get test.enc to test.js using the same key?
Thanks in advance
You can use a similar process to decrypt the file that you have encrypted using the above code.
We'll write the decrypted file to "test-decoded.js" so we don't end up overwriting our original file.
I'd also point out that you should ideally populate the IV with a random value and store this with the encrypted data, though if you're just testing it doesn't really matter too much!
const fs = require('fs');
const crypto = require("crypto");
const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
const key = crypto.scryptSync(password, 'salt', 24);
const iv = Buffer.alloc(16, 0); // Initialization vector.
const decryptInput = fs.createReadStream('test.enc');
const decryptOutput = fs.createWriteStream('test-decoded.js');
const decipher = crypto.createDecipheriv(algorithm, key, iv);
decryptInput.pipe(decipher).pipe(decryptOutput);

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'

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