How can i encrypt and decrypt a pdf blob with forge and store in localStorage?

Deadly 提交于 2019-12-01 06:06:47

问题


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


回答1:


Your decryptPDF function is returning a binary-encoded string, which is the native format forge v0.6.x works with. To convert that back to a Uint8Array do this instead:

decipher.finish();
return s2a(decipher.output.getBytes());

function s2a(str) {
    var view = new Uint8Array(str.length);
    for (var i = 0, j = str.length; i < j; i++) {
        view[i] = str.charCodeAt(i);
    }
    return view;
}

You should also check the return value of decipher.finish() to ensure it is true. Otherwise, the decryption may have failed.



来源:https://stackoverflow.com/questions/28585353/how-can-i-encrypt-and-decrypt-a-pdf-blob-with-forge-and-store-in-localstorage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!