I want to implement the following encryption scheme. The data is created and stored on a web server, but related to some user of the system (i.e. it is entered "on behalf" of the user). Both encryption and decryption process should involve a request to a mobile device of this user (the encryption password is located on the device). The point is that nobody, including the server, would be able to approve the encrypted data entry on behalf of the user or later decrypt it without having access to a mobile device of the user.

However, we can’t send the whole data to the device for encryption, because (aside from the matters of security) it could be very large. Also, the decryption is done to provide access to some third party, so there's no need to transfer the data to the device at all. So both encryption and decryption should occur on the server.

Another point is that the encryption/decryption occurs on a per-record basis, so it would be preferable that noone (even the server) at any point in time would be able to decrypt all user data at once.

I need to come up with a protocol or a pattern to do this.

As a precondition, the server already has an ID of the user’s device. This allows the server to send a push notification to the device. The push notification channel is secure in the sense that it is over TLS. However, there is a risk that the messages are stored as plaintext somewhere in the push notification provider database and could leak in the case of a data breach.

I was thinking about the following protocol (for the encryption):

  1. the server generates a one-time key (OTK) and a transaction id (TID)
  2. the server sends a push notification to the device containing the TID
  3. the device sends the TID to the server via HTTPS, receives the plain-text OTK in response
  4. the device encrypts the plain-text OTK with a password known only to the device and "forgets" the plain-text OTK
  5. the device sends the encrypted OTK and the TID via HTTPS to the server
  6. the server uses some symmetric encryption algorithm to encrypt the data with the plain-text OTK, and then "forgets" the plain-text OTK
  7. the server stores the encrypted data together with the encrypted OTK

For the decryption, the protocol is similar.

So my questions are:

  1. Is this approach reasonably secure (by "reasonably" I mean at least as secure as other involved protocols, like OTK generation, HTTPS and some chosen symmetric encryption protocol used on the server)?
  2. Are there any other patterns to do something like this?
  3. Are there any known implementations of these patterns (for any kind of backend, any kind of a mobile device)?
  • Encryption 1&2 can be merged to simplify. If you assume that HTTPS is your protection, then under that assumption what you send inside of it is secure. And if we trust, that forgetting "works", then it seems enough.
    – wojteo
    Jan 1, 2019 at 21:24
  • @wojteo you mean I can just send the OTK? The problem here is that the push messages could be stored unencrypted on the push notification provider side which is out of my control.
    – Sergei
    Jan 2, 2019 at 3:15
  • I'm struggling to understand what you mean? How is the data created on the web server? It seems a bit contradictory to encrypt the data and throw away the OTK if this is data that the server can create anyway.
    – paj28
    Jan 2, 2019 at 20:37
  • @paj28 a third party adds this data to the server database on behalf of the user. The point is that 1) the data may be added only with the user’s consent, 2) the data should be protected with a key belonging only to this user, and 3) the data should decryptable only with the involvement of the user. Throwing away the OTK guarantees that the server can’t later decrypt the record without the involvement of the user.
    – Sergei
    Jan 2, 2019 at 21:11
  • I see. In that case, I recommend using a public key algorithm. Have the third-party encrypt the data with the user's public key, and keep the user's private key on the mobile device. Basically the same design as PGP email.
    – paj28
    Jan 2, 2019 at 21:15

3 Answers 3


Before designing a protocol, we need to make an important decision: do we trust the server?

If we do, the design can be quite simple: HTTPS would be used for communication encryption, and disk encryption would be used for data encryption, and there would be no encryption in application code. All access control decisions like "is this data approved" and "is this third-party authorised" would be done as database records, enforced by checks in application code.

This is the standard approach, used by many thousands of client-server applications, including high-value finance, military, aerospace and healthcare.

In some cases, it is possible to avoid trusting the server. For example, many password managers encrypt your password vault with a master password on the client, and the server only processes the encrypted vault. However, this gets harder with more complex applications, especially when multiple parties are involved. There is a major risk that a scheme will only add the appearance of security, not true resistance to attack.

For example, in the scheme you propose, the server has transient access to the one-time keys. So a hacker (or malicious sys-admin) could harvest data over a period of time. To rectify that I recommend using public-key encryption:

  • Each user of the system would have a private key that only they know, and a public key that is shared with the server and other users.
  • When a third-party creates a record, they encrypt it with a random key (like the OTK), and encrypt the OTK with the recipient's public key. The server stores this in a temporary area until it is approved.
  • A user approves a record by signing a hash of it with their private key. The server then puts the encrypted & signed message in the database.
  • To share a record with a third party, the user encrypts the OTK with the third-party's public key.

Even with all this, the server can potentially cheat by substituting a user's public key with its own. You can partially mitigate that with external monitoring, or an external certificate authority. Ultimately, this is a great increase in complexity for what is probably just a marginal benefit. That's why the standard pattern is to just trust the server.

  • Thanks! Seems like a working scheme. However, in my case the 3rd party is just a user of a web app, so the OTK generation and encryption would still occur on the server. Anyway, either the server or the 3rd party would still have transient access to the OTK. But I like that we don’t need to send the OTK to the user during the encryption. However, we'd still need to send it during the decryption. So I’m still thinking wether this scheme actually adds value without adding too much complexity of asymmetric cryptography (mitigating MITM during public key exchange, establishing trust with a CA etc)
    – Sergei
    Jan 3, 2019 at 7:22
  • @SergeiPetunin - Thanks for accepting my answer and the bounty. With a web app it's effectively impossible to avoid trusting the server, as all the client-side code is provided by the server. In the design above, the third party would only have the OTK for records they create, or where the main user shares the OTK. They wouldn't be able to access records from other third parties. But as you say, you need to think carefully about whether the value added is worth the complexity.
    – paj28
    Jan 3, 2019 at 8:16

EDITED because of misunderstanding

In my opinion, the mechanism described isn't good because of several issues:

  • You're (more or less) about to re-invent asymetric encryption... Generally, re-inventing crypto stuff isn't a good idea ;-)

For the same needs i would:

  1. During "user creation" on server side, ask user device to generate a public/private key pair (gpg, whatever ...). The private key must be passphrase protected. The passphrase will be a random token generated and stored on user device.
  2. User device then push both public and private key to the server.
  3. Server encrypt user data with its public key and store result.
  4. Then data must be decrypted on server, then:
    1. Server request passphrase from User device.
    2. Server decrypt data.
    3. Server forget passphrase.
  • Thanks for the answer. I agree with your points of concern, but the proposed solution is not exactly what I am looking for. Providing the user access to the data on the device side is not the point. The data needs to be decrypted on the server side to be accessible by the third party, but only when the user "unlocks" it via the mobile application (piping the data through the device to decrypt it is also not feasible, since the data volume could be very high).
    – Sergei
    Jan 2, 2019 at 17:17
  • Ok, got it. I will modify my answer according to your comment ;-)
    – binarym
    Jan 2, 2019 at 17:19
  • Sorry, my bad, I didn't make another limitation quite clear. Both encryption and decryption process should involve a user's approval. So the server shouldn't even be able to create an encrypted record without user being involved. Also, I need to provide granular access to the records, so I don't really like the idea of sending to the server a passphrase that allows to decrypt everything at once. I'll add a clarification to the question.
    – Sergei
    Jan 2, 2019 at 17:36

Why do you want to “involve user” during the encryption, since, for example, PGP allows you to encrypt data using a Public Key? At least, it should be safer to encrypt data without sending sensitive stuff from the server to the device.

When registering/initializing:

  • The device generates a “Private Device Key” and “Public Device Key”.
  • The device sends the “Public Device Key” to the server for storing it in the database.
  • The “Private Device Key” is encrypted by a user password and stored securely only on the device.

When saving data:

  • The server generates a “Secret Passphrase” (it must be unique for each record and must not be stored anywhere).
  • The server encrypts data using the “Secret Passphrase”.
  • The server encrypts the “Secret Passphrase” using the “Public Device Key” to obtain “Encrypted Passphrase”.
  • Finally, the server stores the encrypted data and “Encrypted Passphrase”.

When decrypting data:

  • The server sends “Encrypted Passphrase” to the device.
  • The device decrypts “Encrypted Passphrase” and sends “Secret Passphrase” to the server.
  • The server decrypts data using the “Secret Passphrase”.
  • I want to involve the user during the encryption because I don't want anyone to generate any kind of data and encrypt it with the public key of the user without their consent. The process of creating a valid record should be impossible without something that a user has or knows (in my implementation, the password stored on the device).
    – Sergei
    Jan 2, 2019 at 21:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.