Currently, I'm trying to create a web-only end to end encrypted chat, with message persistency.

I did some readup on how to create an end to end encrypted chat in JS, I found out there are quite some libs for encryption in js, which is good to know. I'd be capable of writing a chat straightaway now.

However, I still have some problems thinking about the persistency point of view - How would that work? Let's say, my server stores the encrypted messages, and the client would ask for them when loading the chat, so he can see a chat history.

Most of the tutorials I saw didn't bother with persistence, they just created keys on the fly for each load.

My main problem right now is, that I'd somehow have to persist the chat key for the customer, but I don't know how.

If it is cookie-based, it would probably be lost at some point and with that all messages are lost. Also, this wouldn't work with logins on multiple devices

The only solution I can think of is to store the keys on the database and hand them out to the customer when necessary, but how do I do this without getting knowledge about the keys? As soon as I as a website maintainer have all the info about the customer's keys, it's not really end to end encrypted anymore, right? However, this is the only way I could think of it right now. For this, I would probably have to generate a key-set on signup, which I will then hand out to the customer on login. This key-set will be stored on the database in an encrypted way (My app does have general-purpose encryption for settings etc).

Is this simply a tradeoff I have to do, picking between true end to end encryption and portability between other devices?

  • I recommend to look outside of chat and instead at protocols like GPG or S/MIME for mail. These use public key cryptography which allows to safely store the messages at some untrusted place (mail server) while still allowing everybody who has one of the private key for one of the message keys to decrypt the data. Of course users need to find a way to backup their local key pairs and to share keys between there own devices - but these are per user keys and not per session or per message. May 18, 2020 at 8:58

2 Answers 2


I am the developer of https://www.encryptedsend.com/, which is a browser-based end-to-end encrypted messaging system with message persistency. Encrypted messages are stored on the server, as you describe in your question.

With regard to your question,

My main problem right now is, that I'd somehow have to persist the chat key for the customer, but I don't know how

There are a number of ways to handle key management in in-browser crypto applications:

One solution is to simply derive a key from a password that the user enters when the he/she begins a session with the application. Then, the key is derived from the password (via client-side scripting, in-browser) using a key derivation function such as PBKDF2, with a large number of iterations. This solution is simple to implement, and has the advantage of not requiring any storage on the client side, and does not create challenges if users need to access the system from multiple devices, but may be susceptible to brute-force attacks if weak passwords are used.

Another solution is to use IndexedDB to store users' private keys. See more information about this solution here. This solution is more resilient to brute-force attacks than the above solution (because the key is not derived from a password), but the private key is stored unencrypted in IndexedDB (see here), and this solution may present challenges if the user wants to access the system from multiple devices, as this would require keys to be transferred from IndexedDB on one device to IndexedDB on another device.

Yet another solution is to store the private key in a file, which the users is responsible for storing securely on his/her system. For additional security, this file is encrypted using symmetric encryption, with a key derived from a passphrase via PBKDF2 with a large number of iterations. When the user begins a session with the application, he/she provides the key file to the browser, along the password to decrypt the file, and client-side in-browser scripting decrypts the file to access the private key. This private key never leaves the web browser, and is then used to authenticate the user with the server, and to decrypt encrypted messages downloaded from the server. This solution is resilient to brute-force attacks (because the underlying key is generated randomly, instead of from a password), it does not store the key unencrypted on the user's system, and the user can access the system from multiple devices by (securely) transferring the file to each device. This is the method used in EncryptedSend. For more information, see the whitepaper.


Is this simply a tradeoff I have to do, picking between true end to end encryption and portability between other devices?

Not necessarily. The tradeoff is between true end to end encryption and developer/user convenience. If you think beyond the constraints that you have in your design, you can indeed build a true end to end encrypted system.

Right now you seem to be constrained to using a public JS library for encryption and web browsers as clients. This, speeds up your development which is great! But, you'll have to rely on the end user to maintain the keys. So, you do have end to end encryption at the cost of convenience but not at the cost of portability between devices. Users of PGP already do this.

If you are not limited to the particular libraries, you can look at other protocols like Steffen and mti suggested. You can look at: Which protocols exist for end-to-end encrypted group chat? for suggestions on other protocols.

If you are okay with building your own client, then there are keystores that you can use for your end client. Then, you can have a new device registration flow that can sync the keys between clients without you having to store them on the server side.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .