3
votes

On my server I have users that can store and encrypt files.

The users passwords are SHA512 hashed so I can't reverse/decrypt them. The user's files are encrypted with a random file_key, which is encrypted in my database, the only way to know the file_key of the files is to use the user's password to decrypt the file_key. I did this because I don't want to have to re-encrypt all the files each time a user change his password, instead it just re-encrypt the file_key with the user's new password and re-store it in the database.

Generate a secret key to encrypt a user's data; call this the "content encryption key." Derive a key from the user's password; call this the "key encryption key." Encrypt the "content encryption key" using the "key encryption key." Store the encrypted key along with the salt and the number of iterations used for key derivation.

If they change their password, decrypt the content encryption key with the old password, and re-encrypt it with a key derived from the new password. You should choose a new salt for the new password, and make sure you store it along with the new encrypted key.

I've come to think of a little (big?) problem, in fact, if the user forgets his password and asks for a password reset, I will lose all the encrypted files as it's impossible for me to access the encrypted file without the original password..

Are there any encryption strategy to handle the possibility that the user could forget his password and so, I would be able to decrypt the files?

2

2 Answers

3
votes

It should be fairly obvious that the key is derived from a password, and all knowledge of that password in the universe disappears, the key, and thus any data, are unrecoverable.

So, if you want a "forgot password" kind of function, you'll need to preserve some knowledge of the users' passwords. Obviously, doing so will diminish the security of the users' data. First of all, if you (as the individual running such a service) maintain knowledge of the users' passwords, you maintain access to all their private data. Secondly, you must be keeping those passwords somewhere, which means they can be compromised.

If, after careful analysis, you're willing to degrade the security in favor of convenience, you'll want to do so carefully.

One scenario you might consider is to use asymmetric crypto to maintain an encrypted database of users' passwords. You would generate a strong key pair, and put the public key on your web server. Whenever a user created or changed a password, you would use the public key to encrypt that password. If the user needed to recover the password, your system would require human intervention on your side. You would need to fetch the encrypted password from storage into a safe environment, and decrypt it with the the private key.

Ideally, you wouldn't keep the encrypted passwords on the web server. Instead, you would encrypt them on the web server and immediately write them to some other, hardened server configured to allow write-only access from the web server.

I suppose if you had such a setup, you could remove the need for a human to decrypt. This would further degrade security, and may or may not be acceptable. In this scenario you would keep the private key on that hardened server, along with some code that would use it to decrypt the "lost" password, and effect the password change on the web box. Of course, that's clearly not as secure as keeping the private key completely airgapped on a flash drive in a safe, or whatever.

0
votes

Encrypt the content encryption key with yet another "admin" or "restoration" key. It is best to use a public key to encrypt and a backend, well managed private key to restore the content key and the data (RSA asymmetric encryption, e.g. using OAEP padding mechanism).

Of course, the user should trust you to handle the private key well. But the user has to trust you at a certain level anyway. The user is generally unable to verify the method you are deploying to encrypt/decrypt/store the data.