2
$\begingroup$

I am looking at ChaCha20Poly1305 WolfSSL. It is noted that the ChaCha20Poly1305 AEAD construction has the property, that it only outputs the plaintext, if the verification of the MAC (Authentication Tag) was successful.

I am asking myself whether AES-GCM also can provide this (from a security perspective quite important) property. However, when looking at the mode diagram of GCM, it seems like the Authentication Tag is calculated successively using information from each ciphertext block. Therefore, the cipher must be decrypted in order to verify its integrity?

$\endgroup$
2
  • 1
    $\begingroup$ This is library implementers' choice. There is nothing preventing you from decryption the message even the tag is incorrect. A good library prevents, a bad library doesn't prevent. Ironically, a good library also should have methods to decrypt the message even the tag is incorrect since I want to see the issue.... $\endgroup$
    – kelalaka
    Commented Aug 14, 2020 at 7:09
  • $\begingroup$ @kelalaka thanks for your comment! However, the above argument in my question does show, that an implementation of AES-GCM could not provide this property, right? Becuase the integrity can only be checked if you decrypt the message. In case for ChaCha20Poly1305 you are more flexible, right? $\endgroup$
    – Marm
    Commented Aug 14, 2020 at 7:55

2 Answers 2

5
$\begingroup$

Therefore, the cipher must be decrypted in order to verify its integrity?

No, there is no such requirement. As you state, the authentication tag is calculated from the ciphertext blocks, however, the receiver does not have to decrypt anything to get the value of the ciphertext blocks - they gets those directly.

One of the things that appear to be confusing you is that the diagram is the processing that occurs during encryption, not decryption.

For GCM decryption, the authentication block is validated this way: You take the ciphertext (and the AAD), and repeatedly do MULTH and ADD [1] operations, then you MULTH and ADDs the AAD/ciphertext len, and then a MULTH and ADD of the processed nonce. No decryption of ciphertext need to be done.

[1]: I say "ADD" even though it is really XOR; we're working in $GF(2^{128})$, and so field addition is xor.

$\endgroup$
2
  • $\begingroup$ Thanks for you answer! So the operations ADD and MULTH are both done on the Ciphertext (and AAD)? So there is no need to decrypt the cipher first? From the diagram I was under the impression, that one need to decryption first in order to replicate the same operations as they were done during encryption in order to compare the MAC Tags. Unfortunately, I cant find any diagram for the decryption / validation. For me it is still unclear how exactly this process works. After the process you described, the result is compared with the input authentiation tag? $\endgroup$
    – Marm
    Commented Aug 14, 2020 at 13:11
  • $\begingroup$ @Marm, yes, of course. From the diagram, the decryption process starts with the ciphertext, and proceeds downwards (to generate the authentication tag which is compared to the received tag), and upwards (to generate the plaintext). Of course, you don't need to compute upwards until after you've validated the tag. $\endgroup$
    – poncho
    Commented Aug 14, 2020 at 13:53
2
$\begingroup$

Both the ChaCha20 / Poly1305 construction and AES in GCM mode operate in basically the same manner. First the AAD is MAC-ed, then the ciphertext, resulting in the authentication tag. However, since the ciphertext itself is generated first, there is no requirement to verify the authentication tag before decryption. One can just perform the stream decryption without looking at the authentication tag whatsoever.

As for the implementation, there are several choices that can be made (focusing on the encryption part):

  1. performing verification and releasing the plaintext in a single method call;
  2. updating and buffering the plaintext, and releasing it during the final call that verifies the authentication tag;
  3. allowing online encryption / decryption property, releasing the plaintext before the authentication tag is verified.

Personally I'm in favor of at least offering option 3 to developers because it can be useful to directly stream plaintext to file instead of keeping it in memory. It could also allow developers to reuse the buffer of the ciphertext for the plaintext (and vice versa during encryption).

For similar reasons I would always treat the nonce, the AD, the ciphertext and tag as separate input values for this kind of lower level functionality. Some libraries such as Java include the authentication tag with the ciphertext (mainly for backward compatibility with modes that do not produce one, it seems), which makes buffering / resizing & reusing the arrays much more cumbersome. I've tried and succeeded in a 30% code decrease (and a much larger decrease in complexity due to symmetry between the encryption / decryption methods) if fully online encryption / decryption with a separate authentication tag is implemented.

It is of course dangerous as developers could use the plaintext before validation, so I'd generally issue a warning in the documentation about this. Cryptography has many pitfalls though, and I haven't seen anyone disappear in this particular pit. On the other hand, there was quite a lot of back-and-forth in the Java community about this, e.g. when coupled with CipherInputStream and CipherOutputStream.


Option 1 could then be created as a convenience method that is also more secure. Of course, if you have option 2 or option 3 then it is relatively easy for a developer to create such a method themselves, and that's exactly what I would recommend you to do if you find that the functionality is missing.


Java is a bit special because the API basically offers incremental updates and a final method where the authentication tag is verified. The authentication tag is present in the ciphertext. That means that it cannot perform fully online decryption, as the ciphertext received during the update methods may include the authentication tag. Therefore it will return plaintext from a "window" into the buffers that lags 16 bytes (in case the maximum tag size is used) from the supplied ciphertext.

This also means that the encryption and decryption of authenticated ciphers has no symmetry: encryption can be performed online, while the decryption lags behind. As indicated, this is probably because the developers wanted AEAD ciphers as a drop-in addition to existing cipher modes.

To show that you can decrypt GCM ciphertext without verifying the tag please have a look at my Java implementation here.

$\endgroup$
4
  • $\begingroup$ I'll expand on the Java specific API later, because it is relatively weird due to allowing something near online encryption / decryption, but while including the authentication tag into the ciphertext output. $\endgroup$
    – Maarten Bodewes
    Commented Aug 14, 2020 at 12:22
  • $\begingroup$ Option 3 can also be necessary in constrained-memory environments (embedded, IoT stuff). If the plaintext doesn't fit in RAM options 1 & 2 don't work, it needs to be released to a filesystem API somehow. Since in these systems there's often no OS API for it (likely just some external QSPI flash chip) in practice the library has to release the plaintext to the user. $\endgroup$ Commented Aug 14, 2020 at 13:01
  • 2
    $\begingroup$ I would humbly disagree that option 3 is a good idea. That is, allowing the application to make decisions based on the decrypted plaintext because it has been authenticated is just asking for problems - it is straight-forward for an adversary to flip arbitrary bits (and hence change a known plaintext into any value the attacker wants) if the attacker doesn't have to worry about the tag. If memory constraints make this impractical, perhaps GCM is not the correct encryption method. $\endgroup$
    – poncho
    Commented Aug 14, 2020 at 18:08
  • 1
    $\begingroup$ @poncho For constrained devices just writing to a temporary file and only move to the correct location after verification is still a valid use case if you ask me. And reusing a buffer for the same size ciphertext / plaintext seems a good idea as well. That's what we are describing, we're not talking about making decisions based on the bits. $\endgroup$
    – Maarten Bodewes
    Commented Aug 14, 2020 at 22:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.