10
$\begingroup$

I'm trying to write a cloud storage application where everything the user uploads is unreadable by the server, encrypted client-side before being sent.

Currently, the flow looks like this:

  • User inputs password
  • Password is salted and a 256-bit SHA-3 hash is taken
  • A new true-random key is generated
  • The password hash is used as a key to encrypt the random key and IV (AES-256-CCM)
  • The encrypted copy of the random key is sent to the server for storage
  • When the user logs in, they download and decrypt this, again with the password
  • The random key/IV pair is used to encrypt user files

How bad is it that I'm using a hash with a fixed salt as an encryption key? Is there a better way to do this? The problem is just that I need each password to generate exactly the same key each time, and I didn't see how to do that without a fixed salt, and indeed, a fixed IV in the encryption action.

Also, if it isn't clear why I'm using this key to encrypt another key, my thought is that the second key is significantly more random (minimum 4500 passes of PBKDF2), plus it provides the potential to change the password without having to re-crypt every single user file.

$\endgroup$
7
  • $\begingroup$ Welcome to Cryptography Stack Exchange. I formatted the list in your question using the markdown syntax instead of hard HTML line breaks. $\endgroup$ Commented Jul 20, 2013 at 20:24
  • $\begingroup$ Is the salt is the same for all users, or does each user has a separate one? Also, how does "true random" relate to your "45000 passes of PBKDF2"? $\endgroup$ Commented Jul 20, 2013 at 20:25
  • $\begingroup$ Ah, thanks for the formatting. It threw me off a bit to see that HTML tags were supported (and necessary) here. $\endgroup$ Commented Jul 20, 2013 at 20:37
  • $\begingroup$ The salt is the same for each user right now, but it occurs to me that I could probably change that by deriving it from their username somehow, if that would help. I guess "true random" might be a bit of an exaggeration, I'm talking about the key generated after a minimum of 4500 iterations (not 45000) of PBKDF2. $\endgroup$ Commented Jul 20, 2013 at 20:38
  • $\begingroup$ From what is your second key generated? $\endgroup$ Commented Jul 21, 2013 at 6:08

1 Answer 1

6
$\begingroup$

Is there a better way to do this?

Yes there is, using tools specifically designed for this problem - namely key derivation functions (KDF). Good ones include PBKDF2 and bcrypt. A more modern, better alternative is scrypt, but it's relatively new and could use some more analysis before deemed safe.

All above mentioned algorithms take a password and a salt, as well as tweakable security parameter(s). I recommend storing a randomly generated salt (at least 128 bits) for each user in the database and passing that into the algorithm. The key used for encryption/decryption is simply the key generated. I can't give a recommendation on the security parameters - you'll have to do your own research as to what makes you comfortable.

Also, if it isn't clear why I'm using this key to encrypt another key, my thought is that the second key is significantly more random (minimum 4500 passes of PBKDF2)

You do not have to do this with a good KDF.

Plus it provides the potential to change the password without having to re-crypt every single user file.

Do you really want this? This means that if I managed to "hack" someone once I'll be able to read his files at any point in the future. If you still want this feature I'd suggest to store a randomly generated number (on the client side) encrypted using the key generated with the KDF (your idea) in the database. Make sure to inform your users about the decoupled password/key system in laymans terms, and give them the options to re-encrypt under a newly generated key.

$\endgroup$
8
  • $\begingroup$ Hm... I think I at least partially misunderstood precisely what PBKDF2 was for while I was setting this up. $\endgroup$ Commented Jul 20, 2013 at 21:04
  • $\begingroup$ @user2589389 The name is quite descriptive - it's a password-based key derivation function. $\endgroup$
    – orlp
    Commented Jul 20, 2013 at 21:08
  • 2
    $\begingroup$ I think scrypt is sufficiently mature to be usable in production. It was published in 2009 and I'm not aware of any attacks on it. Its design is simple and solid: it uses PBKDF2-HMAC-SHA256 as a PRF to generate the initial blocks before the sequential memory-hard mixing occurs, and then uses it again after the mixing occurs. I don't think anyone should have any reservations about using scrypt, at least not anymore. $\endgroup$
    – Reid
    Commented Jul 21, 2013 at 0:22
  • 1
    $\begingroup$ Encrypting an intermediate key has several advantages. Eg it allows multiple different passwords (user accounts) to access the same file. Another advantage is it lets you permanently "delete" the files by simply deleting the key. It might take weeks to find all your redundant copies of the data to delete it, but keys are small enough you can keep them in a structure that's easy to remove. Full disk encryption often uses this to let you kill a drive in seconds instead of hours. $\endgroup$ Commented Jul 22, 2013 at 20:43
  • $\begingroup$ @Reid come back to me in 10 years, then I'll consider using scrypt, assuming nobody cracks it before then. $\endgroup$ Commented Jul 22, 2013 at 20:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.