I'm designing a small personal journal web application for my wife. I'm a crypto newb, but I want her to feel secure knowing only she will have access to her journal entries. I am thinking of the following scheme to achieve this using the Web Crypto API:
- User registers. A
masterKey
is generated and wrapped (using AES-KW) using a PBKDF2 derived key (masterKeyWrapKey
) from the user'spassword
and a random salt,masterKeyWrapSalt
. We now havewrappedMasterKey
.wrappedMasterKey
along withmasterKeyWrapSalt
is sent the server for storage. When changing passwords, we simply perform the previous steps with the new password, re-usingmasterKey
instead of generating a new one. - User logs in. Their password is hashed (yet to determine which hash to use) on the client side and sent to the server, so that the server doesn't get to use it to derive the
masterKeyWrapKey
. The hash used here must be different than the one used to generatemasterKeyWrapKey
, otherwise we'll just be sending the key to unwrapwrappedMasterKey
to the server on each log in. - Upon successful logging in, the server sends the user's
wrappedMasterKey
andmasterKeyWrapSalt
. We use PBKDF2 againstpassword
andmasterKeyWrapSalt
to deriveunwrapKey
and use that to unwrapwrappedMasterKey
, getting back ourmasterKey
. - The user can now encrypt and decrypt their journal entries using their
masterKey
. I am planning on using AES-256-GCM with a 96 bit random IV produced fromCrypto.getRandomValues()
. Given the amount of posts there's likely to be, I don't think I need to worry about an IV collision.
It sounds pretty safe to me I'd love to hear what people in the know think. I've read that one should never implement their own encryption ANYTHING, but the temptation is strong.. especially on such a small project.
Edit to add information:
PBKDF2 was chosen as it is the only password based key derivation function available in the Web Crypto API
- I want to avoid dependence on any external crypto libraries.
masterKey
should not change and so it needs to be stored (securely) somewhere. Wrapping it with the key derived from the user's password derived key on the client side and storing the wrapped version on the server seemed sensible. If I were to forgo having amasterKey
and only use the key derived from the user's password, then yes, I would only need to keep the salt on the server. I could include a minimum password strength requirement using one of various libraries. $\endgroup$