Node.js encrypting and decrypting is doubling file size - javascript

I am creating a Node.js application that can encrypt and decrypt image files. However when my code is run I get varying results: Sometimes the decrypted image looks like the original at the top but the bottom half looks corrupted, sometimes the decrypted image is completely there but looks like it was heavily compressed and sometimes the decrypted image is too corrupt to open. Here is an image that demonstrates this. The only thing these results have in common is the encrypted and decrypted images are double the file size of the original image.
const fs = require('fs');
const crypto = require('crypto');
var path = 'C:\\Users\\' + windowsUserName + '\\Desktop\\image';
var fileExtension = '.jpg';
var password = '1234';
var algorithm = 'aes-256-cbc';
var image = fs.createReadStream(path + fileExtension);
var encryptedImage = fs.createWriteStream(path + ' encrypted' + fileExtension);
var decryptedImage = fs.createWriteStream(path + ' decrypted' + fileExtension);
var encrypt = crypto.createCipher(algorithm, password);
var decrypt = crypto.createDecipher(algorithm, password);
image.pipe(encrypt).pipe(encryptedImage);
image.pipe(encrypt).pipe(decrypt).pipe(decryptedImage);
How do I fix the image corruption and file size doubling?

You are trying to decrypt the cypher before it is finished. If you wait until the pipe is done and read the encrypted file, it should not be garbled:
const fs = require('fs');
const crypto = require('crypto');
var path = 'file path';
var fileExtension = '.jpg';
var password = '1234';
var algorithm = 'aes-256-cbc';
var image = fs.createReadStream(path + fileExtension);
var encryptedImage = fs.createWriteStream(path + ' encrypted' + fileExtension);
var encrypt = crypto.createCipher(algorithm, password);
image.pipe(encrypt).pipe(encryptedImage);
encryptedImage.on("finish", function(){
var decrypt = crypto.createDecipher(algorithm, password);
var decryptedImage = fs.createWriteStream(path + ' decrypted' + fileExtension);
var encryptedImage = fs.createReadStream(path + ' encrypted' + fileExtension);
encryptedImage.pipe(decrypt).pipe(decryptedImage);
})

Related

Convert a specific google sheets tab into a pdf

For a project I am currently working on I'm trying to find a way that lets me turn a specific google sheets tab into a pdf using javascript
You have to put your own id in this script
function savePDF(){
const docID = '______id of the spreadsheet________';
const feuilleID = '___id of the sheet______';
const dossier = DriveApp.getFolderById('______id of the folder_______');
const fichier = 'name of the file.pdf'
const url = 'https://docs.google.com/spreadsheets/d/' + docID + '/export?';
const exportOptions =
'exportFormat=pdf&format=pdf' +
'&size=A4' +
'&portrait=true' +
'&fitw=false' +
'&sheetnames=false&printtitle=false' +
'&pagenumbers=false&gridlines=false' +
'&fzr=false' +
'&gid=' + feuilleID;
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
var reponse = UrlFetchApp.fetch(url + exportOptions, params).getBlob();
dossier.createFile(reponse.setName(fichier));
}

How to generate SharedKeyLite for Azure Table Storage REST request

I'm trying to call Azure Table Storage using Postman but keep getting :
Server failed to authenticate the request. Make sure the value of
Authorization header is formed correctly including the signature.
The code I am using for the pre-call script in Postman is as follows:
var storageAccount = "**mystorageaccount**";
var accountKey = "**mystoragekey**";
var date = new Date();
var UTCstring = date.toUTCString();
var data = date + "\n" + "/**mystorageaccount**/**mytable**"
var encodedData = unescape(encodeURIComponent(data));
var hash = CryptoJS.HmacSHA256(encodedData, accountKey);
var signature = hash.toString(CryptoJS.enc.Base64);
var auth = "SharedKeyLite " + storageAccount + ":" + signature;
postman.setEnvironmentVariable("auth", auth);
postman.setEnvironmentVariable("date", UTCstring);
The headers in Postman are as follows:
Authorization : {{auth}}
date : {{date}}
version : 2015-12-11
I am guessing the issue may be with the data variable, but running out of ideas.
The reason you're getting this error is because you're not converting your account key to a buffer. Please change the following line of code:
var hash = CryptoJS.HmacSHA256(encodedData, accountKey);
to
var hash = CryptoJS.HmacSHA256(encodedData, Buffer.from(accountKey, 'base64'));
And you should not get the error.
UPDATE
I also got the same error. Please try the following code:
var storageAccount = "**mystorageaccount**";
var accountKey = "**mystoragekey**";
var date = new Date();
var UTCstring = date.toUTCString();
var data = UTCstring + "\n" + "/**mystorageaccount**/**mytable**"
var encodedData = unescape(encodeURIComponent(data));
var hash = CryptoJS.HmacSHA256(encodedData, CryptoJS.enc.Base64.parse(accountKey));
var signature = hash.toString(CryptoJS.enc.Base64);
var auth = "SharedKeyLite " + storageAccount + ":" + signature;
postman.setEnvironmentVariable("auth", auth);
postman.setEnvironmentVariable("date", UTCstring);
I just tried the code above and was able to list entities in my table.

How to Generate and validate JWE in node js?

I tried the bellow code to create RSA-OAEP and A128GCM JWE generator and validator. it works with node js , ie, encrypt claims and generate the jwe and decrypt the same gives me the claims. but it is not working with the other clients , like nimbusds jose, jose4j. So for a sure I am missing something.
I am doing this by reading https://www.rfc-editor.org/rfc/rfc7516
index.js
var crypto = require('crypto');
var randomstring = require("randomstring");
var ursa = require("ursa");
var fs = require("fs");
var base64url = require('base64url');
var ascii = require("./ASCII");
var claims = {
firstName: "vimal"
};
var header = {
"enc": "A128GCM",
"alg": "RSA-OAEP"
};
var headerBase64Url = base64url.encode(JSON.stringify(header));
console.log("headerBase64Url : " + headerBase64Url);
console.log("headerBase64Url to UTF8 : " + base64url.decode(headerBase64Url));
var cek = randomstring.generate(16);
console.log("cek : " + cek);
var publicKey = ursa.createPublicKey(fs.readFileSync('./pubkey.pem'));
var encryptedKey = publicKey.encrypt(cek, 'utf8', 'base64');
console.log("encryptedKey : " + encryptedKey);
// var privateKey = ursa.createPrivateKey(fs.readFileSync('./privkey.pkc8.pem'));
// var decryptedKey = privateKey.decrypt(encryptedKey, "hex", "utf8");
// console.log("decryptedKey : " + decryptedKey);
var iv = randomstring.generate(12);
console.log("IV : " + iv);
var cipher = crypto.createCipheriv('aes-128-gcm', cek, iv);
cipher.setAAD(Buffer.from(ascii.toASCII(headerBase64Url)));
var chipherText = cipher.update(JSON.stringify(claims), "utf8", "base64");
chipherText += cipher.final('base64');
console.log("chipherText : " + chipherText);
var chipherTextAuthTag = cipher.getAuthTag().toString("base64");
console.log("chipherText Auth Tag : " + chipherTextAuthTag);
var jweToken = headerBase64Url + "." + base64url.encode(encryptedKey, "base64") + "." + base64url.encode(iv, "base64") + "." + base64url.encode(chipherText, "base64") +
"." + base64url.encode(chipherTextAuthTag, "base64");
console.log("jweToken : " + jweToken);
// decrypt
var jweTokenParts = jweToken.split(".");
var headerHex = base64url.decode(jweTokenParts[0]);
console.log(headerHex);
var encryptedKeyHex = base64url.decode(jweTokenParts[1], "base64");
console.log(encryptedKeyHex);
var ivHex = base64url.decode(jweTokenParts[2], "base64");
console.log(ivHex);
var chipperTextHex = base64url.decode(jweTokenParts[3], "base64");
console.log(chipperTextHex);
var chipherTextAuthTagHex = base64url.decode(jweTokenParts[4], "base64");
console.log(chipherTextAuthTagHex);
var privateKey = ursa.createPrivateKey(fs.readFileSync('./privkey.pkc8.pem'));
var decryptedKeyHex = privateKey.decrypt(encryptedKeyHex, "base64", "utf8");
console.log("decryptedKeyHex : " + decryptedKeyHex);
var dcipher = crypto.createDecipheriv('aes-128-gcm', decryptedKeyHex, iv);
dcipher.setAAD(Buffer.from(ascii.toASCII(jweTokenParts[0])));
dcipher.setAuthTag(Buffer.from(chipherTextAuthTagHex, "base64"));
var planText = dcipher.update(chipperTextHex, "base64", "utf8");
planText += dcipher.final('utf8');
console.log(planText);
ASCII.js
function toASCII(text) {
var ascii = "";
for (var f in text) {
ascii = ascii + text.charCodeAt(f);
}
return ascii;
}
module.exports = {
toASCII: toASCII
};
Generated public and private key using the below command
openssl genrsa -out ./privkey.pem 2048
openssl pkcs8 -topk8 -inform pem -in ./privkey.pem -outform pem -nocrypt -out ./privkey.pkc8.pem
openssl rsa -in ./privkey.pkc8.pem -pubout -out ./pubkey.pem
Please help me to fix this code.
This is my public key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyT0HZHrlk8nN8HfTDq5t
dv6UCKHf7+RF1bICxaR4h2vzGCqcYUlzyW7Sp33BZAHDeO3d5tX26m7z2EOPaOPn
SSe6psgvBmE4Ivyc3+uyIYJm+Eo9bXiqqfvuDRidXsHj23w41l6GMERKbpOBVvp+
dmWt/cWU8FESvKUqNw/Au2R9mE1sQ5irMQj42hhUrVA1azs2AYpysKNZABm11YMb
/vd/xSPLsNqcDefuCs7j3CcT9xNLrMV6K63QjCAP+h0IMuA+ayi3WRUbl04D6cAC
AC97/cKMC0YLRumbf5x5/KjUBwNlzgRA3/n9KE+YjJ9Rs9dtiGnlg+c70Kgx4hm9
9QIDAQAB
-----END PUBLIC KEY-----
Generated JWE
eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.A_KMJqfr6FZSoejRGWPsZKMCNZmPyaWoNvpG6KMRpqyv7Alb8Ui5ELWLjpcaemjNM8EFU8d4-Yzz8jRRZ5TpK2pEEc4NXfDLcnj2b0-38_-P-0HbW1YyMkkGMVXIpJDYMo8vKgVHIBj0pNlzgF7xmxLFWZlJlXmYzXi4QZcig5HezHg7AAQB7U2HYry25cQDYam60747gRCH372NaSm_dfRCNvH8copVXqiJGNs6xhslxMt_LopnZt9iIcAC9o7m0FPdnu_0Ui_w0jp5OUam8i0v8k6SSajBvXSedtUENxcehPGRSFYzi8KqZ53u4CpRygir84wNFRTi7zmLV6TlVw.84xgyx6TTI8I.4zTt1fI1XCbvxW2L-pH8_Mfp_ySF.EPmpEHiMYAvA2nqz9M0v5Q
It looks like the IV is not correctly encoded using Base64 Url.
On my computer, when I execute the following line of code:
console.log(iv);
console.log(base64url.encode(iv, "base64"));
Then the two lines are identical.
When I modify your code:
var jweToken = headerBase64Url + "." + base64url.encode(encryptedKey, "base64") + "." + base64url.encode(iv, "base64") + "." + base64url.encode(chipherText, "base64") +
"." + base64url.encode(chipherTextAuthTag, "base64");
lnto these lines:
var bufferedIV = new Buffer(iv);
var jweToken = headerBase64Url + "." + base64url.encode(encryptedKey, "base64") + "." + base64url.encode(bufferedIV, "base64") + "." + base64url.encode(chipherText, "base64") +
"." + base64url.encode(chipherTextAuthTag, "base64");
Then it works fine ; I can load the resulting JWE using my PHP library.
From my understanding, the error comes from the base64url dependency that does not correctly encode the IV.

How to send an email with a PDF through a script inside google spreadsheets?

The script just works as I want, I didn't develop it, I forgot the author's site, sorry if I don´t mention he/she.
The big problem is that I´m unable or I can't figure out how can I send an email with the PDF created through the script, I don't want to sent it in Zip format and if you release, the PDF file name´s change every time you use the spreadsheet, here I leave the code:
function spreadsheetToPDF(){
var key = '1hBbCnmca_wx4wbQx93Vf4d9cfUwGbFSP9hKgv9Qu7Vk'; //docid
var index = 0; //sheet gid / number
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ActiveSheet = ss.getSheetByName('Sheet 1');
var timestamp = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd'-'HHmm");
var plainonum = ActiveSheet.getRange("C5").getValue(); //order number
var supp_name = ActiveSheet.getRange("C12").getValue(); //supplier
var onum = ('0000' + plainonum ).slice(-4); //sets leading zeros to order number
var description = ActiveSheet.getRange("C18").getValue(); //description
var email = ActiveSheet.getRange("D1").getValue(); //email
var name = 'Order-' + onum +'-' + supp_name + '-' + description + '-' + timestamp + '.pdf'; //makes pdf filename
SpreadsheetApp.flush(); //ensures everything on spreadsheet is "done"
//make the pdf from the sheet
var theurl = 'https://docs.google.com/spreadsheets/d/'
+ key
+ '/export?exportFormat=pdf&format=pdf'
+ '&notes=false'
+ '&size=letter'
+ '&portrait=true'
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false'
+ '&gridlines=false'
+ '&fzr=false' // do not repeat frozen rows on each page
+ '&gid='
+ index; //the sheet's Id
var token = ScriptApp.getOAuthToken();
var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });
var pdf = docurl.getBlob().setName(name).getAs('application/pdf');
//save the file to folder on Drive
var fid = '0B6iePPHdQRoxQVB3eERrb1c3MUE';
var folder = DriveApp.getFolderById(fid);
folder.createFile(pdf);
var pfd = DriveApp.getFileById(pdf.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:name,content:pfd, mimeType:'application/pdf'};
// Here I need to send the email
// GmailApp.sendEmail(email, "The subject", "The body content") // AND The PDF File witch I can´t attach
//Show a Popup with a message that a file was created inside a folder
SpreadsheetApp.getUi().alert('New document created in' + ' ' + folder);
}
After getting the file from drive using the DriveApp.getFolderById(id), you may then send it as an attachment using MailApp.sendEmail(recipient, subject, body, options).
Here's the sample code that you can try:
// Send an email with two attachments: a file from Google Drive (as a PDF) and an HTML file.
var file = DriveApp.getFileById('1234567890abcdefghijklmnopqrstuvwxyz');
var blob = Utilities.newBlob('Insert any HTML content here', 'text/html', 'my_document.html');
MailApp.sendEmail('mike#example.com', 'Attachment example', 'Two files are attached.', {
name: 'Automatic Emailer Script',
attachments: [file.getAs(MimeType.PDF), blob]
});
Solution given in this SO post might also help.
As I suspected, I was emailing only the name of the file but without the content, so I made a little variation to the var under the folder creation:
var archivo = docurl.getBlob().getAs('application/pdf').getBytes();
// Create a PDF from the active sheet, save it under a specific directory and send the PDF by mail
function spreadsheetToPDF(){
var key = 'abcdefghijk1234567890'; //docid (actual spreadsheet)
var index = 0; //sheet gid / number
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ActiveSheet = ss.getSheetByName('Hoja 1');
var timestamp = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd'-'HHmm");
var plainonum = ActiveSheet.getRange("C5").getValue(); //order number
var supp_name = ActiveSheet.getRange("C12").getValue(); //supplier
var onum = ('0000' + plainonum ).slice(-4); //sets leading zeros to order number
var description = ActiveSheet.getRange("C18").getValue(); //description
var correo = ActiveSheet.getRange("D1").getValue(); //correo electrónico
var name = 'Order-' + onum +'-' + supp_name + '-' + description + '-' + timestamp + '.pdf'; //makes pdf filename
SpreadsheetApp.flush(); //ensures everything on spreadsheet is "done"
//make the pdf from the sheet
var theurl = 'https://docs.google.com/spreadsheets/d/'
+ key
+ '/export?exportFormat=pdf&format=pdf'
+ '&size=A4'
+ '&portrait=true'
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false'
+ '&gridlines=false'
+ '&fzr=false' // do not repeat frozen rows on each page
+ '&gid='
+ index; //the sheet's Id
var token = ScriptApp.getOAuthToken();
var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });
var pdf = docurl.getBlob().setName(name).getAs('application/pdf');
//save the file to folder on Drive
var fid = 'abcdefghij1234567890';
var folder = DriveApp.getFolderById(fid);
folder.createFile(pdf);
//get the file, name and content to send it by email
var archivo = docurl.getBlob().getAs('application/pdf').getBytes();
var attach = {fileName:name,content:archivo, mimeType:'application/pdf'};
// Send email with the PDF attached
GmailApp.sendEmail(correo, "The subject", "The body content", {attachments:[attach]});
//Show a Popup with a message that a file was created inside a folder
SpreadsheetApp.getUi().alert('Nuevo Documento creado en el folder' + ' ' + folder);
}

Azure Account Shared Access Signiture

I am trying to construct an Account level Shared Access Signiture so my client can access all containers in a storage account. I am following these docs Account SAS. It seems straight forward enough but I keep getting the following error message:
"Signature did not match. String to sign used was accountname\nrl\nb\nsc\n\n2016-10-09\n\n\n2015-04-05\n".
My parameters are identical so I suspect it has something to do with how I am hashing the String to Sign. Below is how I construct the token.
var crypto = require('crypto');
var accountName = 'accountname';
var accountKey = 'tH37FTlG3TUT86caMrt2y5kOzof8nFqqA6spzg6r7HPRojE1zDiLJD/xE4oLFDh4RNqAmymvlV7fm8W4SF8cJg==';
var signedPermissions = "sp=rl";
var signedServcies = "ss=b";
var signedResourceType = "srt=sc";
var signedExpiry = "se=2016-10-09";
var signedVersion = "sv=2015-04-05";
var stringToSign = accountName + "\n" + signedPermissions + "\n" + signedServcies + "\n" + signedResourceType + "\n" + signedExpiry + "\n" + signedVersion + "\n";
var hmacsha256 = crypto.createHmac('sha256', accountKey).update(stringToSign).digest('base64');
var token = signedPermissions + "&" + signedServcies + "&" + signedResourceType + "&" + signedExpiry + "&" + signedVersion + "&sig=" + hmacsha256;
I have tried using crypto-js as well but to no avail. The final URL used to access a blob in a container is...
"https://accountname.blob.core.windows.net/containername/blobName?srt=sc&se=2016-10-09&api-version=2015-04-05&sp=rl&ss=b&sv=2015-04-05&sig=IFD2wyfRAsHGU5IFg3RbwSJW6tRE0m0%2FxgAYvJ%2FmnEk%3D"
I have been trying for days and really would appreciate knowing what I'm doing wrong. Thanks.
Benzene, for stringToSign, the value should NOT has the parameter name?
var signedPermissions = "rl";
var signedServcies = "b";
var signedResourceType = "sc";
var signedExpiry = "2016-10-09";
var signedVersion = "2015-04-05";
Please try the following (code shamelessly taken from Azure Storage Node.js library):
var hmacsha256 = crypto.createHmac('sha256', new Buffer(accountKey, 'base64')).update(stringToSign, 'utf-8').digest('base64');

Categories