I've trying to encrypt a Blob of pdf file and store it in the localStorage and read and decrypt it later when i'm offline.
My app is written in AngularJS and the encryption is done with forge
Here is my code for downloading the pdf file:
$http.get(url, {
headers: {
"Application-Authorization": appContext.user.token
},
responseType: "blob"
}).then(function(response) {
backendCipherService.encryptPDF(response.data, appContext.user.password).then(function(data) {
$localForage.setItem("document::" + document.documentId + "::pdf", data.json).then(function(success) {
console.log("cached pdf", document.documentId);
deferred.resolve();
}, function(error) {
console.log("Error", response.data, document.documentName);
deferred.reject(error);
});
});
}, function(error) {
deferred.reject(error);
});
and here is my code for encryption and decryption (backendCipherService):
this.encryptPDF = function(blob, password) {
var salt = forge.random.getBytesSync(256);
var key = forge.pkcs5.pbkdf2(password, salt, 40, 32);
var iv = forge.random.getBytesSync(32);
var cipher = forge.cipher.createCipher('AES-CBC', key);
cipher.start({iv: iv});
var deferred = $q.defer();
var uint8Array = null;
var arrayBuffer = null;
var fileReader = new FileReader();
fileReader.onload = function(progressEvent) {
arrayBuffer = this.result;
uint8Array = new Uint8Array(arrayBuffer);
};
fileReader.readAsArrayBuffer(blob);
fileReader.onloadend = function() {
var inp = uint8Array;
console.log(inp);
cipher.update(forge.util.createBuffer(inp));
cipher.finish();
var encrypted = cipher.output;
var data = forge.util.bytesToHex(encrypted);
var obj = {"salt": forge.util.bytesToHex(salt), "iv": forge.util.bytesToHex(iv), "encrypted": data};
deferred.resolve({
json: angular.toJson(obj)
});
};
return deferred.promise;
};
this.decryptPDF = function(json, password) {
var obj = angular.fromJson(json);
var key = forge.pkcs5.pbkdf2(password, forge.util.hexToBytes(obj.salt), 40, 32);
var iv = forge.util.createBuffer();
var data = forge.util.createBuffer();
iv.putBytes(forge.util.hexToBytes(obj.iv));
data.putBytes(forge.util.hexToBytes(obj.encrypted));
var decipher = forge.cipher.createDecipher('AES-CBC', key);
decipher.start({iv: iv});
decipher.update(data);
decipher.finish();
return decipher.output.data;
};
and here is the code for converting the decrypted value to a Blob again:
return $localForage.getItem("document::" + documentId + "::pdf").then(function(pdf) {
var pdfBlob = new Blob([backendCipherService.decryptPDF(pdf, appContext.user.password)], {type: 'application/pdf'});
return pdfBlob;
}, function(error) {
return error;
});
This in general works but the pdf can not be read from PDF.js and i get the error:
Error: Bad FCHECK in flate stream: 120, 194
pdf.worker.js:252 at error (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:252:15)
at Object.FlateStream (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:31394:7)
at Object.Parser_makeFilter [as makeFilter] (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:30281:18)
at Object.Parser_filter [as filter] (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:30259:25)
at Object.Parser_makeStream [as makeStream] (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:30234:21)
at Object.Parser_getObj [as getObj] (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:30022:28)
at Object.XRef_fetchUncompressed [as fetchUncompressed] (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:4323:28)
at Object.XRef_fetch [as fetch] (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:4280:26)
at Object.XRef_fetchIfRef [as fetchIfRef] (http://localhost:8080/client/components/pdfjs-dist/build/pdf.worker.js:4261:19)
pdf.worker.js:235 Warning: Unsupported feature "unknown"
pdf.worker.js:235 Warning: Invalid stream: "Error: Bad FCHECK in flate stream: 120, 194"
pdf.js:235 Warning: Unsupported feature "unknown"
It seems that the pdf is corrupted somehow.
Any ideas what's wrong? Thx