What's the most secure way to derive a key from a password repeatably? 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.
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.