I'm working on a project with a scheme in which c[i] = AES-CBC-Encrypt(msg_key[i], IV, msg[i])
, and two distinct plaintexts never have identical keys. IV
is a string of nulls.
Random IVs are not an option because fully deterministic behavior is essential in this application. The only available sources of entropy (passphrase
, id
and msg[i]
below) are used in key derivation, so no derived IV would be independent of the key. The value i
is used for notational reasons only and is not available for cryptographic use, e.g. as a counter.
Keys are derived as follows:
passphrase = string chosen by user, constant for all messages
uuid = non-secret UUID, constant for all messages
msg[i] = plaintext of message i
root_key = PBKDF2(passphrase || uuid)
signing_key = HKDF(root_key, 0x01) # HKDF with extraction as in RFC 5869, IKM=root_key, salt=0x01, info="", L=chosen AES key length
text_id[i] = HMAC(signing_key, msg[i])
msg_key[i] = HKDF(root_key, text_id[i] || 0x02)
text_id[i]
is known to recipients in another scheme beyond the scope of this question. The reason for deriving variable keys with a fixed non-secret IV instead of variable IVs for a fixed secret key is twofold:
- Limit the amount of text encrypted with one key
- Require knowledge of
text_id[i]
to decrypt any block ofc[i]
in addition to the passphrase. (The motivation for this comes from the system this scheme belongs to.)
It seems to me that this scheme addresses the major concerns I have seen raised regarding fixed IVs:
In order to produce an key collision in a chosen-plaintext attack, the adversary must find two messages that produce a collision in the HMAC function.
Two plaintexts with identical prefixes will not generate ciphertexts with matching or similar prefixes with any greater likelihood than two random plaintexts would.
Someone asked a similar question and got an answer that concerns me a bit: Why should I use an Initialization Vector (IV) when I have unique keys?
On the other hand, by not using a random IV, in some setups, one gives the adversary the same plaintext block enciphered with different keys (that would be the case if the first block of each plaintext is a known constant); this reduces the number of trial encryptions for exhaustive key search by a factor (at worse) equal to the number of different keys.
If I'm understanding this right, the concern is that if an attacker possesses N ciphertexts and knows that their plaintexts all start with a common prefix P at least one block in length, then the attacker can encrypt P under various keys until they duplicate the first block of one of the ciphertexts, at which point they will have discovered the key for that ciphertext. It seems like N needs to be quite large to make this practical, particularly for a 256-bit key.
But fixed IVs make me feel bad inside, and so I wanted to ask... what dangers might I be overlooking?
msg_iv[i] = HKDF(root_key, text_id[i] || 0x03)
. A collision intext_id[i]
will still cause identical encryption between messages -- but that would require attackers to create an HMAC collision. $\endgroup$