1

Imagine a mobile app that connects to an API server.

Disclaimer

I'm not sure if RSA is the right technique for this, please feel free to recommend alternatives.

The goal

The backend/database super users should not be able to recognize personal data (except email) that the user submits (in this case personal tracker data) while the user should be able to read that data in cleartext. In the case of a lost phone or something, the user should be able to retrieve his old RSA keypair without him even noticing, just by using his email and password. Besides all that we want to be able to verify the user by sending him an email on registration.

My idea

  1. User downloads app, app generates local RSA keys.
  2. User registers on the app, provides strong password and email address for verification and this is sent to the server over https:
    • Hashed Password (Bcrypt, salt is stored inside hash)
    • Encrypted RSA Keys (encrypted with ? using the password)
    • Plaintext email for contacting/verification purpose
  3. Server recieves data, creates new user entry in database and stores the already hashed RSA Keys also with the user entry.
  4. User uses app, sends sensitive data encrypted with RSA to the server, server stores that encrypted gibberish.
  5. User can retrieve old entries in the app by retrieving the gibberish and decrypting it with the local RSA key.
  6. User loses his Smartphone, therefore the unencrypted RSA keys
  7. User buys new phone, installs app and logs in with his credentials
  8. Server first uses hashed password to check if credentials are okay, if yes, sends the user his encrypted rsa keys for him to decrypt them with his password locally.
  9. Voila, user has now recovered his encrypted data while backend has no idea of what is inside the data.
schroeder
  • 129,372
  • 55
  • 299
  • 340
Laisender
  • 111
  • 3
  • 1
    What's your question? "What's your opinion?" is not a great question for the site. – schroeder Apr 18 '23 at 13:58
  • For the process you described the server does need to store any keys at all. User can encrypt data on the client side with a simmetric cipher, e.g. AES, and sent to the server. When needed, user retrieves encrypted data and decrypts them on the client side. – mentallurg Apr 18 '23 at 14:00
  • @schroeder My question is if this is the way to achieve this goal. Or if I completely going in the wrong direction. – Laisender Apr 18 '23 at 14:41
  • @mentallurg Thanks for the clarification, that sounds a lot simpler! Can you recommend any method to derive the key from the plain password? I am thinking bcrypt and then some KDF. Is there anything I have to make sure when choosing this key generation method? is there a standard way of doing so? – Laisender Apr 18 '23 at 15:03
  • @Laisender: You don't need 2. If you can, use Argon2. If you cannot, e.g. if you use WebCrypto, use PBKDF2. – mentallurg Apr 18 '23 at 15:10
  • OP, with regard to the first bullet point under (2) - are you saying that the password is hashed on the client side, then the client sends the hashed password to the server? Also, in (7), where it reads 'and logs in with his credentials' - are you saying that the client sends the unhashed password (through the TLS tunnel) to the server in this step? – mti2935 Apr 18 '23 at 20:06
  • @mentallurg I've thought about that a bit. What happens when the user forgets his password? Then, even tho we have password recovery option. The password hash and all data will be lost? How can we prevent that? – Laisender Apr 19 '23 at 09:13
  • @mti2935 Well in both cases the client definitely doensn't send the ingredients to make the AES Key to the Server. Thats why I wanted to send the already bcrypted password to the server. – Laisender Apr 19 '23 at 09:15
  • @Laisender: If password is lost, it is lost. The same in your original case. You suggested that server keeps the hash. But if user has lost the password, having hash does not help. To deal with the case that the password is lost, you need a separate solution. There are many approaches for this. 1) Use password manager. 2) Use hardware token like YubiKey or NitroKey. 3) Store key at multiple parties, see e.g. this. 4) Print out codes that allow to derive the password and keep these codes in a secure place. And so on. – mentallurg Apr 19 '23 at 10:05

1 Answers1

0

If I understand correctly, two cryptographic values are derived from the user password on the client side:

  1. A salted hash (e.g. bcrypt) that is used to authenticate the user with the server

  2. An encryption key that is used to encrypt the user's secrets on the client side.

My concern is with (1) above. From the discussion in the comments, it seems that when the user registers with the service, the user's password is salted and hashed (by way of bcrypt) on the client side, then this salted hash is sent to the server and stored in the user record. Then later, when the user authenticates with the server, the salted+hashed password is sent to the server, and the server compares the salted+hashed password that it receives from the client with the one that it has stored. This basically amounts to client-side hashing, where the salted+hash password simply 'becomes' the actual password. See this answer for more detail about this, and note in particular where it reads, 'This means that you will be storing the full "plain-text" password (the hash) in the database, and you will have lost all benefit of hashing in the first place'. As you probably know, storing the plaintext password (or the equivalent), is not recommended.

In addition to the above, you also need to address the question of where the salt would be stored. If you store the salt on the user's device, and the user looses his/her device, then the salt is lost. If you store the salt on the server, then you would have to work out some protocol for the client to get the salt from the server; and at this point, this begins to look a lot like SRP.

SRP addresses both of the above problems. With SRP, the client and the server mutually authenticate each other based on a password known to the client (and a derivation of the password known to the server), without the server storing the password (or password equivalent). SRP has a number of other security benefits as well. See Alternatives for sending plaintext password while login for more info.

Once you get your head around SRP, you might want to take a look at https://protonmail.com/blog/encrypted_email_authentication for an interesting read on how Protonmail uses SRP to derive two keys from the user's password - one that is used to authenticate with the server, and another that is used for client-side encryption, which seems very similar to what you are trying to do.

Last but not least, I'm not sure you need (asymmetric) RSA encryption for this. Being that the personal data is being encrypted and decrypted by the same user, symmetric encryption (e.g. AES encryption), where the same key is used for both encryption and decryption, ought to suffice.

mti2935
  • 23,468
  • 2
  • 53
  • 73