In an implementation of AEAD_AES_128_GCM, if the AAD is defined as a "zero-length octet sequence", is it necessary to call the encryption code that adds an AAD at all? In particular, does an OpenSSL/LibreSSL libcrypto client need the EVP_En/DecryptUpdate invocation that adds the AAD, if its length is 0?

I'm working on an implementation of RFC 8188, a protocol for encrypting HTTP messages with AEAD_AES_128_GCM, which has this to say:

   The additional data passed to each invocation of AEAD_AES_128_GCM is
a zero-length octet sequence.


Currently my test code (just in a mockup stage) has this:

static const unsigned char *aad = (const void *)&aad;
static const int aad_len = 0;

#if 0
/* XXX not sure if this is necessary, examples work with & without */
return -1;
}
#endif


The resulting code produces the expected decryptions and intermediate values for the examples in chapter 3 of the RFC. As you can see, this part is #if 0-d out, so in fact nothing is done to add an AAD.

Since this may seem like a remarkably silly question (already I'm pre-emptively embarrassed), let me explain why I'm asking:

• The RFC has all of two examples, both of which decrypt ciphertext to "I am the walrus" (with two different record sizes). So the "it works" result may be a lucky accident of sparse test data.

• Since the RFC goes to the trouble of saying "zero-length octet sequence", rather than something like "there is no AAD", it feels like there might be a reason for putting it that way.

• An assumption on my part, a crypto layman, that "it's zero-length so I don't have to do anything" feels like the sort of thing that leads to errors and insecurity in code that uses cryptography. Operations on zero-length structures don't always mean the same thing as "do nothing" (consider SHA hashes of the empty string).

So I thought I'd ask others if there might be more going on here than meets the eye.

AES-GCM does not support ‘no AAD’ as distinct from ‘zero-length AAD’. See NIST SP800-38D for details of how it works internally: the AAD is padded with zeros so it is a multiple of 128 bits long, and the length is hashed in at the end. If the AAD is zero-length, then zero bits of padding are added and no time is spent hashing any AAD or AAD padding.

1. Let $$u = 128\cdot\lceil\operatorname{len}(C)/128\rceil - \operatorname{len}(C)$$ and let $$v = 128\cdot\lceil\operatorname{len}(A)/128\rceil - \operatorname{len}(A)$$.
2. Define a block, $$S$$, as follows: $$S = \operatorname{GHASH}_H(A \mathbin\| \mathtt 0^v \mathbin\| C \mathbin\| \mathtt 0^u \mathbin\| [\operatorname{len}(A)]_{64} \mathbin\| [\operatorname{len}(C)]_{64}).$$

In Steps 4 and 5, the AAD and the ciphertext are each appended with the minimum number of ‘$$\mathtt 0$$’ bits, possibly none, so that the bit lengths of the resulting strings are multiples of the block size.

—NIST SP800-90A, §7.1 ‘Algorithm for the Authenticated Encryption Function’, p. 15 (emphasis added)

Note that if the AAD $$A$$ is empty, then $$\operatorname{len}(A) = \lceil0/128\rceil = 0$$, so $$\lceil\operatorname{len}(A)/128\rceil = 0$$, and thus the number of ‘$$\mathtt 0$$’ bits appended is $$v = 128\cdot\lceil\operatorname{len}(A)/128\rceil - \operatorname{len}(A) = 128\cdot0 - 0 = 0.$$ In other words, if $$A$$ is empty, then the prefix $$A \mathbin\| \mathtt 0^v$$ is also empty.

But it is a good intuition to wonder whether ‘no AAD’ and ‘zero-length AAD’ are distinct! There are many applications that do make such distinctions, often to the advantage of adversaries or at least to the frustration of legitimate users.

• Hmm, OK to be honest I wouldn't have read the NIST document that way (I would have thought it's saying that it really does fill out all of the 0 bits, append length 0 as well as the same construct with the ciphertext, and GHASH the result). But like I said, I'm not the type who routinely reads NIST specs.I'm coming around to removing the #if 0, if nothing else to make it explicit in the code what's happening and that it's by choice. – slimhazard Sep 2 '19 at 17:41
• Thanks for the clarification. I had thought "possibly none" refers to the case when AAD/ciphertext fit right into the block size, so no padding is necessary. (But that's not what my question about anyway.) – slimhazard Sep 3 '19 at 15:46