1
$\begingroup$

I originally posted this in the security.stackexchange forums but then I was directed to this one which seems more befitting for my question.

I am writing a C# .NET application. For my application the following requirements should be met:

  1. The data of the users should be stored encrypted in the database
  2. Users can share data with other users
  3. I, as the developer, should be unable to decrypt any user data
  4. If the user resets their password, previously encrypted data should still be possible to decrypt
  5. The private key should not be stored anywhere on disk. Ideally, I want the client application to be able to derive the private key, for example from the password, every time the user logs in.

I cannot seem to find a solution that meets all five requirements. So far, I have come up with the following cryptographic system using asymmetric encryption: When a user registers, a public-private key pair is derived based on the user password (Is that even possible/practical?). The public key is stored in the database. When the user shares data with another user, it is encrypted with that other user's public key and stored in the database. But now req. 4 is not met, since the key pair is based on the current password a reset will render all previously encrypted data undecryptable.

If instead I use symmetric encryption to encrypt the data, then I can encrypt the encryption key using some password based key, which solves req. 4. However, then I am unable to meet req. 2 i.e. share data with other users. This is, of course, because the user would need the other user's symmetric data encryption key which is encrypted with the private key.

So I am finding myself stuck and unable to come up with a solution that fixes all issues simultaneously.

$\endgroup$
3
  • 1
    $\begingroup$ These are commercial grade product requirements. Do you really expect to be able to find free solution from online forums? $\endgroup$
    – DannyNiu
    Jun 5 at 7:56
  • $\begingroup$ One Idea I came up with is to add contacts, divide the key into several parts (see secret sharing) and distrivute them to the contacts. The user can then contact k of n of his contacts to reconstruct the key, but he needs to trust those to not collaborate or not know each other. $\endgroup$
    – Gamer2015
    Jun 5 at 9:27
  • 1
    $\begingroup$ Another one would be to store a copy of the vault key on the client, encrypt it with another key that is sent to the server and if the user forgets the password, but they still have access to a device they used to log in previously, the server can send the key to decrypt the vault key to the user. This creates the vulnerability that anyone with access to such a device can get the vault key. (Implementation details are obviously still to be discussed, but that's outside the scope of this comment section) $\endgroup$
    – Gamer2015
    Jun 5 at 9:37
0
$\begingroup$

The phrase "password reset" is not applicable for encryption.

Password reset means that starting from some moment only a new password can be used and none of the previous passwords can be used any more. For encryption this is not possible, because if some password (key) can be used for decryption, it can still be used without any limits. For instance, if reset was possible and user reset password to a new one, then a few days later found the previous password, this password would obviously still be able to decrypt the same data.

Thus, we cannot call it "reset". The requirement to be able to decrypt the data in case user forgotten the password actually means:

  1. either you may help user to restore the current password (decryption key)
  2. or, if encryption scheme allows multiple decryption keys, you give user an additional password (key)

In both cases you as a developer can obtain a password (decryption key) not only when user asked you about this, but also on your own. Thus, the requirement 3 would be violated.

Any schemes with secret sharing don't fit these requirements as well. If you implement secret sharing where user has one part of the additional decryption key, this can also be lost. If you implement secret sharing where user has none of parts of shared secret, then the secret (decryption key) can be restored without the user knowing about that, thus the requirement 3 would be violated.

Briefly: There is no way to fulfill all your requirements simultaneously. This has nothing to do with cryptography, this is just a common sense. Means, at least one of requirements need to be changed.

$\endgroup$
0
$\begingroup$

If we assume that users lose all secrets when they lose a password, requirements 3+4 imply the developer of 3 can't change a user password as in 4. Also, whatever code encrypts or decrypts data manipulates it in clear, and whatever keys are needed.

The developer of 3 must thus be unable to maliciously write or alter code responsible for user management. And if the developer of 3 can maliciously write or alter code responsible for encryption or decryption, then it must be impossible for said developer to make that code leak data (including the the decryption key, and the plaintext data in clear or encrypted under a key known by said developer).

Thus any C# code that the developer of 3 writes must match at least one of

  • It is audited and run by trusted parties independent of the developer.
  • It is not responsible for user management and data encryption, and can't alter the nature or behavior of other trusted code that does. That is hard to insure in C# if that other trusted code is part of the same process (other languages like Java give more insurances in this regard).
  • For code responsible for encryption or decryption, what it produces is somewhat made unavailable to the developer or cross-checked to make leaks impossible. The simplest (thus best, and best practice in high-security environments) is to run the developer's code in a trusted perimeter with no way information produced within can reach the developer. That's attempted with physical isolation of machines, virtual machines, VPNs, and data diodes, trying to insure no information can flow from the IT system to the developer¹.

So I am finding myself stuck and unable to come up with a solution that fixes all issues simultaneously.

Yes. Welcome to the reality of what cryptography as practiced in IT allows: at least a core part of the system must be trusted.


¹ Murder of the developers after they release the code solves 3, but is ineffective to prevent data leaks to others, and is illegal under some jurisdictions. Also, while it often is totally justified when you ask the unfortunate users, it remains unpopular with developers.

$\endgroup$
0
0
$\begingroup$

Actually, I had thought something about it for long. Using password with a salt and a KDF to derive a key which is used to encrypt a key table which stores the user's signing private key and randomly generated key for each content.The key table needs to be decrypted and re-encrypted every time user changes a password. Then the user also uses that to encrypt a private key stored somewhere that needs to be decrypted and reencrypted every time user changes a password as well. That way you can sign the cipher for each content so that no one else can modify the content even if you share the key for that content with someone else. But that way there is no way for any user to recover their content if they forget the password and the password needs to be reset in any other way. Of course, the key table is vulnerable to dictionary attack if the password is not strong enough and you have to make sure that the password is stored safely and is never lost.

I don't really think that will even be possible for user to recover the table in case he/she forgets the password because if it was possible the server storing the content would be able to decrypt it as well, violating your privacy requirement.

$\endgroup$

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.