3

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

Tom
  • 321
  • 2
  • 9
  • Interesting, could be that the padding is calculated incorrectly if you don't supply any ciphertext. Could you show us the actual incorrect output, I haven't got an openssl compatible RT directly available. Could you also supply the version number of OpenSSL, could be a bug... Oh, and the test vector used? Sorry to bother you so much :) – Maarten Bodewes Nov 19 '14 at 18:42
  • I don't see any direct issues with your code, and Java generates the expected value... – Maarten Bodewes Nov 19 '14 at 18:51
  • Thank you so much for your quick reply! Have you tried the case with AAD length not equal to key length? – Tom Nov 19 '14 at 18:58
  • Yes, that one runs fine on Java. Din't get more response, will try to study the OpenSSL implementation myself. The test with just AAD with AAD.length % n != 0 is not tested by OpenSSL. I'll try the OpenSSL mailinglist as well. – Maarten Bodewes Nov 19 '14 at 23:37
  • Problem solved! I downloaded the latest openssl. This version "OpenSSL 1.0.1j 15 Oct 2014" gives the correct result. Thank you so much for your help! – Tom Nov 20 '14 at 16:15
  • Could you post this as an answer? I didn't find anyrhing in release notes etc so it may be valuable information to other devs. – Maarten Bodewes Nov 20 '14 at 16:28

1 Answers1

0

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?

Tom
  • 321
  • 2
  • 9
  • 1
    With security libraries, the only good answer is "the latest" version (without re-design). Sometimes you can choose a version with only the security fixes applied, that may work as well. Keep your applications up to date. And try to use runtimes (such as Java) that puts security before features and speed. I'm certainly not impressed with what I've seen from OpenSSL (NSS is probably worse though). – Maarten Bodewes Nov 20 '14 at 19:26