I’m making a little media server, just for fun, but I want to know if what I’m thinking makes sense.
The idea is that the files will be stored on the server, encrypted. The file encryption key (henceforth FEK) will also be stored on the server, but it too will be encrypted using a 2nd key, derived from the user’s password (henceforth PDK).
It will work like this:
- There will be a 2-stage login. First, the user enters their username.
- If the user exists, the server will send back two fixed, per-user salts and a # of iterations.
- The client will use the first salt to hash their password with 1 iteration of sha256. They will send this to the server.
- The server takes this hashed password and rehashes with a 3rd salt and many iterations (PBKDF2) and uses this to authenticate the user.
- Meanwhile, the client uses the 2nd salt and # of iterations that the server previously sent, also with PBKDF2, to create the PDK.
- If the user is successfully authenticated, the server sends back the encrypted key (FEK).
- The client uses the PDK to decrypt the FEK.
- The decrypted FEK is used to encrypt and decrypt all files client-side.
Rationale: The password will be sent over HTTPS, but supposing my server is completely compromised (attacker has SSH access), then they could just wait for someone to login and get the plain-text password. One iteration of sha256 doesn’t provide a lot of protection, but this is a sort of worst-case scenario, and I don’t want to double the amount of time we’re waiting for PBKDF2 (once on client, again on server).
It still has to be rehashed on the server in case the attacker manages to download the database, but maybe doesn’t have full/persistent access. This would prevent them from cracking passwords too quickly.
I sent the 2nd salt and # of iterations to the client before they authenticate so that we can do (4) and (5) in parallel. Salt and # iterations don’t really need to be secret, do they?
Since the server never sees the plain-text password, it can never decrypt the FEK, which is the most important.
We use different salts to basically get 2 different keys out of 1 password. One is the hashed password for authentication, and the other is the PDK.
I also want to do file-deduplication using hashes. I realize this also exposes some information, so I plan on using the FEK for the file hashes too. Then I can only do per-user file deduplication, but that’s good enough.
If the user changes their password, I simply re-encrypt the FEK and send it back to the server for safe-keeping. No need to re-encrypt the files.
Does this all make sense? Any problems in my plan?
Oh, also I’m thinking
aes-256-cbc with per-file IVs for the encryption, HMAC-SHA256 for the file hashes, PBKDF2 w/ sha256 and half a second worth of iterations for both the password hash and the PDK.