0

I have the C program below that tries to use the MbedTLS AES GCM functions to encrypt and decrypt. The encryption is running well but the decryption is abending with rc = -25344 (-0x6300) in mbedtls_cipher_check_tag(). The mbedtls_strerror returns "Last error was: -0x6300 - CIPHER - Authentication failed (for AEAD modes)" for that return code.

Although the documentation says to put it after the mbedtls_cipher_finish(), I've tried to change the function's place (as indicated in the code) without sucess.

What am I doing wrong, any idea ?? Any help is very valuable.

Thanks in advance

Here the code:

 //#
 //# AES 128 GCM - MbedTLS
 //#

 #include <mbedtls/cipher.h>
 #include <mbedtls/gcm.h>

 #include <stdio.h>
 #include <string.h>
 #include <errno.h>

 #include "etss.h"

 #define PLAIN_SIZE 1024
 #define CRYPT_SIZE 1032

 key128 k;
 iv16   iv;
 aad16  aad;
 tag16  tag;

 int Decrypta (FILE * fInput, FILE * fOutput) 
 {
    int conta = 0, rc = 0;
     int nBytesWorked = 0, nGCMfinal = 0;
     int nBytesRead = 0, nBytesWritten = 0;
     int cIn = 0, cOut = 0, cWorked = 0;

     unsigned char sPureBuff[PLAIN_SIZE] __attribute__((aligned(16))), sCiphBuff[CRYPT_SIZE] __attribute__((aligned(16))); 
     unsigned char *pPureBuff __attribute__((aligned(16)));
     unsigned char *pCiphBuff __attribute__((aligned(16)));

     unsigned char *pTag = tag.data;

     pPureBuff = sPureBuff;
     pCiphBuff = sCiphBuff;

     mbedtls_cipher_context_t ctx;

     mbedtls_cipher_init (&ctx);

     rc = mbedtls_cipher_setup (&ctx, mbedtls_cipher_info_from_values(MBEDTLS_CIPHER_ID_AES, k.size*8, MBEDTLS_MODE_GCM));

     if ( rc != 0 )
    {
        printf ("Setup - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

     rc = mbedtls_cipher_setkey (&ctx, k.data, k.size*8, MBEDTLS_DECRYPT);

     if ( rc != 0 )
    {
        printf ("Set Key - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

     rc = mbedtls_cipher_set_iv (&ctx, iv.data, iv.size);

     if ( rc != 0 )
    {
        printf ("Set IV - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

 // rc = mbedtls_cipher_check_tag (&ctx, pTag, (size_t) tag.size); 
 //
 // if ( rc != 0 ) 
 // {
 //     printf ("Decryption - Error in check_tag() (rc=%d).\n",rc);
 //     return rc;
 // }

     rc = mbedtls_cipher_reset (&ctx);

     if ( rc != 0 )
    {
        printf ("Reset - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

     rc = mbedtls_cipher_update_ad (&ctx, aad.data, aad.size);

     if ( rc != 0 )
    {
        printf ("Set AAD - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

    memset(pCiphBuff, 0, CRYPT_SIZE);
    memset(pPureBuff, 0, PLAIN_SIZE);

    if ( (rc = ReadFile (fInput, &pCiphBuff, 1, CRYPT_SIZE, &nBytesRead)) )
    {
        printf ("Decryption - Input file reading error (rc = %d). \n", rc);
        return rc;
    } 

    while ( nBytesRead > 0 )
    {
        cIn += nBytesRead;

        nBytesWorked = 0;

         rc = mbedtls_cipher_update (&ctx, sCiphBuff, nBytesRead, sPureBuff, (size_t *) &nBytesWorked);

         if ( rc != 0 ) 
        {
             printf ("Decryption - Error in DecryptUpdate() (rc = %d).\n", rc);
             return rc;
         }

        cWorked += nBytesWorked;

        // Count decryptions
        conta++;

        if ( nBytesWorked != 0 )
        {
            if ( (rc = WriteFile (fOutput, sPureBuff, 1, cWorked, &nBytesWritten)) )
            {
                printf ("Decryption - Output file writing error (rc = %d).\n", rc);
                return rc;
            }

            pPureBuff = sPureBuff;
            memset(pPureBuff, 0, PLAIN_SIZE);

            cOut += nBytesWritten;

            cWorked = 0;
        }

        if ( (rc = ReadFile (fInput, &pCiphBuff, 1, CRYPT_SIZE, &nBytesRead)) )
        {
            printf ("Decryption - Input file reading error (rc = %d). \n", rc);
            return rc;
        } 
     }

 // rc = mbedtls_cipher_check_tag (&ctx, pTag, (size_t) tag.size); 
 //
 // if ( rc != 0 ) 
 // {
 //     printf ("Decryption - Error in check_tag() (rc=%d).\n",rc);
 //     return rc;
 // }

    pPureBuff += cWorked;

     rc = mbedtls_cipher_finish (&ctx, pPureBuff, (size_t *) &nGCMfinal); 

    if ( rc != 0 ) 
    {
        printf ("Decryption - Error in DecryptFinal() (rc=%d).\n",rc);
        return rc;
    }

     // Count decryptions
     conta++;

    rc = mbedtls_cipher_check_tag (&ctx, pTag, (size_t) tag.size); 

    if ( rc != 0 ) 
    {
        printf ("Decryption - Error in check_tag() (rc=%d).\n",rc);
        return rc;
    }

    cWorked += nBytesWorked;

    if ( (rc = WriteFile (fOutput, sPureBuff, 1, cWorked, &nBytesWritten)) )
    {
        printf ("Decryption - Output file writing error (rc = %d).\n", rc);
        return rc;
    }

    cOut += nBytesWritten;

    printf("\tD %d cIn = %d cOut = %d\n\n", conta, cIn, cOut);

     mbedtls_cipher_free (&ctx);

     return 0;
 }


 int Encrypta (FILE * fInput, FILE * fOutput) 
 {
    int conta = 0, rc = 0;
     int nBytesWorked = 0, nGCMfinal = 0;
     int nBytesRead = 0, nBytesWritten = 0;
     int cIn = 0, cOut = 0, cWorked = 0;

     unsigned char sPureBuff[PLAIN_SIZE] __attribute__((aligned(16))), sCiphBuff[CRYPT_SIZE] __attribute__((aligned(16))); 
     unsigned char *pPureBuff __attribute__((aligned(16)));
     unsigned char *pCiphBuff __attribute__((aligned(16)));

     unsigned char *pTag = tag.data;

     pPureBuff = sPureBuff;
     pCiphBuff = sCiphBuff;

     mbedtls_cipher_context_t ctx;

     mbedtls_cipher_init (&ctx);

     rc = mbedtls_cipher_setup (&ctx, mbedtls_cipher_info_from_values(MBEDTLS_CIPHER_ID_AES, k.size*8, MBEDTLS_MODE_GCM));

     if ( rc != 0 )
    {
        printf ("Setup - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

     rc = mbedtls_cipher_setkey (&ctx, k.data, k.size*8, MBEDTLS_ENCRYPT);

     if ( rc != 0 )
    {
        printf ("Set Key - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

     rc = mbedtls_cipher_set_iv (&ctx, iv.data, iv.size);

     if ( rc != 0 )
    {
        printf ("Set IV - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

     rc = mbedtls_cipher_reset (&ctx);

     if ( rc != 0 )
    {
        printf ("Reset - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

     rc = mbedtls_cipher_update_ad (&ctx, aad.data, aad.size);

     if ( rc != 0 )
    {
        printf ("Set AAD - Context preparation error (rc = %d). \n", rc);
        return rc;
    } 

    memset(pPureBuff, 0, PLAIN_SIZE);
    memset(pCiphBuff, 0, CRYPT_SIZE);

    if ( (rc = ReadFile (fInput, &pPureBuff, 1, PLAIN_SIZE, &nBytesRead)) )
    {
        printf ("Encryption - Input file reading error (rc = %d). \n", rc);
        return rc;
    } 

    while ( nBytesRead > 0 )
    {
        cIn += nBytesRead;

        pCiphBuff += cWorked;

         rc = mbedtls_cipher_update (&ctx, sPureBuff, nBytesRead, sCiphBuff, (size_t *) &nBytesWorked);

         if ( rc != 0 ) 
        {
             printf ("Encryption - Error in EncryptUpdate() (rc = %d).\n", rc);
             return rc;
         }

        cWorked += nBytesWorked;

         // Count encryptions
         conta++;

        if ( nBytesWorked != 0 )
        {
            if ( (rc = WriteFile (fOutput, sCiphBuff, 1, cWorked, &nBytesWritten)) )
            {
                printf ("Encryption - Output file writing error (rc = %d).\n", rc);
                return rc;
            }

            pCiphBuff = sCiphBuff;
            memset(pCiphBuff, 0, CRYPT_SIZE);

            cOut += nBytesWritten;

            cWorked = 0;
        }

        if ( (rc = ReadFile (fInput, &pPureBuff, 1, PLAIN_SIZE, &nBytesRead)) )
        {
            printf ("Encryption - Input file reading error (rc = %d). \n", rc);
            return rc;
        } 
     }

    pCiphBuff += cWorked;

     rc = mbedtls_cipher_finish (&ctx, pCiphBuff, (size_t *) &nGCMfinal); 

    if ( rc != 0 ) 
    {
        printf ("Encryption - Error in EncryptFinal() (rc=%d).\n",rc);
        return rc;
    }

     // Count encryptions
     conta++;

    rc = mbedtls_cipher_write_tag (&ctx, pTag, (size_t) tag.size); 

    if ( rc != 0 ) 
    {
        printf ("Encryption - Error in write_tag() (rc=%d).\n",rc);
        return rc;
    }

    cWorked += nBytesWorked;

    if ( (rc = WriteFile (fOutput, sCiphBuff, 1, cWorked, &nBytesWritten)) )
    {
        printf ("Encryption - Output file writing error (rc = %d).\n", rc);
        return rc;
    }

    cOut += nBytesWritten;

    printf("\tE %d cIn = %d cOut = %d\n\n", conta, cIn, cOut);

     mbedtls_cipher_free (&ctx);

     return 0;
 }


 int main (int argc, char *argv[]) 
 {
    FILE *fPlain = NULL, *fEncrypt = NULL, *fDecrypt = NULL;

     k.size = 16;
    unsigned char inKey[16] = {0x9A, 0x59, 0x4E, 0xFA, 0x2C, 0x40, 0xBC, 0xC1, 0x2A, 0x05, 0x64, 0x43, 0xAC, 0x0C, 0xC1, 0xC2};

     iv.size = 16;
    unsigned char inIV[16] = {0x57, 0x1D, 0x32, 0xCE, 0x4F, 0x43, 0x17, 0x38, 0xE5, 0x52, 0x69, 0xE2, 0x18, 0xD1, 0x32, 0x09};

     aad.size = 16; tag.size = 16;
    unsigned char inAAD[16] = {0x9A, 0x1D, 0x4E, 0xCE, 0x2C, 0x43, 0xBC, 0x38, 0x2A, 0x52, 0x64, 0xE2, 0xAC, 0xD1, 0xC1, 0x09};

    strncpy((char *) k.data, (const char *) inKey, k.size);

    strncpy((char *) iv.data, (const char *) inIV, iv.size);

    strncpy((char *) aad.data, (const char *) inAAD, aad.size);

    int rc = 0;

     if ( (rc = OpenFile (&fPlain, argv[1], "r")) )
    {
         printf ("GCM128-M - Open input plain text file %s error (rc = %d).\n", argv[1], rc);
        return rc;
    }

     fEncrypt = fopen (argv[2], "wb+");
    rc = errno;
     if ( fEncrypt == NULL )
    {
         printf ("GCM128-M - Open output encrypt text file %s error (rc = %d).\n", argv[2], rc);
        return rc;
    }

    printf("\n>> Encrypting AES GCM 128 ...\n\n");
    Encrypta (fPlain, fEncrypt);

    CloseFile(fPlain);
    CloseFile(fEncrypt);


     fEncrypt = fopen (argv[2], "rb+");
    rc = errno;
     if ( fEncrypt == NULL )
    {
         printf ("GCM128-M - Open input encrypt text file %s error (rc = %d).\n", argv[2], rc);
        return rc;
    }

     if ( (rc = OpenFile (&fDecrypt, argv[3], "w")) )
    {
         printf ("GCM128-M - Open output decrypt text file %s error (rc = %d).\n", argv[3], rc);
        return rc;
    }

    printf("\n>> Decrypting AES GCM 128 ...\n\n");
    Decrypta (fEncrypt, fDecrypt);

    CloseFile(fEncrypt);
    CloseFile(fDecrypt);

     return 0;
 }

The etss.h (asked by Gilles) is:

 #ifndef ETSS_H_
 #define ETSS_H_

 typedef struct st_key128 { 
    unsigned char data[16];
    int size;
 } key128;

 typedef struct st_key192 { 
    unsigned char data[24];
    int size;
 } key192;

 typedef struct st_key256 { 
    unsigned char data[32];
    int size;
 } key256;

 typedef struct st_iv8 { 
    unsigned char data[8];
    int size;
 } iv8;

 typedef struct st_iv16 { 
    unsigned char data[16];
    int size;
 } iv16;

 typedef struct st_iv32 { 
    unsigned char data[32];
    int size;
 } iv32;

 typedef struct st_aad8 { 
    unsigned char data[8];
    int size;
 } aad8;

 typedef struct st_aad16 { 
    unsigned char data[16];
    int size;
 } aad16;

 typedef struct st_aad32 { 
    unsigned char data[32];
    int size;
 } aad32;

 typedef struct st_tag8 { 
    unsigned char data[8];
    int size;
 } tag8;

 typedef struct st_tag16 { 
    unsigned char data[16];
    int size;
 } tag16;

 int InitKey128(key128 * key);
 int InitKey192(key192 * key);
 int InitKey256(key256 * key);
 int InitIV8(iv8 * iv);
 int InitIV16(iv16 * iv);
 int InitIV32(iv32 * iv);
 int InitAAD8(aad8 * iv);
 int InitAAD16(aad16 * iv);
 int InitAAD32(aad32 * iv);
 int InitTAG8(tag8 * iv);
 int InitTAG16(tag16 * iv);

 int SetKey128(key128 * key, char * keyValue);
 int SetKey192(key192 * key, char * keyValue);
 int SetKey256(key256 * key, char * keyValue);
 int SetIV8(iv8 * iv, char * ivValue);
 int SetIV16(iv16 * iv, char * ivValue);
 int SetIV32(iv32 * iv, char * ivValue);
 int SetAAD8(aad8 * aad, char * aadValue);
 int SetAAD16(aad16 * aad, char * aadValue);
 int SetAAD32(aad32 * aad, char * aadValue);
 int SetTAG8(tag8 * tag, char * tagValue);
 int SetTAG16(tag16 * tag, char * tagValue);

 int OpenFile(FILE ** handler, char * name, char * mode);

 int ReadFile(FILE * handler, unsigned char ** buffer, int regsize, int blocking, int * bytesread); 

 int WriteFile(FILE * handler, unsigned char * buffer, int regsize, int blocking, int * byteswritten);

 int CloseFile(FILE * handler);

 int DisplayChs(unsigned char * buffer, int size); 

 int PrintChs(FILE * handler, unsigned char * buffer, int size, int flag); // flag = 0 => don't DisplayChs

 int DisplayNibbles(unsigned char * buffer, int size); 

 int DisplayHex(unsigned char * buffer, int size); 

 int PrintHex(FILE * handler, unsigned char * buffer, int size, int flag); // flag = 0 => don't DisplayHex

 int Generate_Key128 (key128 *k) ;

 int Generate_Key192 (key192 *k) ;

 int Generate_Key256 (key256 *k) ;

 int Generate_Nonce8 (iv8 *iv) ;

 int Generate_Nonce16 (iv16 *iv) ;

 int Generate_Nonce32 (iv32 *iv) ;

 #endif /* ETSS_H_ */

Notice that the hexcodes are not generate here, just manually set.

Thanks again.

  • Where's `etss.h` from? You're using several types (`key128`, `iv16`, etc.) and functions (`OpenFile`, `ReadFile`, etc.) that aren't defined in your code. Given that the bug is plausibly in a call to these functions, it's impossible to help you without knowing exactly what they do. – Gilles 'SO- stop being evil' Mar 10 '18 at 21:21
  • Gilles, etss.h has the support types and functions used used in programs. OpenFile, ReadFile, WriteFile, ... are routines related to work with the plain and cipher files... key128, iv16, aad16 and tag16 are typedef's to "unsigned char data[16]", that is, size of 128 bits hexcodes. The AES CBC programs use etss.h without problem. – user9047155 Mar 12 '18 at 13:31
  • But correctly answering you I gonna put etss.h along with the program code. Thanks for you time. – user9047155 Mar 12 '18 at 13:43
  • And where are those functions defined? Are they your own code or part of some library (which I don't recognize)? It's plausible that the problem is the way you're reading or writing the file — maybe the data is incomplete, or there's some extra garbage. We can't help you unless you post [complete code that people build and can run](https://stackoverflow.com/help/mcve). – Gilles 'SO- stop being evil' Mar 12 '18 at 18:46
  • Gilles, they are my own code... But I have 3DES, AESCBC and AESGCM running for OpenSSL, BoringSSL and LibreSSL, AESCBC for MbedTLS... i think that i may use those routines to run AESGCM at MbedTLS with no problem. My deal is to understand if i am using MbedTLS functions on wrong way... in a wrong order or missing another function to use. But i can send etss.c for you if it is necessary. – user9047155 Mar 14 '18 at 13:22
  • Gilles, I had the input and outbut buffers with different sizes (i brought them from an aes cbc program), so I just put the buffers at same size and the problem was solved. Thank you for your support ! JL – user9047155 Mar 17 '18 at 20:28

1 Answers1

1

On AEAD algorithms, the encrypted buffer includes the tag. This is why CRYPT_SIZE is 8 bytes longer than PLAIN_SIZE. I believe you are trying to decrypt the full cipher buffer, including the tag. In your Decrypta() function, please try the mbedtls_cipher_update() loop only for CRYPT_SIZE - tag.size bytes.
After that, get the tag from the cipher buffer, and use it for mbedtls_cipher_check_tag() function.

Ron Eldor
  • 210
  • 1
  • 11