I’m in the process of building a secure document storage on behalf of users of a web and mobile application. The goal is to have end-to-end encryption, as in documents will be encrypted and decrypted on device, but not require users to manage a private key themselves.

The plan is to use libsodium to encrypt documents using a symmetric “content encryption key” (CEK), then using envelope encryption to encrypt that CEK with the public key of the users that should have access to the documents. The main question is then, how to store the private keys. Ideally the private key would never leave the user’s device, but that complicates accessing documents from multiple devices, “digital legacy access”, recovery in case of loss of key etc.

I’m not looking for the absolute perfect system where don’t have to trust any part of the system etc, but something in between that and just HTTPS and “encryption at rest” at our storage provider. I do understand that for us to keep the private key weakens the solution, and this question is about how to mitigate that risk as much as possible.

The current idea is to generate a public/private key pair for each user, store the public key in our database a long with other user info, and store an encrypted version of the private key in a different database (potentially a key storage solution like Azure Key Vault) that will have very strict access control, but accessible by the application server. The encryption key for the private key will be a user defined password (or at least a key derived from that password). That way we keep the private key in our possession, but cannot use it without knowing the users password. We would also need some sort of recovery method in case of a lost password, potentially creating a recovery paper-key that users are told to store safely that we can use to decrypt the private key.

In this suggested solution, the users password would need to be sent over HTTPS to our servers to do the encryption/decryption of the private key, and either the key needs to be transported to the users device, or the decrypted CEK will need to be transported to the users device. 

With either the private key and the encrypted CEK, or the decrypted CEK on the device, the document itself can be decrypted.

With this system we would never store unencrypted documents, never store encryption keys a long side documents. We have no way without knowing the users passwords or recovery keys to decrypt the documents. Documents are never unencrypted outside the users device.

Is this a secure system, or is all the complexities around encryption useless since we at some point need to send some keys over the “wire” to the user?

All API communication also requires an API token that you cannot get without using a MFA authentication scheme. So the user defined password described above is just for to decrypt the private key. So one needs to both have an access key using the MFA auth scheme + the user defined password.

  • Some 'zero-knowledge' systems store the users private key, encrypted with another key derived from a password, on the server. When the user authenticates, the encrypted key is sent to the user's device, where the user decrypts the key using the password. All encryption and decryption of documents then takes place on the user's device. So, your server never sees the plaintext documents, and only sees encrypted documents, and never sees the user's decrypted private key.
    – mti2935
    Dec 28, 2021 at 13:31
  • @mti2935; I'd suggest you to convert your comment to an answer.
    – mentallurg
    Dec 28, 2021 at 13:53
  • @mti2935 that is sort of what I tried describing. Although I'm unsure if it's best to send the decrypted private key, and decrypt it locally using the password, or decrypt the private key on the server, use it to decrypt the CEK (the key used to encrypt the document), and then return that CEK to the user. With the CEK the device can then decrypt the document. The server still never sees the plaintext document. Dec 28, 2021 at 16:34
  • @espenhogbakk wrt decrypt the private key on the server - in this case, the server has knowledge of the decrypted private key. The user then has to trust that the server will not use this key to decrypt the CEK, then use this to decrypt the documents. Some users may not be comfortable with this, and that is why 'zero knowledge' (aka 'zero-access' or 'zero-trust') services never see the unencrypted key.
    – mti2935
    Dec 28, 2021 at 17:00
  • Thanks for the suggestion @mentallurg. I may do that at some point, but thought it would be helpful to work through some of the details of OP's ideas through the comments before doing so.
    – mti2935
    Dec 28, 2021 at 17:01

1 Answer 1


The strength of your scheme is determined mainly by the strength of the user password. Anyone who gets user password will be able to decrypt all documents of this user. It is weaker compared to storing private key on the user device only.

I'd suggest you to consider approach with private key on the user devices. To make sure that private key never leaves the device, each device would need its own key pair. On the server side you can store not a single password encrypted with public key, but the password with different device public keys. Normally the number of devices would be relatively small, like 5-10, and if the number of documents is bigger, like 100 - 1000, then this would be relatively small price. Adding new devices can also be done. User would register new public key, then from one of previously registered devices load encrypted password from server, re encrypt it with the new public key and send back to server.

The advantage would be that private key never leaves corresponding device. It would be much harder to attack such scheme, because knowing user password will not be sufficient: The attacker would need also access to the device.

  • I'll update my question, but I forgot to say that the password is a secondary level of authentication. To get access to the website/app one first has to authenticate using a secure authentication scheme that includes MFA. So all API communication requires a token using that MFA auth scheme + the password described in the question. Dec 28, 2021 at 16:29

You must log in to answer this question.

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