NodeJS crypto package with zip files - node.js

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!

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

Can NodeJS Crypto Handle Video Files?

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

encrypt the audio file by android and decrypt it by backend sails js

I want to encrypt the audio file by android and decrypt it by backend sails js. I developed the program for that but I got error in sails js like
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
This is my source code for encrypt the audio file in android
final String ALGORITHM = "blowfish";
String keyString = "DesireSecretKey";
private void encrypt(String file) throws Exception {
File extStore = Environment.getExternalStorageDirectory();
File inputFile = new File(file);
File encryptedFile = new
File(extStore+"/Movies/encryptAudio.amr");
doCrypto(Cipher.ENCRYPT_MODE, inputFile, encryptedFile);
}
private void doCrypto(int cipherMode, File inputFile,
File outputFile) throws Exception {
Key secretKey = new
SecretKeySpec(keyString.getBytes(),ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(cipherMode, secretKey);
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes);
FileOutputStream outputStream = new
FileOutputStream(outputFile);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
}
I installed the crypto , fs libraries in sails js backend by following command
npm install crypto
npm install fs
This is my source code for decrypt the audio file in sails js
function decrypt() {
var crypto = require('crypto'),
algorithm = 'blowfish',
password = 'DesireSecretKey';
var fs = require('fs');
// input file
var r = fs.createReadStream(config.UPLOAD_FILES_PATH
+'/encryptAudio.amr');
var decrypt = crypto.createDecipher(algorithm, password,"");
// write file
var w = fs.createWriteStream(config.AUDIO_PATH+'decryptAudio.amr');
// start pipe
r.pipe(decrypt).pipe(w);
}
Encryption is working properly & i can get the encrypted audio file.But the issue is i couldn't get the decrypted audio file by sails js. Can you identify the issue?
maybe the answer to this question might help as you are using Java's library for cryptography this should pretty much guide you in right direction.
Encrypt with Node.js Crypto module and decrypt with Java (in Android app)
I would have mentioned this in comments section but I do not have enough reputation points to comment.
This is opposite of what you are trying to achieve but still it could help you to analyze your issue.

Saving Data URI as Image?

On a node server I would like to save uploaded datauri data as an image. To do this I've tried decoding the content of this png-
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAIAAAFlEcHbAAAAB3RJTUUH1gMWFjk7nUWcXQAAAAlwSFlzAABOIAAATiABFn2Z3gAAAARnQU1BAACxjwv8YQUAAAAeSURBVHjaY7h79y7DhAkTGIA04/Tp0xkYGJ49ewYAgYwLV/R7bDQAAAAASUVORK5CYII=
And saving it as a .png extension. Looks like there is more too it than that. How do I decode the datauri and save it as a file?
I've created a library to be used with Node.js that helps with encoding and decoding of data URI schemes. I believe it can help you, check:
https://github.com/DiegoZoracKy/image-data-uri
Using this library, in your case, the code would be:
'use strict';
const ImageDataURI = require('image-data-uri');
const dataURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAIAAAFlEcHbAAAAB3RJTUUH1gMWFjk7nUWcXQAAAAlwSFlzAABOIAAATiABFn2Z3gAAAARnQU1BAACxjwv8YQUAAAAeSURBVHjaY7h79y7DhAkTGIA04/Tp0xkYGJ49ewYAgYwLV/R7bDQAAAAASUVORK5CYII=';
const fileName = 'decoded-image.png';
ImageDataURI.outputFile(dataURI, filePath);
I was trying to decode the data using atob and saving this as a png file. I'm instead saving it base64 encoded but specifying the encoding in the write buffer.
fs.writeFileSync('tmp/myfile.png', new Buffer(data, 'base64'));
You can convert your data uri to a blob using below code:
function dataURItoBlob(dataURI) {
var byteStr;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteStr = atob(dataURI.split(',')[1]);
else
byteStr = unescape(dataURI.split(',')[1]);
var mimeStr = dataURI.split(',')[0].split(':')[1].split(';')[0];
var arr= new Uint8Array(byteStr.length);
for (var i = 0; i < byteStr.length; i++) {
arr[i] = byteStr.charCodeAt(i);
}
return new Blob([arr], {type:mimeStr});
}
and then you can append this blob data to from data and upload it as a file:
var blob = dataURItoBlob(dataURI);
var fd = new FormData(document.forms[0]);
fd.append("image", blob);

How do I parse a data URL in Node?

I've got a data URL like this:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
What's the easiest way to get this as binary data (say, a Buffer) so I can write it to a file?
Put the data into a Buffer using the 'base64' encoding, then write this to a file:
var fs = require('fs');
var string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
var regex = /^data:.+\/(.+);base64,(.*)$/;
var matches = string.match(regex);
var ext = matches[1];
var data = matches[2];
var buffer = Buffer.from(data, 'base64');
fs.writeFileSync('data.' + ext, buffer);
Try this
const dataUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
const buffer = Buffer.from(dataUrl.split(",")[1], 'base64');
I also met such questions (parsing and validating data URL) recently and found the following workaround: https://gist.github.com/bgrins/6194623
I created 2 packages to make working with data URL easier in the code. Here they are:
https://github.com/killmenot/valid-data-url
https://github.com/killmenot/parse-data-url
Check out examples
I was looking into the sources of Node.js and stumbled upon this code that decodes a data URL into a Buffer. Although the function is not public and exclusively intended to parse encoded ES modules, it sheds light on aspects of data URLs that are apparently not considered by some other answers: the content of data URLs must not be base64 encoded and may be URL encoded, and it may even be unencoded.
Essentially, the Node.js logic boils down to something like the code below plus error handling:
const parsed = new URL(url);
const match = /^[^/]+\/[^,;]+(?:[^,]*?)(;base64)?,([\s\S]*)$/.exec(parsed.pathname);
const { 1: base64, 2: body } = match;
const buffer = Buffer.from(decodeURIComponent(body), base64 ? 'base64' : 'utf8');
This will correctly handle different encodings of a Javascript file with the content console.log("Node.js");:
data:text/javascript,console.log("Node.js");
data:text/javascript,console.log(%22Node.js%22)%3B
data:text/javascript;base64,Y29uc29sZS5sb2coIk5vZGUuanMiKTs=
The resulting buffer can be converted into a string if required with buffer.toString().
This method works for me
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
var data = dataURI.split(',')[1];
var byteString = Buffer.from(data, "base64");
// separate out the mime component
var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
// write the ArrayBuffer to a blob, and you're done
var blob = new Blob([byteString], { type: mimeString });
return blob;
}
to use
var uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
dataURItoBlob(uri)

Resources