I have a large piece of data I want to encrypt, and I have a key master_key
.
Rather than encrypt the data directly with master_key
, I generate a random key item_key
, split it in two parts, and encrypt the data with the first half, and use the second half as an auth key in generating an authentication hash with HMAC.
I then encrypt item_key
with master_key
. This way, if the user were to change their master_key
, I would only need to rewrite the item_key
, and not the large piece of data.
So the end result of the overall encryption is:
- the ciphertext
- the authentication hash (or tag) of the ciphertext <- HMAC(ciphertext, auth key)
- encrypted item_key
What I overlooked however is that I am generating two ciphertexts here, one of the encrypted data, and one of the encrypted key. But, I only have one auth hash. This is a flaw as I go on to decrypt the encrypted item key using the split master_key
without checking its authenticity. I do however check the authenticity of the ciphertext, but that's not as useful.
My challenge now is to use the pieces that I already have to fix this problem. This means I don't want to introduce new keys.
To fix this flaw, I would need to generate an auth hash/tag for both the data ciphertext, and the item key ciphertext. The problem is, I don't have another secret authentication key to spare.
Possible solutions:
Do not generate an auth hash for the ciphertext, and instead generate an auth hash only for the encrypted item key, since that is what is being encrypted with the master key. The application promises to never decrypt the actual data ciphertext without first authenticating and decrypting the item key. Will I be roasted by the security community for doing this, even if it's theoretically safe? Is it "bad style"?
Derive from the master key an encryption key and an auth key using a PBKDF2 with a small iteration count (less than 3000). I would use this auth key to generate an auth hash for every encrypted item key. (The item key would then be used the same way explained in the beginning: split in half, one half used as encryption key, the other as auth key for the data).
I prefer to go with option 1. Does this sound reasonable? Or are there any other solutions I may be overlooking?
Note: AES-GCM would seem to solve this problem easily, as I do not need auth keys, but I cannot use this method since the platforms I intend to support do not provide native support for this algorithm.