Suppose wine and coding stuff related to cryptography do not mix, but here's what I ended up doing as none of that stuff answered my question (though it does look like some good stuff to read for general security knowledge)
Anyway so here's what I ended up going with:
- When you login, your password goes through a fairly standard hash routine (using bcrypt now) to verify against DB hash. If it matches your login is successful, if not, well it fails. This part is fairly standard and basic and simply is the first step to authenticating to the system as a user.
- Now for the decryption part, the password is also hashed through a different function. In this case I needed a consistent salt that I could generate and store myself, so I went with SHA-512 + a salt that was generated when the user originally set the password. The idea here is that given a password, I will always get the same hash which I will call the password key here. Bcrypt did not work as it handles the salt internally so will always generate a random hash with same data.
This password key is the encryption key that is used to encrypt the key that encrypts the actual stored data entries. This password key is not stored as-is anywhere, and can only be generated by logging in.
- Now I don't want to type my password every single page load obviously, so this is when the session management comes in. Upon a successful login, and after generating the password key, a randomly generated hash (the fact that it's a hash does not really matter here, a hashing function is simply used so that it's database friendly data that comes out) is created, which is the session hash for that specific login session. This session hash is then hashed again. This is used as a key to encrypt the password key previously generated based off the password. This key, is then stored in the user's cookie, and not stored anywhere else.
- The session hash and encrypted data(the password key) is stored in the session entry
- Now that the cookie is set, the cookie can be verified against the DB to make sure the hash is valid to authenticate to the system, but also the cookie hash is the key to decrypt the password key, which can then decrypt the data
Now here's the fun part. When the user changes their password several things happen:
- new bcrypt hash generated using the bcrypt function
- New salt is generated, for good measure this salt is used with brcrypt even though bcrypt uses it's own salt. Figure it does not hurt. This salt is for the pasword key otherwise it would not really be needed.
- All the keys now need to be decrypted with the old password key (which will be available as changing password requires to specify old password) and then re-encrypted with new password key (which is derived from the newly entered password and salt).
- All existing login sessions are also cleared at this point. Any stored cookies on any machines are also useless even if I did not clear sessions as it would not be able to decrypt the keys anymore. Not clearing the session table would allow an old cookie to still be able to login, but then it would not decrypt the data.
Think I about covered it. Might be forgetting some details.
Hope all this makes sense I had like 2 glasses of wine. lol.
Basically TLDR: The keys used to encrypt the password data is encrypted by a key that can only be obtained by knowing the login password, or having a cookie that was previously set by knowing the login password. This way it does not need to actually be stored anywhere.
One weakness is that the database being compromised and a cookie being compromised could basically be used to decrypt the data. But someone that has access to both is probably already deep enough in my network that I have more serious things to worry about, and could easily just login by controlling my browser anyway. To slightly mitigate that, login sessions are going to be kept short. Once a session expired the cookie associated with that session is useless.