0

It is well-known that AES-GCM requires the IV to be unique for each message that is encrypted with the same key. If the IV ever repeats, with the same key, then AES-GCM fails catastrophically. Now, what if we used a fixed IV (e.g. all zeros), but instead used a new random AES key for each message? The random (per-message) AES key could be "wrapped" (e.g. via RFC 3394) using a single master key. The "wrapped" message key would then be prefixed to the AES-GCM-encrypted message. This allows the receiver to "unwrap" the message key, by using the master key, and then decrypt the AES-GCM-encrypted message as usual, with the fixed IV and message key.

Of course, now the random message key must not repeat, I suppose. But with a random 256-Bit AES key such repeats are much less likely than with a 96-Bit IV, right? Using a proper CRNG.

Is this a feasible concept?

Note: Much unlike AES-GCM-SIV, this does not require to process the entire message twice and, therefore, it does not require to buffer the entire message in memory.

This is slightly similar to but not a duplicate of, because they don't use key wrapping:
AES CBC with unique key per message, but fixed IV

(here the key is not a pseudo-random function of the message)

  • 1
    Yeah sure, but AES key expansion is slow and high memory. This process will not perform well compared to alternatives. – Thomas M. DuBuisson Oct 25 '23 at 10:24
  • What you're describing is essentially the KEK/DEK paradigm but with a fixed nonce. It can be done and has been. However, whether this is sensible depends on the scenario and scale. If you're doing stream encryption and encrypting a message in chunks, this is a terrible idea. If you're AWS, you can't afford to rotate your key that frequently due to how much data is processed. You can also argue that you may as well randomly generate the nonce as well as rotating the key, or you could derive the key and nonce simultaneously using a KDF. – samuel-lucas6 Oct 25 '23 at 12:56
  • I see that having to initialize the AES key twice, instead of just once, is not ideal for performance. But why is it a "terrible idea" for stream encryption and encrypting a message in chunks? I think AES-GCM-SIV is bad in this scenario, because you would have to process the entire stream twice for "SIV" to work, i.e. you'd have to buffer/process the whole thing before you can send out the first chunk! With KEK/DEK, we need two AES key initializations at the start, but then we can encrypt or decrypt the chunks "on-the-fly" without the need to buffer everything. Right? – pogoya9172 Oct 25 '23 at 13:20
  • @pogoya9172 Because if you're encrypting in chunks with a fixed nonce, that means rekeying for every chunk. The chunk size is usually 16, 32, 64 KiB, which is a lot of rekeying. Then the chunks are completely independent of each other, so if you're not careful, they can be rearranged, chunks can be dropped, etc. AES-GCM-SIV is not as inefficient as people seem to think it is, and that's the price you must pay for misuse resistance. – samuel-lucas6 Oct 25 '23 at 15:20
  • I don't think I must re-key after every chunk. AES-GCM can encrypt a bit-stream of arbitrary length, with a single key+IV instance. And, unlike AES-GCM-SIV, standard AES-GCM does not need to be provided with the complete input message (which could be huge!) before any output data is produced. Instead, we can feed it with small chunks of input data. And, each time we feed in $n$ bits, we get back an equally sized chunk of encrypted data, which can already be transmitted – even if not all input data is yet generated/known. The "auth tag" is generated/sent after the last chunk. – pogoya9172 Oct 25 '23 at 15:40
  • AES-GCM has a limit on the size of the message that can be encrypted (64 GiB). Furthermore, AEAD APIs in cryptographic libraries don't work like that; you pass the entire message. Stream/chunked/session encryption also means you get many tags, not just one. You want to detect tampered chunks early rather than having to process the entire (unchunked) ciphertext. Fixing the nonce doesn't make sense in this scenario. It makes more sense for key wrapping. – samuel-lucas6 Oct 25 '23 at 17:37
  • I'm mostly familiar with Java/BouncyCastle API. And, with that API, we call init() *once* to set up the key plus IV. Then we call update() (or updateAAD()) function *in a loop, until all chunks of input data (or "associated" data) have been processed. Those are "$n$ bytes in, $n$ bytes out" functions, so we get chunks of encrypted data back, already before all input data was encrypted. Finally, we call doFinal() to handle the last* chunk of input data. In case of AEAD (e.g. AES-GCM) the doFinal() appends the "auth tag" to the last chunk of output (encrypted) data. – pogoya9172 Oct 25 '23 at 18:05
  • Yes, there are exceptions to passing in the entire message, but there are also lots of APIs that are not like what you describe. For example, libsodium, Monocypher, and the .NET System.Security.Cryptography. And that does not invalidate my other remarks. What you're describing is not the same as stream/session encryption. Anyhow, your question has been answered by two people. – samuel-lucas6 Oct 26 '23 at 15:35

0 Answers0