5
$\begingroup$

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 */
    if (EVP_DecryptUpdate(&ctx, NULL, &len, aad, aad_len) != 1) {
        ERR("decryption: adding aad");
        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.

$\endgroup$
3
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – slimhazard Sep 2 at 17:41
  • $\begingroup$ 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.) $\endgroup$ – slimhazard Sep 3 at 15:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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