Nodejs encryption problems with npm "crypto" module - javascript

When I try to encrypt or decrypt a token, I have this error :
internal/crypto/cipher.js:92
this[kHandle].initiv(cipher, credential, iv, authTagLength);
^
Error: Invalid IV length
I have to do the same encryption that's done on this link : here
Can someone help me ? :)
Have a great day all !
Here is what i've done:
var crypto = require('crypto'),
key = 'xNRxA48aNYd33PXaODSutRNFyCu4cAe/InKT/Rx+bw0=',
iv = '81dFxOpX7BPG1UpZQPcS6w==';
function encrypt_token(data) {
var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
cipher.update(data, 'binary', 'base64');
return cipher.final('base64');
}
function decrypt_token(data) {
var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
decipher.update(data, 'base64', 'binary');
return decipher.final('binary');
}
console.log('NodeJS encrypt: ', encrypt_token('partnerId=1&operationId=30215&clientId=CDX12345&timestamp=1545735181'));
console.log('NodeJS decrypt: ', decrypt_token('hxdBZWB4eNn0lstyQU3cIX3WPj4ZLZu-C8qD02QEex8ahvMSMagFJnAGr2C16qMGsOLIcqypO8NX4Tn65DCrXGKrEL5i75tj6WoHGyWAzs0'));

You need to use buffer or utf8 strings as parameters for createCipheriv
This works:
'use strict';
const crypto = require('crypto');
const key = Buffer.from('xNRxA48aNYd33PXaODSutRNFyCu4cAe/InKT/Rx+bw0=', 'base64');
const iv = Buffer.from('81dFxOpX7BPG1UpZQPcS6w==', 'base64');
function encrypt_token(data) {
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const encryptedData = cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
return encryptedData;
}
function decrypt_token(data) {
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
const decripted = decipher.update(data, 'base64', 'utf8') + decipher.final('utf8');
return decripted;
}
console.log('NodeJS encrypt: ', encrypt_token('partnerId=1&operationId=30215&clientId=CDX12345&timestamp=1545735181'));
console.log('NodeJS decrypt: ', decrypt_token('hxdBZWB4eNn0lstyQU3cIX3WPj4ZLZu-C8qD02QEex8ahvMSMagFJnAGr2C16qMGsOLIcqypO8NX4Tn65DCrXGKrEL5i75tj6WoHGyWAzs0'));
Note also that you need to concat the results of update and final

Related

Image encryption using node.js crypto does not work

I created an encryption app using node.js crypto. But the encryption/decryption seems to only work on .txt files. I encrypted an image file, but when i decrypted it, it doesnt return the original image.
const crypto = require("crypto");
const fs = require("fs");
//
function encrypt(text, password) {
let salt = crypto.randomBytes(16).toString("hex");
let key = crypto.scryptSync(password, salt, 16, { N: 16384 });
key = key.toString("hex");
const cipher = crypto.createCipheriv("aes-256-gcm", key, salt);
const encrypted = cipher.update(text, "utf8", "hex") + cipher.final("hex");
const tag = cipher.getAuthTag().toString("hex");
return salt + tag + encrypted;
}
function decrypt(text, password) {
const salt = text.substr(0, 32);
const tag = Buffer.from(text.substr(32, 32), "hex");
const ciphertext = text.substr(64, text.length);
let key = crypto.scryptSync(password, salt, 16, { N: 16384 });
key = key.toString("hex");
const cipher = crypto.createDecipheriv("aes-256-gcm", key, salt);
cipher.setAuthTag(tag);
try {
let decrypted = cipher.update(ciphertext, "hex", "utf8") + cipher.final("utf8");
return decrypted;
} catch (e) {
return true;
}
}
//
function encryptFile(fileLocation, password) {
fs.readFile(fileLocation, "utf8", (err, data) => {
if (err) return console.log(err);
if (data) {
const encText = encrypt(data, password);
fs.writeFileSync(fileLocation, encText);
console.log("File Encrypted");
}
});
}
function decryptFile(fileLocation, password) {
fs.readFile(fileLocation, "utf8", (err, data) => {
if (err) {
throw err;
} else {
const decText = decrypt(data, password);
if (decText === true) {
console.log("Wrong Password/Salt");
} else {
fs.writeFileSync(fileLocation, decText);
console.log("File Decrypted");
}
}
});
}
//
const fileLocation = "./sample.txt";
// encryptFile(fileLocation, "password");
decryptFile(fileLocation, "password");
I did it on repl so you can have a look - https://replit.com/#sampauls8520/file-enc
I have provided an image file as well so that you can encrypt/decrypt that.
You can't read binary data (this includes images) using the UTF-8 text encoding, nor write them back.
You will need to rework your code so that it doesn't operate on text strings, but with binary buffers.
IOW:
don't specify an encoding for fs.readFile/fs.writeFile ("If no encoding is specified, then the raw buffer is returned." say the docs)
don't specify either input or output encoding for cipher.update()/cipher.final()

How to zlib deflate a string in browser

I have in my backend a simple system for encrypting and compressing data.
Backend NodeJS
export const aesEncrypt = (text: string, key: string = ENCRYPTION_KEY) => {
let iv = randomBytes(IV_LENGTH);
let cipher = createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}
export const textCompressToBase64Url = (text: string) => {
return deflateSync(text).toString('base64url')
}
export const packDataForUrl = (data: string, key: string = ENCRYPTION_KEY) => {
return textCompressToBase64Url(aesEncrypt(data, key))
}
Result string:
eJwVU8cRxDAIbIkowXUjUv8lHP55BoM2Bp_W59hmGWH0DrxKpMlumMlfgAKD2DBKEx0gJs9j2ll-D7Gfl2PAgn1dPN696eDor3dWdR4iHH3hGQRKqKVy790Dneo7VZMEelNVag-n4rKAjhn4NNCiMmqwQ7QHMjgfkk0Rd3GlyviJuxz2zJWh6-_oAd4z9WHQPMhXgQ7P3LkegZHMt9-8h_IA-qSfm5LVIxn3PMJ0DEZSefcNW4CVKMluHkfhqjdIyXSPPWdeJGeJUWjInVq4E3tCClEQq2NSDFfA1QjSi71twSRRoMMk7GtceDIzTCHm9iqjFcB3D0U-N6tTIdnnkpnf_VpHDBJ5VnVZas7DQMVUrUu5TWXZV81j378DjVsYsGhdI7j7my6mFT6HH5dxxusT6_CiKpISF-u3A8U4O-aguJbnMapTBa0R8qEf6iK_GsZoZ89ZuTkBNoCazYWwUR8nQ0jBq9xu6Vr70nMKwAHeXWSNhI4qOS6QjSvtDg_iLoQVRmfAy_RVv3yN7buUFS6MiKCf0yVsgqr8KqYYXf0zR56utsdzXLFGauMhJ7QggHSphe0bwH1DyuQJT-DGAyfgUltmP4JcPUJ0akPPB0NTW6bV-61OIGcSV7N1zcik1_67QIH1c6i3An5X41WgZZfugnkWRxYF-2LxMuskueL8dNV_z7Ub5StKPVmZ2e52Y5M3I905SlaVdG2rF9X5dFg307uxiak2vgYSruvggU07bhP5wV273c6-Z65Zd_mjb0HXXs7pe-mrA-lsHzQZNvp8z2jt4rrID89spGGlyLdsagOyWd-eX13TX1DmNhnRdkMzt0NRHivqORe3nH_9zDtg
I then try to use Pako (port of zlib for browser) in the frontend to deflate before doing a AES decrypt however i keep getting various errors:
export const textDecompressFromBase64Url = (text: string) => {
//#ts-ignore
const sanitizedbase64 = text.replace(/_/g, '/').replace(/-/g, '+')
const testData = convertDataURIToBinary(sanitizedbase64)
const inflated = inflate(testData).toLocaleString()
return inflated
}
const convertDataURIToBinary = (base64Data: string) => {
const raw = window.atob(base64Data);
const rawLength = raw.length;
let array = new Uint8Array(new ArrayBuffer(rawLength));
for (let i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
If I don't use { raw: true } I get the following which is not usable in my aes function in the inflate method:
98,51,54,101,53,97,57,49,101,56,56,99,98,98,56,50,97,54,48,97,100,99,49,50,102,99,101,101,48,102,102,99,58,98,48,53,48,51,48,52,56,102,51,49,52,101,50,50,54,48,50,51,50,57,99,54,56,53,101,99,100,57,55,54,50,51,57,54,97,99,102,56,48,51,52,49,101,55,57,52,57,98,97,55,55,99,57,48,57,49,57,97,101,51,57,54,100,100,54,97,49,49,48,54,53,97,98,57,99,98,50,48,53,50,49,53,100,53,52,55,55,55,53,101,99,101,99,53,57,97,49,49,53,56,52,99,48,50,97,102,100,100,100,53,56,97,49,102,100,98,55,51,52,48,53,102,56,56,48,57,102,101,48,50,56,50,97,56,50,101,48,56,54,50,50,50,48,53,99,98,51,99,97,49,50,56,102,100,50,51,101,100,51,100,99,53,52,102,57,54,98,55,57,49,101,52,99,48,55,52,102,50,55,57,97,54,53,54,48,51,98,55,51,100,101,51,57,54,53,99,54,49,51,55,53,48,50,54,51,102,102,55,102,55,57,98,98,49,98,99,51,51,55,101,97,102,97,97,49,52,97,48,48,101,54,99,57,54,55,99,52,99,100,101,102,52,99,98,55,54,97,50,49,99,57,49,98,51,49,50,53,52,97,55,97,102,51,56,98,48,56,100,52,53,50,52,98,99,51,54,57,49,52,51,100,100,97,102,49,50,99,51,50,55,54,56,97,57,51,51,51,100,99,54,53,52,55,50,98,53,98,52,55,102,100,48,56,54,102,98,99,57,49,52,100,49,49,52,49,49,100,101,98,102,99,52,56,49,50,54,48,52,57,98,48,99,57,100,51,57,101,56,55,102,55,99,50,50,98,49,57,48,102,99,48,49,98,51,51,100,49,54,99,99,99,98,56,53,48,98,102,55,101,49,53,56,53,100,98,48,51,55,98,99,57,98,99,97,57,56,56,100,54,100,98,52,99,101,54,55,50,56,56,57,55,52,99,101,50,50,54,56,48,99,49,51,102,55,55,99,52,102,55,57,57,51,102,51,48,50,100,51,50,100,101,53,55,53,48,101,56,53,52,99,54,49,100,100,102,97,51,57,99,101,50,98,49,56,51,101,52,51,48,49,100,50,97,99,102,50,48,55,100,101,53,53,50,54,48,100,53,56,99,102,51,97,51,100,56,51,99,98,97,101,54,98,99,54,56,49,57,48,100,50,52,100,52,57,52,56,101,97,100,56,51,53,49,98,54,56,51,99,51,98,50,98,55,56,99,54,97,51,49,53,57,50,100,98,50,102,100,50,52,99,48,49,98,102,50,101,100,50,57,55,53,98,56,51,49,56,54,99,102,51,56,100,57,56,57,50,48,49,101,48,48,53,56,56,102,55,48,98,56,102,53,57,102,57,50,56,49,48,99,52,49,55,53,51,101,57,56,99,57,53,100,49,57,48,97,57,50,98,48,49,102,48,51,51,49,56,49,51,53,98,99,48,101,98,100,100,52,54,57,52,48,99,101,49,100,99,54,48,49,102,54,49,49,101,57,56,98,56,100,49,98,101,99,98,48,97,99,99,57,51,50,55,100,57,48,50,54,101,55,100,51,50,53,48,55,48,102,52,52,52,49,57,54,54,101,100,52,51,56,52,49,53,53,51,97,100,98,102,100,51,49,57,53,57,52,55,50,98,52,97,53,53,48,98,54,57,99,102,57,53,49,100,102,52,100,57,54,53,52,54,98,53,100,48,98,48,50,53,98,50,98,98,56,101,57,56,48,51,101,55,98,52,100,56,52,97,52,51,102,98,49,48,101,54,49,102,98,48,55,50,101,56,99,99,101,97,50,48,99,97,100,56,98,52,53,102,100,52,49,101,51,54,49,98,53,99,53,101,52,102,101,53,57,101,97,56,51,53,48,52,54,102,99,49,101,97,100,99,57,98,56,50,56,52,101,49,49,100,55,50,55,100,48,51,53,102,55,57,57,101,50,49,53,57,55,101,54,98,49,55,53,101,52,101,53,57,55,99,102,57,97,56,98,54,52,53,100,48,51,57,98,53,100,57,100,56,56,101,99,50,52,55,52,57,51,97,53,56,101,97,97,97,57,53,101,101,49,52,56,52,99,48,100,97,52,100,50,57,51,56,55,57,102,101,54,56,97,102,102,52,101,101,99,102,53,50,56,100,100,99,50,55,56,57,48,57,98,100,101,99,97,53,102,51,53,99,57,54,56,52,99,100,98,52,100,101,56,51,55,56,48,52,98,57,53,56,51,99,54,48,54,99,57,49,53,50,49,51,97,48,55,99,98,97,57,56,54,56,56,101,56,57,53,99,100,55,98,98,56,49,57,100,53,52,54,97,51,51,99,102,101,55,55,50,52,99,98,55,50,53,102,50,49,99,53,99,51,48,54,57,49,51,55,54,102,53,100,55,99,98,49,48,99,51,97,49,54,102,54,48,52,48,102,100,52,99,97,101,52,101,100,51,99,51,100,101,98,48,53,50,55,53,53,56,56,97,98,50,99,99,53,102,56,49,49,56,100,55,99,53,99,99,56,100,52,98,100,57,98,102,98,49,54,54,55,49,51,57,54
I have try to convert this to hex as I do in the backend but it is not working
If I pass the {raw: true} I get the following:
invalid code lengths set
In the backend however i'm able to inflate and decrypt with zlib with no issue:
export const textDecompressFromBase64Url = (text: string) => {
return inflateSync(Buffer.from(text, 'base64')).toString()
}
export const aesDecrypt = (text: string, key: string = ENCRYPTION_KEY) => {
let textParts = text.split(':');
let iv = Buffer.from(textParts.shift(), 'hex');
let encryptedText = Buffer.from(textParts.join(':'), 'hex');
let decipher = createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
From the comments it is said that this is impossible to make it work but here is a working example in nodejs of the full circle:
https://jdoodle.com/ia/s5Y
TIMELINE:
Stringify object
AES encrypt the string + add the IV in front in format of hex string
Deflate the string with zlib and output as base64url
Inflate the string with zlib
Decrypt the string with AES
The issue is using pako I'm not able to execute step 4

What is the difference between Crypto and CryptoJS AES encryption? The results are different. (javascript

The encryption results of the two libraries are different.
Can someone give me some advice?
//Crypto
const enCrypt = (plainText, key, iv) => {
plainText = Buffer.from(plainText);
let cipher = Crypto.createCipheriv("AES-128-CBC", key, iv);
let encrypted = cipher.update(plainText, "", "");
return Buffer.concat([encrypted, cipher.final()]).toString("base64");
}
//Crypto-js
const encryptAES = (pText, init_key, init_iv) => {
const key = CryptoJS.enc.Utf8.parse(init_key);
const iv = CryptoJS.enc.Utf8.parse(init_iv);
const cipherData = CryptoJS.AES.encrypt(pText, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return cipherData.ciphertext;
}
//crypto-js result
ba0a16dc341853969069249a74649a865403d8887816479f3b4d907eb6f827d96364a6960009a548edae9997037cc5718e8a3655bd7181d017983cba8d8b6e798905a7bd90741569f72bfc8677e8f3e97c0bfeafef1a22aa1c3e3e0711a53cdb54f6ec088b54ed77d08914f33f86f4fdd7dd8afd95894b64d33ff5f50c226e179e35b8a5018615624b992ef6b2b8ab9a8fa08bb6052445b5baa27737fac0896930e260f3c26d129b0bfa66bc381d3e0859f0bf37713af7541ff25651119894ff
//crypto result
ugoW3DQYU5aQaSSadGSahlQD2Ih4FkefO02Qfrb4J9ljZKaWAAmlSO2umZcDfMVxjoo2Vb1xgdAXmDy6jYtueYkFp72QdBVp9yv8hnfo8+l8C/6v7xoiqhw+PgcRpTzbVPbsCItU7XfQiRTzP4b0/dfdiv2ViUtk0z/19QwibheeNbilAYYVYkuZLvayuKuaj6CLtgUkRbW6onc3+sCJaTDiYPPCbRKbC/pmvDgdPghZ8L83cTr3VB/yVlERmJT/

(NODEJS) AES-256-GCM break pdf,gzip,png encoding after decryption

I wish I had help because i don't know why my implementation of AES-GCM break file encoding.
I have an API that uses 1 function to encrypt/decrypt with AES-256-GCM. (With KEY=buffer of 32 random bytes)
Here is the function:
const aes256gcm = (key) => {
const ALGO = 'aes-256-gcm';
const encrypt = (str) => {
try {
const salt = crypto.randomBytes(64);
const iv = crypto.randomBytes(32);
let derivedkey = crypto.pbkdf2Sync(key, salt, 55000, 32, 'sha512');
const cipher = crypto.createCipheriv(ALGO, derivedkey, iv);
let encrypted = Buffer.concat([cipher.update(str), cipher.final()]);
const tag = cipher.getAuthTag();
let buffer = Buffer.concat([salt, iv, encrypted]);
encrypted = {
tag: tag,
buffer: buffer
}
return encrypted;
} catch (e) {
console.log(e);
}
};
const decrypt = (data, authTag) => {
try {
const salt = data.slice(0, 64);
const iv = data.slice(64, 96);
const text = data.slice(96, data.length);
authTag = new Buffer.from(authTag, 'base64');
let derivedkey = crypto.pbkdf2Sync(key, salt, 55000, 32, 'sha512');
let decipher = crypto.createDecipheriv(ALGO, derivedkey, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(text, 'binary') + decipher.final();
return decrypted;
} catch (e) {
console.log(e);
}
};
return {
encrypt,
decrypt
};
};
With this code i encrypt and write in file the result:
const aesCipher = aes.aes256gcm(aes.loadKey(path.resolve(__dirname, `key`)));
const encrypted = aesCipher.encrypt(file.data);
if (encrypted !== undefined) {
fs.writeFile(`${file.name}.enc`, encrypted.buffer, function (err) {
if (err) return console.log(err);
console.log(`${file.name}.enc successfully created`);
});
}
And finaly with this i decrypt and write the content in a file:
const aesCipher = aes.aes256gcm(aes.loadKey(path.resolve(__dirname, `key`)));
let filename = 'test1.gz';
let authTag = 'puI0FfV4Btiy7iPiZFbwew==';
let encrypted = fs.readFileSync(path.resolve(__dirname, `test1.gz.enc`));
const decrypted = aesCipher.decrypt(encrypted, authTag);
if (decrypted !== undefined) {
const file = fs.createWriteStream(filename);
file.write(new Buffer.from(decrypted, 'ascii'), function (err) {
if (err) return console.log(err);
console.log(`Successfully decrypted`);
file.close();
});
res.send({
status: true,
message: 'File is decrypted',
});
}
Diff of my input/output files :
Diff
So, what am i doing wrong ? Is my encryption process good ? Why this only work well with .txt files ?
Thanks you !
I think a fairly small change to your decrypt function should fix the issue, if you just update it to:
const decrypt = (data, authTag) => {
try {
const salt = data.slice(0, 64);
const iv = data.slice(64, 96);
const text = data.slice(96, data.length);
authTag = new Buffer.from(authTag, 'base64');
let derivedkey = crypto.pbkdf2Sync(key, salt, 55000, 32, 'sha512');
let decipher = crypto.createDecipheriv(ALGO, derivedkey, iv);
decipher.setAuthTag(authTag);
let decrypted = Buffer.concat([decipher.update(text), decipher.final()]);
return decrypted;
} catch (e) {
console.log(e);
}
};
I think the previous implementation was not concatenating the result correctly for non-text files.

Encrypt in CryptoJS (Angular) and do the same in Crypto (NodeJS)

I am having trouble encrypting a password in Angular vs NodeJS.
For example, the password I'm using is: test
In Angular I am using CryptoJS:
encryptUsingAES256(password) {
let _key = CryptoJS.enc.Utf8.parse("elservidordelgatotuerto88");
let _iv = CryptoJS.enc.Utf8.parse("elservidordelgatotuerto88");
let encrypted = CryptoJS.AES.encrypt(
password, _key, {
iv: _iv,
format: CryptoJS.format.Hex,
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.Pkcs7
}).toString();
return encrypted;
}
The value I get from this function is: b75d0db663be668a24498aaa460f8896
Now, I also want to encrypt the same value in NodeJS using Crypto:
public encrypt(text) {
try {
var cipher = createCipher("aes-256-ctr", "elservidordelgatotuerto88");
var crypted = cipher.update(text,'utf8','hex');
crypted += cipher.final('hex');
return crypted;
} catch (error) {
throw new Error( 'couldn\'t encrypt text' );
}
}
And the value I get is different: 067e0c77
I want to obtain in Angular the same result that NodeJS gives me (067e0c77).
What could be the fixes that I should make in Angular?
Thank you!!
With a few changes we can make the output of the Crypto.js and Node crypto encryption identical.
We need to remove the padding in Crypto.js and also ensure that the key and iv are exactly the same.
The code will look like so:
const CryptoJS = require("crypto-js");
const crypto = require("crypto");
function encryptUsingAES256(password, key, iv) {
let _key = CryptoJS.enc.Utf8.parse(key);
let _iv = CryptoJS.enc.Utf8.parse(iv);
let encrypted = CryptoJS.AES.encrypt(
password, _key, {
iv: _iv,
format: CryptoJS.format.Hex,
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.NoPadding
}).toString();
return encrypted;
}
function encryptUsingNodeCrypto(text, key, iv) {
try {
const cipher = crypto.createCipheriv("aes-256-ctr", key, iv);
let crypted = cipher.update(text,'utf8','hex');
crypted += cipher.final('hex');
return crypted;
} catch (error) {
console.error("encryptUsingNodeCrypto: An error occurred: ", error);
throw error;
}
}
const originalText = "test";
const key = "elservidordelgatelservidordelgat";
const iv = "elservidordelgat";
const encryptedTextCryptoJs = encryptUsingAES256(originalText, key, iv);
console.log(`Crypto.js: "${originalText}" was encrypted to "${encryptedTextCryptoJs}"`);
const encryptedTextNodeJs = encryptUsingNodeCrypto(originalText, key, iv);
console.log(`Node.js: "${originalText}" was encrypted to "${encryptedTextNodeJs}"`);
I'm getting identical results for the same input.

Categories

Resources