Can NodeJS Crypto Handle Video Files? - node.js

I cannot get why the video files cannot be encrypted and then decrypted. When then I try to open the resulting file, it says "This file isn't playable. That might be because the file type is unsupported, the file extension is incorrect, or the file is corrupt.". The same code works perfectly well with audio files. Here is the snippet:
// Nodejs encryption of buffers
const crypto = require('crypto'),
algorithm = 'aes-256-cbc',
password = 'd6F3Efeq';
const fs = require('fs');
let r = fs.createReadStream('video.mp4');
let encrypt = crypto.createCipher(algorithm, password);
let decrypt = crypto.createDecipher(algorithm, password);
let w = fs.createWriteStream('video.out4.mp4');
r.pipe(encrypt).pipe(decrypt).pipe(w);

Related

encrypted file is converted to buffer on IPFS

I'm encrypting a a text file locally using the crypto module from node.js and upload the file to IPFS. I'm trying to then download the file and decrypt it. But once I upload the encrypted file to IPFS, it seems to change to a buffer.
It looks somewhat like this before upload (I only copied the first line):
N�&��6-d�9L% 9���E��k�ir�C��ڤ|%B5-(���i�
...
...
And it looks like this after download:
{"type":"Buffer","data":[1,78,211,38,190,164,54,25,...])
I tried to convert it to multiple encodings, but that doesn't seem to solve anything. Is there a way to upload it in a different format (which stays the same on IPFS) or is there a way to convert the buffer back and decrypt it?
This is the code I use for encryption:
export const encrypt = (buffer, key) => {
const algorithm = 'aes-256-ctr';
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
const result = Buffer.concat([iv, cipher.update(buffer), cipher.final()]);
return result;
};

nodejs PKCS7 decryption and verify with PrivateKey and Cert problem

Im tring to make a nodejs app for decrypt a pem file with some cert.
i made something but couldnt get true verified data.
im getting false and decrypted data wrong.
const crypto = require('crypto');
const forge = require('node-forge');
var privateKeyAssociatedWithCert = fs.readFileSync("./test2.key").toString();
var certOrCertPem = fs.readFileSync("./soft_maya_test_certificate.crt").toString();
let p7d = forge.pkcs7.messageFromPem(decryptedData)
let privateCert = forge.pki.decryptRsaPrivateKey(privateKeyAssociatedWithCert);
p7d.decrypt(p7d.recipients[0], privateCert);
console.log(p7d.content)
var testCert = fs.readFileSync("./test_ca_chain.crt").toString();
var testKey = fs.readFileSync("./test.pem").toString();
var pem = forge.pkcs7.messageToPem(p7d);
console.log(pem)
console.log(Buffer.from(p7d.content.data, 'binary').toString('utf8'))
var v = crypto.createVerify('RSA-SHA256');
v.update(p7d.content.data);
let ffr = v.verify(testCert, testKey, 'binary')
console.log(ffr);

Decrypted string is not encoded properly in subsequent Node sessions

I have text of the form crypto.randomBytes(30).toString("hex") that I need encrypted.
Below is the encrypt and decrypt algorithms that I use.
import crypto from "crypto";
const ALGORITHM = "aes-256-ctr";
const IV_LENGTH = 16;
const ENCRYPTION_KEY = crypto.randomBytes(32);
export const encrypt = (text: string) => {
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(ALGORITHM, ENCRYPTION_KEY, iv);
const encryptedText = cipher.update(text, "utf8", "base64") + cipher.final("base64");
return `${iv.toString("hex")}:${encryptedText}`;
};
export const decrypt = (text: string) => {
const textParts = text.split(":");
const iv = Buffer.from(textParts.shift(), "hex");
const decipher = crypto.createDecipheriv(ALGORITHM, ENCRYPTION_KEY, iv);
const encryptedText = Buffer.from(textParts.join(":"), "base64");
return decipher.update(encryptedText, "base64", "utf8") + decipher.final("utf8");
};
I run node in my terminal and am able to mess around with these functions in my repl-like environment.
When I am within that node session, I see the following:
const encryptedText = encrypt("0e1819ff39ce47ec80488896a16520bc6b8fcd7d55dc918c96c61ff8e426")
// Output: "9fa7486458345eae2b46687a81a9fcf5:LOrlVD06eotggmIPAq0z9yzP/EHoeQyZyK6IiBYKZMIWvWYLekmSe73OjlgXdWJVOrcTyWS/eP3UU2yv"
const decryptedText = decrypt(encryptedText);
// Output: "0e1819ff39ce47ec80488896a16520bc6b8fcd7d55dc918c96c61ff8e426"
Just like I want!
If I exit the node session, and open a new node session and copy and paste to decrypt the same string I get the following:
const decryptedText = decrypt(ENCRYPTED_TEXT_FROM_ABOVE)
// Output: "�Z<�\r����S78V��z|Z\u0013��\u001a}�����#ߩ����Ɣh���*����y\b�\u001d���l'�m�'�"
Why is this happening? What changed? Clearly it seems like the Node no longer knows how to display the characters or something. I don't know what encoding it is now.
I came across this because I store the encrypted data in Postgres and upon retrieving it, I sometimes need to decrypt it. For some reason, when I restart the node session it forgets how to read it.
The interesting thing is I can decrypt(encrypt("another string")) => "another string" in the new node terminal and it'll work, but the original string no longer does.
The decryption step is failing here since you are generating a new key for each session in the line:
const ENCRYPTION_KEY = crypto.randomBytes(32);
If you log the key like so:
console.log( { key: ENCRYPTION_KEY.toString("hex") });
You'll see the key is different for each run. So it makes sense that we fail to decrypt the encrypted data from a previous session!
If you change to using a fixed key:
const ENCRYPTION_KEY = Buffer.from("8b3d2068cf410479451eef41fe07d43e62ec80b962ae30cd99f7698499acfd61", "hex");
The output from each session should be decrypted in the next one.
Of course we won't want to leave keys in code, so it would be best to use an environment variable for this purpose.

Encrypting file in Node via Crypto and Stream

I want to read from a stream then encrypt it and finally write it to another file.
This is my code:
var fs = require('fs');
var crypto = require('crypto');
var infile = fs.createReadStream('a.dmg');
var outfile = fs.createWriteStream('b.dmg');
var encrypt = crypto.createCipher('aes192', 'behdad');
var size = fs.statSync('a.dmg').size;
console.log(size);
infile.on('data',function(data) {
var percentage = parseInt(infile.bytesRead) / parseInt(size);
console.log(percentage * 100);
var encrypted = encrypt.read(data);
console.log(encrypted);
if(encrypted){
console.log(encrypted);
outfile.write(encrypted);
}
});
infile.on('close', function() {
encrypt.end();
outfile.close();
});
But it returns an empty file, and encrypted is null. What is the problem? I don't want to use pipe .
You really want to use Cipher#update and Cipher#final instead of Stream#read, because the function signature is read([size]) and data is not a size.
var fs = require('fs');
var crypto = require('crypto');
var infile = fs.createReadStream('a.dmg');
var outfile = fs.createWriteStream('b.dmg');
var encrypt = crypto.createCipher('aes192', 'behdad');
var size = fs.statSync('a.dmg').size;
console.log(size);
infile.on('data',function(data) {
var percentage = parseInt(infile.bytesRead) / parseInt(size);
console.log(percentage * 100);
var encrypted = encrypt.update(data);
console.log(encrypted);
if(encrypted){
console.log(encrypted);
outfile.write(encrypted);
}
});
infile.on('close', function() {
outfile.write(encrypt.final());
outfile.close();
});
Since crypto.createCipher is deprecated now. You should use crypto.createCipheriv where you provide a key and IV. That means that you should stretch the password that you use with PBKDF2 or similar to get a key and generate a random IV to get semantic security. Since the salt for PBKDF2 and the IV are not supposed to be secret, they can be written in front of the ciphertext. Since they have always the same length (salt is usually 8-16 bytes and IV always 16 bytes for AES-CBC), you know how many bytes you have to read in order to get those values back. Keep in mind that the decryption code has to have proper error handling.

NodeJS crypto package with zip files

I'm following the encryption example on this URL (code sample below) (http://lollyrock.com/articles/nodejs-encryption/). The problem is that I'm encrypting a .zip file, which seems to work just fine. The decryption is the problem. If I perform the code example below on something like a jpg, the picture comes out just fine. But if I run a zip file through it and I try to unzip the result, I get the following error:
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
Code:
// Nodejs encryption of buffers
var crypto = require('crypto'),
algorithm = 'aes-256-ctr',
password = 'd6F3Efeq';
var fs = require('fs');
var zlib = require('zlib');
// input file
var r = fs.createReadStream('file.txt');
// zip content
var zip = zlib.createGzip();
// encrypt content
var encrypt = crypto.createCipher(algorithm, password);
// decrypt content
var decrypt = crypto.createDecipher(algorithm, password)
// unzip content
var unzip = zlib.createGunzip();
// write file
var w = fs.createWriteStream('file.out.txt');
// start pipe
r.pipe(zip).pipe(encrypt).pipe(decrypt).pipe(unzip).pipe(w);
So it turns out the difference in my code was it was reading from a request stream. Apparently you can't just pipe a request stream through gunzip through decryption? I'm not sure why.
But if I same the stream to a file and THEN run it through gunzip and decryption it works.
If anyone has any input as to why, I'd at least like to understand!

Resources