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?
Eric Uldall
  • 113
  • 5

1 Answers1

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.

ThoriumBR
  • 50,648
  • 13
  • 127
  • 142
  • Thanks for the detailed response. I get what you're saying about this not being a fully e2e solution and have a few questions. 1. "A developer or database administrator is in position to compromise all data." My original idea is that someone ONLY with access to the database, or ONLY with access to the server, or ONLY with access to the code could not break the encryption. This also assumes no code has been tampered with, in which case there would be a paper trail. Can you elaborate on how someone with only access to the database could break encryption? – Eric Uldall Apr 08 '22 at 17:58
  • 2. To improve usability can we assume the server is a trusted actor and while not being a fully e2e solution is this at least worth implementing in order to say, protect sensitive data taken in a database breach? I have a lot of concerns that come from a server being compromised that I will not fully address with an encryption scheme and given that the nature of the data i'm encrypting is not inherently of high value I'm leaning more towards usability and compartmentalizing data so that someone maintaining the system would have to at the very least execute altered code to sufficiently spy – Eric Uldall Apr 08 '22 at 18:03
  • 3. 192 bits? I was reading we should be favoring 2048 if not 4096. Any elaboration for that? – Eric Uldall Apr 08 '22 at 18:03
  • 4. Assuming I wanted this to be a fully e2e scenario could the following change suffice. User who creates resource group generates resource-group key on client and sends one copy of private key encrypted with each participants public key to the server. Now the server does not know the resource-group key. In the event a new user joins one of the inviting user will add their encryption to the resource-group. This doesn't address the issue of transient access but would it be fully e2e? – Eric Uldall Apr 08 '22 at 18:13
  • 1
    I thought about AES and wrote RSA, I edit it. – ThoriumBR Apr 08 '22 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 08 '22 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 08 '22 at 19:17
  • Is the only problem that doing it this way and calling it e2e is incorrect. Or would you say doing any encryption that is not fully e2e is pointless? – Eric Uldall Apr 08 '22 at 20:01
  • Also, even if the client holds private keys, what prevents the client side code from being hijacked and sending that key to the server or some bad actor? – Eric Uldall Apr 08 '22 at 20:02
  • 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 09 '22 at 02:04
  • Is a zero-trust system even possible without a face to face key exchange? Would there not have to be some third party brokering transactions in most real world scenarios? Be it a web server, socket server, cloud storage bucket or at the very least an ISP through which that information must traverse. – Eric Uldall Apr 09 '22 at 05:19
  • @ThoriumBR I'd say E2E means _nothing on the server needs to be trusted_, but 100% agree otherwise – Haukinger Apr 09 '22 at 12:26
  • 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 09 '22 at 22:23