[gnutls-devel] gnutls_cipher_decrypt2() is broken for AES-GCM

William McGovern will at thaiglish.com
Sat Jan 26 19:26:43 CET 2013


Forgot to include the output of this test case:

$ ./test_case 
ERROR: Out-of-place decrypted data mismatch
ERROR: Out-of-place authentication tag mismatch
OK: In-place decrypted data matches
OK: In-place authentication tags match

On Jan 26, 2013, at 9:40 AM, William McGovern <will at thaiglish.com> wrote:

> Hello,
> 
> It seems that gnutls_cipher_decrypt2() does not work for the AES-GCM
> ciphers and does not generate any data in the output buffer or return
> any error code. In-place decryption of the same ciphertext with
> gnutls_cipher_decrypt() works correctly.
> 
> This is seen with GnuTLS 3.1.6 on Mac OS X 10.8.2 as installed
> by homebrew on platforms with and without AES-NI support.
> 
> I believe my code is correct but let me know if I missed anything :-)
> 
> - Will
> 
> Here is a test case that illustrates the defect:
> 
> /*
> * Test case illustrating bug in gnutls_cipher_decrypt2() with AES-GCM.
> *
> * VERSION: GnuTLS 3.1.6
> * 
> * DEFECT: The gnutls_cipher_decrypt2() function does not correctly decrypt
> *         data for the GNUTLS_CIPHER_AES_[128|256]_GCM
> *         ciphers. The output buffer for the decrypted data is not modified.
> *
> *  NOTES: In-place decryption using gnutls_cipher_decrypt() on the same
> *         ciphertext generated by gnutls_cipher_encrypt2() correctly
> *         decrypts the data in-place. Also, switching the cipher to CBC
> *         mode (and commenting out the AAD and AuthTag calls) shows that
> *         gnutls_cipher_decrypt2() works for CBC. It appears that the
> *         defect is isolated to the GCM mode with or without AES-NI.
> *
> *   ENVS: Mac OS X 10.8.2 : Intel Core i7-2600 (AES-NI)
> *         Mac OS X 10.8.2 : Intel Xeon X5482   (No AES-NI)
> *
> *  BUILD: cc -Wall -o test_case test_case.c -lgnutls
> *    RUN: ./test_case
> */
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <assert.h>
> #include <gnutls/gnutls.h>
> #include <gnutls/crypto.h>
> 
> #define CIPHER GNUTLS_CIPHER_AES_128_GCM
> 
> #define KEY_LEN   32
> #define IV_LEN    12
> #define AAD_LEN   64
> #define DATA_LEN  1024
> #define TAG_LEN   16
> 
> int
> main(void)
> {
>    gnutls_cipher_hd_t h;
>    gnutls_datum_t     keyDatum, ivDatum;
>    void              *key, *iv, *aad, *pt1, *pt2, *ct, *tag1, *tag2;
>    int                rc;
> 
>    key  = malloc(KEY_LEN);
>    iv   = malloc(IV_LEN);
>    aad  = malloc(AAD_LEN);
>    pt1  = malloc(DATA_LEN);
>    pt2  = malloc(DATA_LEN);
>    ct   = malloc(DATA_LEN);
>    tag1 = malloc(TAG_LEN);
>    tag2 = malloc(TAG_LEN);
>    assert(key  != NULL);
>    assert(iv   != NULL);
>    assert(aad  != NULL);
>    assert(pt1  != NULL);
>    assert(pt2  != NULL);
>    assert(ct   != NULL);
>    assert(tag1 != NULL);
>    assert(tag2 != NULL);
> 
>    /* Construct datums for gnutls_cipher_init(). */
>    keyDatum.data = key;
>    keyDatum.size = KEY_LEN;
>    ivDatum.data  = iv;
>    ivDatum.size  = IV_LEN;
> 
>     /* Initialize input buffers (random) and zero output buffers. */
>    gnutls_global_init();
>    gnutls_rnd(GNUTLS_RND_RANDOM, key, KEY_LEN);
>    gnutls_rnd(GNUTLS_RND_RANDOM, iv,  IV_LEN);
>    gnutls_rnd(GNUTLS_RND_RANDOM, aad, AAD_LEN);
>    gnutls_rnd(GNUTLS_RND_RANDOM, pt1, DATA_LEN);
>    memset(pt2,  0, DATA_LEN);
>    memset(tag1, 0, TAG_LEN);
>    memset(tag2, 0, TAG_LEN);
> 
>    /* Encrypt data from pt1 -> ct */
>    rc = gnutls_cipher_init(&h, CIPHER, &keyDatum, &ivDatum);
>    assert(rc == 0);
>    rc = gnutls_cipher_add_auth(h, aad, AAD_LEN);
>    assert(rc == 0);
>    rc = gnutls_cipher_encrypt2(h, pt1, DATA_LEN, ct, DATA_LEN);
>    assert(rc == 0);
>    rc = gnutls_cipher_tag(h, tag1, TAG_LEN);
>    assert(rc == 0);
>    gnutls_cipher_deinit(h);
> 
>    /* Decrypt data from ct -> pt2 */
>    rc = gnutls_cipher_init(&h, CIPHER, &keyDatum, &ivDatum);
>    assert(rc == 0);
>    rc = gnutls_cipher_add_auth(h, aad, AAD_LEN);
>    assert(rc == 0);
>    rc = gnutls_cipher_decrypt2(h, ct, DATA_LEN, pt2, DATA_LEN);
>    assert(rc == 0);
>    rc = gnutls_cipher_tag(h, tag2, TAG_LEN);
>    assert(rc == 0);
>    gnutls_cipher_deinit(h);
> 
>    /* Verify decrypted data matches original plaintext (pt2 == pt1). */
>    if (memcmp(pt1, pt2, DATA_LEN) != 0) {
>        fprintf(stderr, "ERROR: Out-of-place decrypted data mismatch\n");
>    } else {
>        fprintf(stderr, "OK: Out-of-place decrypted data matches\n");
>    }
>    /* Verify authentication tags match. */
>    if (memcmp(tag1, tag2, TAG_LEN) != 0) {
>        fprintf(stderr, "ERROR: Out-of-place authentication tag mismatch\n");
>    } else {
>        fprintf(stderr, "OK: Out-of-place authentication tags match\n");
>    }
> 
>    /* Decrypt data in-place in ct. */
>    memset(tag2, 0, TAG_LEN);
>    rc = gnutls_cipher_init(&h, CIPHER, &keyDatum, &ivDatum);
>    assert(rc == 0);
>    rc = gnutls_cipher_add_auth(h, aad, AAD_LEN);
>    assert(rc == 0);
>    rc = gnutls_cipher_decrypt(h, ct, DATA_LEN);
>    assert(rc == 0);
>    rc = gnutls_cipher_tag(h, tag2, TAG_LEN);
>    assert(rc == 0);
>    gnutls_cipher_deinit(h);
> 
>    /* Verify decrypted data matches original plaintext (pt2 == pt1). */
>    if (memcmp(pt1, ct, DATA_LEN) != 0) {
>        fprintf(stderr, "ERROR: In-place decrypted data mismatch\n");
>    } else {
>        fprintf(stderr, "OK: In-place decrypted data matches\n");
>    }
> 
>    /* Verify authentication tags match. */
>    if (memcmp(tag1, tag2, TAG_LEN) != 0) {
>        fprintf(stderr, "ERROR: In-place authentication tag mismatch\n");
>    } else {
>        fprintf(stderr, "OK: In-place authentication tags match\n");
>    }
>    return 0;
> }
> 
> 
> _______________________________________________
> Gnutls-devel mailing list
> Gnutls-devel at lists.gnutls.org
> http://lists.gnupg.org/mailman/listinfo/gnutls-devel
> 




More information about the Gnutls-devel mailing list