5

I currently store my users passwords as PBKDF2 hashes, for the authentication part of my web application.

Each user also has their own private key and public key (also stored in their user profile in the database). The private key is encrypted with their plain text password upon registration.

Now, I've come to the part where I need to retrieve the user's private key, to decrypt other data - so the issue is; what would be the best way to allow me to access the user's private key?

I have a couple of ideas in mind:

I could (upon login) decrypt the private key, then encrypt it with DPAPI and store it in persistent memory (server side).

I could encrypt the user's password with an OTP, and then store the encrypted password in a cookie (on each request I could generate a new OTP, re-encrypt the password, and put back in the cookie) The OTP would have to be stored in server-side persistent memory (probably encrypted with DPAPI).

I could store the store the OTP and the encrypted password in persistent memory (server side).

I could store half of the password (encrypted) in a cookie and half in persistent memory (server side).

Which one of these options would be the most secure? Is there another method that I haven't thought of?

I know rolling your own is a baaad thing, but this application doesn't need to be government level super secure, but I would like it to be as secure as I can possibly make it.

binks
  • 175
  • 4
  • Personally, I think I'd probably set up a separate server (physical or virtual instance, whatever), then have a service that takes input and encrypts/decrypts it (internal only, obviously). That is, don't put the public/private keys with the rest of your data. This would probably remove the need to encrypt with a per-user key or manage login session information, although the db should still be encrypted at rest (some of them have features for this). If you perform all maintenance for a secret, don't even bother giving it to the user – Clockwork-Muse Sep 07 '14 at 11:29
  • 1
    The question title is confusing. You don't really need to recover their password do you? – Steve Clay Sep 07 '14 at 14:11
  • 1
    I would think a good answer would point you to design specs for other secure systems who do server-side encryption of user data. A big question *you* have to answer first is if users will lose all their data if they lose their password. – Steve Clay Sep 07 '14 at 14:26
  • Would you be interested in doing the encryption on the client side? if this is the case then there are other options. That keep the password and the PKI keys secure from everyone – Ubaidah Mar 16 '16 at 21:14

2 Answers2

4

It looks like you want a back door and that you're not concerned with privacy or legal consequences.

Two recent stories to provide some context

2013: Lavabit intentionally lacked access to its users' content so that it could not be accessed by a court order. When the NSA figured out that they could get it by demanding the server's SSL private key and reading all traffic (rather than that of the user in question, Edward Snowden), Lavabit decided to shut down rather than risk compromising the security of every single user.

2016: The Apple vs FBI debacle is a similar story, playing out right now, about the foolishness of back doors. I've chosen to link a summary of comedian John Oliver's explanation of the issue because it is rather well composed. That link also features Oliver's 18 minute HBO feature on this issue, which you can watch directly at Last Week Tonight with John Oliver - Encryption youtube

 

If you still want to do this

PGP supports multiple recipients, which I'd recommend over actually saving the password. This will let you encrypt data to a server key in addition to a user-specific key. Please note that it would be highly irresponsible to not advertise that you're doing this to your users. It might even be illegal.

Implementing this is as simple as specifying more than one recipient in GPG or whatever implementation you use. For example:

gpg --encrypt --recipient user@example.com \
              --recipient server@example.com message.eml

Depending on your intended use, this probably requires storing the server's private PGP key without a password, which is a problem in itself. If possible, try to use a hardware-based system like an OpenPGP card or at least require a human to unlock the key at each boot (with failovers to your code that accept that the server private key might not always be loaded).

Again, this is a back door and is not advised since it is still subject to subpoena and hackers (though an OpenGPG card or similar hardware key should prevent remote attacks).

 

It would be vastly preferable to find some other solution to your issue. Since you haven't spelled out what you're actually trying to do, this community won't be able to help in that regard.

Adam Katz
  • 10,418
  • 2
  • 22
  • 48
  • 1
    See also [A Critique of Lavabit](http://www.thoughtcrime.org/blog/lavabit-critique/), in which [one of the most respected figures in security](https://en.wikipedia.org/wiki/Moxie_Marlinspike) commends Lavabit (while still finding some flaws in its implementation). There might be some implementation tips in there. (Thanks @rook.) – Adam Katz Mar 16 '16 at 20:59
0

If the server is performing the encryption and decryption then you have created a "promise not to peek". Once your application has been compromised, though legal or technical means, then this promise is void. All of the suggested solutions in the above post fall into this category.

In order for a users secrets to remain a secret, the secrets must only exist on the client's machine. Google's End-To-End is trying to do this in the browser using a JavaScript add-on. This system works as intended, in that Google is only one "promising not to peek." Google controls all updates, so they are permitted to backdoor Chrome or End-To-End to compromise secrets on the client.

Omniwombat
  • 173
  • 13
rook
  • 47,004
  • 10
  • 94
  • 182