# Is storing the hash of a key together with ciphertext encrypted with that key secure?

Is it secure to store the hash of a symmetric cipher key along with data encrypted with that key? Are there any circumstances or algorithms in which this combination could lead to potential weaknesses -- or is it always a bad idea? Assume the cipher is AES-128 or -192 and the hash is SHA-256, and also assume that the key was derived from a pass phrase.

-
How was the key derived from the passphrase? If done poorly (e.g., SHA-256(passphrase)), then storing the hash of the key alongside the encrypted contents is a comically bad idea. –  Stephen Touset Nov 20 '12 at 23:02
Also, why would you want to store the hash of the key alongside the data it protects? If it's to identify the key that was used to encrypt the data, better is to create a mapping of synthetic IDs (e.g., randomly-generated UUIDs) onto keys. This way, there's no direct link whatsoever between the identifier and the key that protects the data. –  Stephen Touset Nov 20 '12 at 23:05

I think this is generally not a good idea, for two reasons.

First, do not generate a key as a hash of a passphrase. Where possible, you should try to avoid deriving cryptographic keys from passphrases, as passphrases rarely have enough entropy to make a secure crypto key. If you must derive the crypto key from a passphrase, then be sure to use PBKDF2 (or similar key derivation function), which is specifically designed to mitigate (but not eliminate) some of these risks, by making key derivation a slow process.

Second, if the key is derived from a passphrase, I do not recommend storing a hash of the key. This may make it easier to mount exhaustive passphrase-search attacks, including facilitating construction of rainbow tables that map from the hashed-key to the original passphrase. Instead, simply use authenticated encryption.

If you use authenticated encryption, there's no need to store a hash of the key. You can tell whether a key is correct by trying to decrypt and seeing whether the decryption is authentic. If it is authentic, you're good; if it isn't authentic, you've got the wrong key.

And you probably want authentication anyway, so this kills two birds with one stone.

-
Well, if there are large numbers of possible keys, it's probably not feasible to simply use trial decryption against every key. –  Stephen Touset Nov 21 '12 at 1:19
@StephenTouset, agreed, good point! If that's the issue, then my proposal should be combined with your proposal: store a UUID that uniquely identifies the key together with the ciphertext. Let's hope that user4328 returns to clarify the nature of his/her requirements. –  D.W. Nov 21 '12 at 1:44
@D.W., I would propose that they only need a key ID, and that the key ID is not generated in any way based on information in the key. (It could be random, sequential, or even a name.) Having a UUID to identify the combination of key & ciphertext does not help identify which key to use to decrypt. Having a Key ID tells the decrypting party exactly which key to select (think index in a database). This is similar to the function of a Subject Key ID OID on an X.509 certificate. The difference is that a SKID can safely be a hash of the public key without compromising security. –  John Deters Nov 21 '12 at 15:12
@JohnDeters, yes, I agree, that's a good scheme -- I thought that's what Stephen Touset was talking about/proposing. –  D.W. Nov 21 '12 at 18:00
Indeed it was. :) –  Stephen Touset Nov 21 '12 at 18:52

It is secure.

I should stress that there is no good reason to do this and several bad ones( i.e. trying to authenticate your data or protect against some kind of attack). You should read D.W.'s answer for a bunch of reasons why you might try to this and why it doesn't actually solve your problem.

However, it is secure assuming sha256 is hard to invert. If this is the case, than the best an attacker can do is simply try keys and see if they match the hash. This is slightly faster than doing a trial decryption, but not anywhere near fast enough to make it feasible to try all of the $2^{128}$ possible random keys. If your key is not random, than your construction isn't secure, but it wouldn't be secure even if you removed the hash(because doing trial decryptions instead of a hash compare to find the key is not that much harder).

Formally, if you want a definition in terms of provable security, its secure under the random oracle model (where we replace sha256 with a call to a truly random "function")

-