Javascript - Client side encryption / key storage

(To be clear: this only protects users in situations that the attacker only gets read-only access and protects users who haven't used the site since an attacker replaced the javascript with a malicious version. It does not protect users from you being malicious from the start unless the user painstakingly verifies / records all javascript that your site delivers them. If that last part is important to you, there might be a way to use ServiceWorkers to alert users whenever a new version of your site's javascript is executed, etc, but that's for another question.)

You can store encryption keys locally in the client with localStorage or IndexedDB. The encryption keys could be strings that your client javascript uses.

On supporting browsers, for increased security you could use the Web Crypto API (+ IndexedDB) instead. With the Web Crypto API, you can generate keys in javascript and use them for encryption/decryption, but the javascript code can not get access to the raw key material no matter what. That means even if an attacker gets access to your server one day and replaces the javascript with a malicious version, they can not replace it with a version that leaks users' keys. (However, they could replace it with a version that makes clients download their files, decrypt them, and upload them back to the server in the background on the next time they go to the site. This would take time and could be noticeable to users and/or you, so it might give you enough time to patch the issue before all user data is leaked.)


If using asymmetric encryption from openpgp.js, the private key is stored encrypted by default and then briefly decrypted to decrypt or sign a message with the users passphrase.

It is never stored un-encrypted and relies on the user remembering the passphrase he used to create the key pair.

In this case even if the hacker found the private keys they are useless without the passphrase.

Downside is we have to train the user to safely store his passphrase somewhere!