1

I have an architecture which requires a certain subset of data to be more heavily secured and encrypted. The main parameters which I believe meet the scope of the project are as follows:

  • Data should be encrypted in transit
  • Data should be encrypted at rest
  • The API Server should never be handling unencrypted data of this type
  • A developer/sysadmin/db admin should not have sufficient information in a vacuum to compromise encrypted data
  • Data should only be decrypt-able by authenticated end users who have permissions to access those resources

Architecture

  • A Mobile app on iOS/Android
    • User sessions have a new RSA Key Pair after each log in/token expiration
  • An API Server (secured vis TLS)
    • The API Server has it's own private key for encrypting data to the database
  • A Database Server

Initial Model

I've roughly conceived what I think will be a close fit for this system and would like to see how it stands up to some educated criticisms. The initial design is as follows:

Authentication

  • A user logs into the mobile app (the client).
  • After a successful authentication, the client generates an RSA Key Pair
  • After a key pair is generated the private key is stored securely on the local device and the public key is sent to the api to be stored in the end users session.

Creating A Shared Encrypted Resource Group

  • A logged in user sends an api request (via the client) to create a resource group POST /resource-group
  • The API receives the POST request and creates the resource-group, during creation the group is assigned it's own RSA Key Pair, that private key is encrypted with the server key for database storage AND encrypted with the clients public key and returned to the client

Creating A Shared Encrypted Resource In a Group

  • A logged in user sends an api request (via the client) to create a new resource inside of a resource-group, the resource has data encrypted with the resource-group key POST resource { groupId, dataEncryptedWithResourceGroupKey }
  • The API receives the resource and re-encrypts the sensitive data using the server key before storing in the DB.

Retrieving A Shared Encrypted Resource From a Group

  • A logged in user sends and api request (via the client) to get a resource from a resource-group they have access to. GET resource [...resourceIds]
  • The API receives the GET request and fetches the resource(s) from the database. The API uses the server key to decrypt the sensitive data resulting in sensitive data now only encrypted with the resource-group key (which the user has at this point and/or could request whenever necessary)
  • The API encrypts the sensitive data with the end users public key and sends the resource to the end user and the end user finally decrypts the sensitive data using their private key followed by the resource-group key

Specific Questions / Unknowns

  1. My initial model doesn't take into account transient access. (ex. If user A had access to resource-group 1 yesterday and somehow stored the private key, then tomorrow no longer has access to that resource group) Is this a valid concern? Are there any good commonplace patterns to address this?
  2. Is this pattern sufficiently secure against MITM attacks? If not what vectors do you see being compromised?
  3. What bit size RSA key would be a good choice to balance security and performance. (I'm not storing any financial/identity data and the quantum computing gotcha is not interesting either)
  4. Any other criticisms are welcome. How can this be the best version of itself?

1 Answer 1

3

First thing: this is not E2E. The server holds the private key for resource groups, so it can decrypt/log/change anything. A developer or database administrator is in position to compromise all data.

To be really E2E, users should be required to receive public keys out of band. Receiving them from your app means the server can issue a keypair for each user, and decrypt, record, re-encrypt and forward all messages. It must be possible for each user to share their public keys (think of the Share functionality on Android, for example) so they don't depend on the server for that.

After that, users should create a resource, encrypt locally with a symmetric key, encrypt the key with the public keys of all intended recipients, and send the resource plus the encrypted symmetric key to the server. The recipients would download both, decrypt the symmetric key with their private key and read the data. The server must not have any private key nor any symmetric key on clear because that breaks E2E.

User must store the public keys of their friends too, server should not supply them. If the user supplies them, the server is in position of impersonation. Public keys must be received out of band and imported on your app.

MITM depends on your application properly checking TLS certificates, and if the server does not provides any keys to the clients. If both the server and the client check TLS certificates, it's not possible for an attacker to intercept and change data. But if the client allows for invalid certificates to be used and still establish a connection, it will be vulnerable. If the server never provides any public key, it's not possible to impersonate any client.

Transient access is not trivial to implement. If you employ the changes I wrote, any user that was allowed on the resource group yesterday will still have access to data sent yesterday, but not the next ones. The users posting to the resource group will just not use the removed user's key on new messages, and the user will not be able to decrypt anything. The same happens to messages sent before the membership: his key wasn't used to encrypt the symmetric key and he is unable to read them unless another user forwards him the message.

For AES key (not RSA), 192 bits is enough for the foreseeable future. 128 bits are enough for the next decade or so, but it does not hurt having 192 today. For RSA, 2048 bits are considered a high-security key.

The "best version" cannot be determined. Security and usability are always a tradeoff. Increasing the usability reduces security and vice versa.

13
  • 1
    I thought about AES and wrote RSA, I edit it.
    – ThoriumBR
    Apr 8 at 19:10
  • 1
    E2E means nothing on the server can be trusted. If someone gets a court order, or someone steals the server, it must be impossible to have any data in clear. With database access someone could just grab the private keys the server are storing and decrypt everything.
    – ThoriumBR
    Apr 8 at 19:11
  • 1
    The point of E2E is not to say "we promise we will not look into the data" but "we cannot look into the data even if our lives depend on it", and that's not achieved if the server holds private keys.
    – ThoriumBR
    Apr 8 at 19:17
  • 1
    @ThoriumBR "nothing on the server can be trusted" To be fair, that's "Zero trust", not "End-to-end encryption". Zero trust generally implies E2EE, but E2EE without zero trust is possible. It's a much, much weaker security guarantee than with zero trust, but it's not completely pointless (for example, your server / load balancer can't inadvertently log secret data if the data is never decrypted, even though in theory there's an attack that could decrypt it). Also, true zero trust requires a way to verify the client, since otherwise you can just publish an update that exfiltrates the keys.
    – CBHacking
    Apr 9 at 2:04
  • 1
    @EricUldall Every single site you access thru TLS is encrypted but not E2EE. Your email is not E2EE, nor your bank, nor your hospital, nor your social network. E2EE is needed when the parties communicating cannot trust the server for any reason.
    – ThoriumBR
    Apr 9 at 22:23

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.