What is the best way to use Forge to encrypt and decrypt a PDF blob before storing it in localStorage?

I'm attempting to encrypt a Blob of a PDF file and save it in the localStorage for later decryption when offline.

My AngularJS app uses forge for encryption.

Below is the code to download 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);
                });

Here is the 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 to convert the decrypted value back to a Blob:

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

While this generally works, I'm unable to read the PDF using PDF.js and encountering the following 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)
   ... (error continues)
pdf.worker.js:235 Warning: Unsupported feature "unknown"
pdf.worker.js:235 Warning: Invalid stream: "Error: Bad FCHECK in flate stream: 120, 194"

It seems the PDF is somehow corrupted.

Any insights on what might be going wrong? Thanks

Answer №1

Your function to decrypt PDF files, named `decryptPDF`, is currently outputting a binary-encoded string. This format is compatible with forge v0.6.x. To convert it back to a Uint8Array, follow these steps:

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

Ensure you verify the return value of `decipher.finish()` to confirm that it returns `true`. If not, it indicates that the decryption process was unsuccessful.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieving information stored in local storage from a different path using Vuex

Using the config panel route, I am fetching data and setting it to local storage using Vuex and StoreJS: const state = { message: [], // console.log(message); sec: 0, // other state }; const getters = { message: ( ...

Change the pseudo class "typed::after" to eliminate the element

Hey there, I need some assistance on how to target a specific element with the class .typed::after using JavaScript. The code provided below only targets classes without ::after or ::before, and the cursor is currently positioned on the after of 'type ...

Uncovering Inline Styles Infused with Javascript for Effective Debugging of Javascript Code

SITUATION: I have recently inherited a website from the previous developer who has scattered important functions across numerous lengthy JS files. I am struggling to track down the source of an inline CSS style within the JS or identify which function is d ...

Unlocking information, utilizing AES GCM through the OpenSSL EVP interface on iOS devices

Here is the code I am using to decrypt the data: -(NSString*)_decrypte:(NSString*)encrypted { NSString *decrypted; NSData *enc = [[NSData alloc]initWithBase64EncodedString:encrypted options:0]; int len = (int)[enc length]; Byte *cipher = ...

Is there a way to incorporate innerhtml (or innertext) with the h() function for adding content?

Due to certain requirements, I need to utilize virtual DOM. Below is the code snippet that I am working with: // test.js import { h, ref } from 'vue' const ButtonCounter = { name: 'button-counter', props: { tag: { type: S ...

Even though all criteria are met, I still cannot assign a value to the property following the application of the filter method

const selectSeatEventCallback = ( price, flightNum, segmentKey ) => { var postData = { ...state.post }; postData.IsSeatChosen = true; postData.AirPassengerList.filter( (passenger) => ...

Postponing the execution of a controller until all JSON files have been fully loaded

I am currently trying to grasp the concepts of AngularJS, so my question might not be perfect. Is it feasible to delay the execution of a controller until the json files are fully loaded in a separate function? Below is the controller code: app ...

Issue with writing to VS Code user settings. To resolve errors/warnings, access user settings and attempt operation again

While attempting to modify the theme of my VS Code, I encountered an issue: Unable to write into user settings. Please open the user settings to correct errors/warnings in it and try again. Upon opening the user settings, a settings.json file appeared wit ...

Retrieve dashboard configurations in AngularJS by making an $http request prior to initiating the dashboard controller

I am currently immersing myself in Angular and tackling a complex dashboard framework all built with Angular. Prior to loading the controllers, I need to fetch various dashboard settings from the server using $HTTP. These settings play a crucial role in de ...

When the second click triggers the loading of a JSON lot via AJAX

As a newcomer to jQuery and ajax, I am in the process of developing an application where content is loaded from a JSON file based on the navigation option selected. Here is the code snippet I've been working on: $(document).ready(functi ...

AngularJS routing always displays 'index.html#!' in the URL

In my AngularJS app within a website project in Visual Studio, I am utilizing ui-router. The issue is that it only functions with the route http://localhost/index.html#!/my-page, when what I desire is for the route to simply be http://localhost/my-page. I ...

How to implement Test-Driven Development using AngularJS with Karma and Jasmine

I am currently learning how to write unit tests for my application using karma and jasmine. As a newbie in unit testing, I have written the following code snippet: $scope.$watch('filterParams.statusModel', function() { $scope.customFilte ...

npm fails to install the dependencies listed in the package.json file

I've encountered an unusual issue. I'm attempting to install project dependencies on my server using a simple npm i command, but it's not generating a node_modules folder. I've already tried various suggested solutions such as running ...

What is the method to configure Angular to wait for the server to load session information data?

The server holds session information that is utilized in several controllers within my application. Is there a way to have Angular wait until the session has fully loaded during startup? ...

Unusual JavaScript AJAX antics

I have a situation that looks like this: elFinder.prototype.commands.info = function() { this.exec = function(hashes) { var temp_array = new Array(), temp_html = new String(); var request = new XMLHttpRequest(); ...

Error encountered: Nitrogen is undefined

For the past three years, my Nitrogen web framework powered site has been functioning smoothly across all browsers. However, I recently encountered an issue where postbacks would randomly fail to respond in Google Chrome and Opera, with the console display ...

Error encountered in Clash of Clans API when attempting to retrieve information

VM100:1 Uncaught SyntaxError: Unexpected token 'E', "Error: " is not valid JSON at JSON.parse (<anonymous>) at Object.success (ajax.js:15:21) at c (Jquery.js:2:25266) at Object.fireWith [as resolveWith] (Jquery.js: ...

Encountering an issue with React where the useContext hook is returning undefined instead of

I am facing an issue where I am attempting to access state and setState from the Store file, but it returns as undefined. Can someone help me understand what is causing this problem and how I can resolve it? import React, {createContext, useState} from &ap ...

What is the process for displaying a three.js project?

I've been trying to follow a beginner's tutorial on three.js from this link, but I'm encountering an issue in part 2 where nothing seems to render on my webpage. Despite checking out other guides, I can't seem to solve the problem. I u ...

Interfacing between JavaScript and Objective-C on iOS devices

One method of communication between iOS and JavaScript involves creating fake URLs in JavaScript and appending a string as a parameter to Objective-C code. This URL is then parsed in the delegate method: -(BOOL)webView:(UIWebView *)webView shouldStartLoad ...