using EVP_aes_128_gcm in openssl for aad with size of not multiple of 16

2.1k views Asked by At

I am trying to use openssl EVP (EVP_aes_128_gcm) as interface for GMAC. I am testing the code against the NIST's CAVP GCM test vector (http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip). The problem is: when the aad size is multiple of 16, the code can give correct GMAC tag. But if the size is not multiple of 16, the result is wrong. What could be the problem?

The code is:

#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/engine.h>

#include <assert.h>
#include <stdio.h>

void dump(const void *p, size_t len)
{
    const unsigned char *a = p;
    size_t i;
    for (i = 0; i < len; i++) {
        printf("%02x", a[i]);
    }
    puts("");
}

void main(void){

    /*
    // key = 16; aad = 20; WRONG tag computed
    u_char key[] = {0x2f,0xb4,0x5e,0x5b,0x8f,0x99,0x3a,0x2b,0xfe,0xbc,0x4b,0x15,0xb5,0x33,0xe0,0xb4};
    u_char iv[] =  {0x5b,0x05,0x75,0x5f,0x98,0x4d,0x2b,0x90,0xf9,0x4b,0x80,0x27};
    u_char aad[] = {0xe8,0x54,0x91,0xb2,0x20,0x2c,0xaf,0x1d,0x7d,0xce,0x03,0xb9,0x7e,0x09,0x33,0x1c,
                    0x32,0x47,0x39,0x41};
    u_char tag[16] = {};
    u_char exp[] =   {0xc7,0x5b,0x78,0x32,0xb2,0xa2,0xd9,0xbd,0x82,0x74,0x12,0xb6,0xef,0x57,0x69,0xdb}; // expected result
    */

    // key = 16; aad = 48; CORRECTED tag computed
    u_char key[] = {0x99,0xe3,0xe8,0x79,0x3e,0x68,0x6e,0x57,0x1d,0x82,0x85,0xc5,0x64,0xf7,0x5e,0x2b};
    u_char iv[] =  {0xc2,0xdd,0x0a,0xb8,0x68,0xda,0x6a,0xa8,0xad,0x9c,0x0d,0x23};
    u_char aad[] = {0xb6,0x68,0xe4,0x2d,0x4e,0x44,0x4c,0xa8,0xb2,0x3c,0xfd,0xd9,0x5a,0x9f,0xed,0xd5,
                    0x17,0x8a,0xa5,0x21,0x14,0x48,0x90,0xb0,0x93,0x73,0x3c,0xf5,0xcf,0x22,0x52,0x6c,
                    0x59,0x17,0xee,0x47,0x65,0x41,0x80,0x9a,0xc6,0x86,0x7a,0x8c,0x39,0x93,0x09,0xfc};

    u_char tag[16] = {};
    u_char exp[] =   {0x3f,0x4f,0xba,0x10,0x0e,0xaf,0x1f,0x34,0xb0,0xba,0xad,0xaa,0xe9,0x99,0x5d,0x85}; // expected result


    int rc = 0, unused;
    unsigned int i;
    EVP_CIPHER_CTX *ctx = NULL;

    ctx = EVP_CIPHER_CTX_new();
    assert(ctx != NULL);

    rc = EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
    assert(rc == 1);

    rc = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(iv), NULL);
    assert(rc == 1);

    rc = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
    assert(rc == 1);

    rc = EVP_EncryptUpdate(ctx, NULL, &unused, aad, sizeof(aad));
    assert(rc == 1);

    rc = EVP_EncryptFinal_ex(ctx, NULL, &unused);
    assert(rc == 1);

    rc = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, sizeof(tag), tag);
    assert(rc == 1);

    EVP_CIPHER_CTX_free(ctx);

    printf("should be: ");
    dump(exp, sizeof(exp));
    printf("result is: ");
    dump(tag, sizeof(tag));

}

For the test vector (comment section in the code):

[Keylen = 128]
[IVlen = 96]
[PTlen = 0]
[AADlen = 160]
[Taglen = 128]

Count = 0
Key = 2fb45e5b8f993a2bfebc4b15b533e0b4
IV = 5b05755f984d2b90f94b8027
PT = 
AAD = e85491b2202caf1d7dce03b97e09331c32473941
CT = 
Tag = c75b7832b2a2d9bd827412b6ef5769db

The output is wrong...

should be: c75b7832b2a2d9bd827412b6ef5769db
result is: e5fb99cb5b9658aa5d2caa3308e0ce6c

For the test vector:

[Keylen = 128]
[IVlen = 96]
[PTlen = 0]
[AADlen = 384]
[Taglen = 128]

Count = 0
Key = 99e3e8793e686e571d8285c564f75e2b
IV = c2dd0ab868da6aa8ad9c0d23
PT = 
AAD = b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc
CT = 
Tag = 3f4fba100eaf1f34b0baadaae9995d85

The output is correct:

should be: 3f4fba100eaf1f34b0baadaae9995d85
result is: 3f4fba100eaf1f34b0baadaae9995d85

The version I am using is: OpenSSL 1.0.1 14 Mar 2012

1

There are 1 answers

1
Tom On

I downloaded the latest openssl (OpenSSL 1.0.1j 15 Oct 2014). It gives the corrected result. The stock openssl (OpenSSL 1.0.1 14 Mar 2012) in Ubuntu 12.04LTS may have some bug on this particular GMAC application.

Thank you so much @owlstead! for confirming that the code is correct.

BTW. Actually I may have another question, how do we know which openssl version is good to use?