Search code examples
c++linuxlibgcrypt

Error using gcrypt on function gcry_cipher_encrypt C++


I'm trying to use gcrypt to make a simple cryptography a txt file. When I executes the command gcry_cipher_encrypt i receive the follow errors:

gcry_strsource => User defined source 1
gcry_strerror => Invalid length

This occurs when I use the content of one txt file, if I hardcode the text content in the code this function works, what is the possible cause?

Text file content

test test test test test 

Crypt code:

void myEncrypt::aesEncrypt(char *txtInput, int txtInputSize, char *txtOutput){

    gcry_error_t     gcryError;
    gcry_cipher_hd_t gcryCipherHd;
    size_t           index;


    size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER);
    size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER);
    //char * txtBuffer = "123456789 abcdefghijklmnopqrstuvwzyz ABCDEFGHIJKLMNOPQRSTUVWZYZ 123456789 abcdefghijklmnopqrstuvwzyz ABCDEFGHIJKLMNOPQRSTUVWZYZ";
    char * txtBuffer = txtInput;
    size_t txtLength = strlen(txtBuffer)+1; // string plus termination
    char * encBuffer = (char *)malloc(txtLength);
    char * outBuffer = (char *)malloc(txtLength);
    char * aesSymKey = "one test AES key"; // 16 bytes
    char * iniVector = "a test ini value"; // 16 bytes

    gcryError = gcry_cipher_open(
        &gcryCipherHd, // gcry_cipher_hd_t *
        GCRY_CIPHER,   // int
        GCRY_C_MODE,   // int
        0);            // unsigned int
    if (gcryError)
    {
        printf("gcry_cipher_open failed:  %s/%s\n",
               gcry_strsource(gcryError),
               gcry_strerror(gcryError));
        return;
    }
    printf("gcry_cipher_open    worked\n");

    gcryError = gcry_cipher_setkey(gcryCipherHd, aesSymKey, keyLength);
    if (gcryError)
    {
        printf("gcry_cipher_setkey failed:  %s/%s\n",
               gcry_strsource(gcryError),
               gcry_strerror(gcryError));
        return;
    }
    printf("gcry_cipher_setkey  worked\n");

    gcryError = gcry_cipher_setiv(gcryCipherHd, iniVector, blkLength);
    if (gcryError)
    {
        printf("gcry_cipher_setiv failed:  %s/%s\n",
               gcry_strsource(gcryError),
               gcry_strerror(gcryError));
        return;
    }
    printf("gcry_cipher_setiv   worked\n");

    gcryError = gcry_cipher_encrypt(
        gcryCipherHd, // gcry_cipher_hd_t
        encBuffer,    // void *
        txtLength,    // size_t
        txtBuffer,    // const void *
        txtLength);   // size_t
    if (gcryError)
    {
        printf("gcry_cipher_encrypt failed:  %s/%s\n",
               gcry_strsource(gcryError),
               gcry_strerror(gcryError));
        return;
    }
    printf("gcry_cipher_encrypt worked\n");

    gcryError = gcry_cipher_setiv(gcryCipherHd, iniVector, blkLength);
    if (gcryError)
    {
        printf("gcry_cipher_setiv failed:  %s/%s\n",
               gcry_strsource(gcryError),
               gcry_strerror(gcryError));
        return;
    }
    printf("gcry_cipher_setiv   worked\n");

    gcryError = gcry_cipher_decrypt(
        gcryCipherHd, // gcry_cipher_hd_t
        outBuffer,    // void *
        txtLength,    // size_t
        encBuffer,    // const void *
        txtLength);   // size_t
    if (gcryError)
    {
        printf("gcry_cipher_decrypt failed:  %s/%s\n",
               gcry_strsource(gcryError),
               gcry_strerror(gcryError));
        return;
    }
    printf("gcry_cipher_decrypt worked\n");

    printf("keyLength = %d\n", keyLength);
    printf("blkLength = %d\n", blkLength);
    printf("txtLength = %d\n", txtLength);
    printf("aesSymKey = %s\n", aesSymKey);
    printf("iniVector = %s\n", iniVector);
    printf("txtBuffer = %s\n", txtBuffer);

    printf("encBuffer = ");
    for (index = 0; index<txtLength; index++)
        printf("%02X", (unsigned char)encBuffer[index]);
    printf("\n");

    printf("outBuffer = %s\n", outBuffer);

    // clean up after ourselves
    gcry_cipher_close(gcryCipherHd);
    free(encBuffer);
    free(outBuffer);
}

Solution

  • Well... I don't know libgcrypt, but...

    In this page, in the description of the gcry_cipher_encrypt() function, I read

    Depending on the selected algorithms and encryption mode, the length of the buffers must be a multiple of the block size.

    If I understand well, you're using AES as algorithm so, according various sources (wikipedia, by example), the block size for AES is 16 bytes.

    If you look at the original txtBuffer, you can see that was of 63 bytes (9 numbers, 26+26 letters, 2 spaces), so (adding +1 for the terminal zero) txtLength was 64, an exact multiple of 16.

    Your text is of 25 bytes, so your texLength if 26, that isn't a multiple of 16.

    En passant: you're using C++, so I strongly suggest to avoid malloc() and use new [] instead; or (better, IMHO) std::string with reserve(), c_str() and data().

    I suppose you should use txtBuffer as an intermediate allocated buffer.

    Using the new [] solution, I suppose you should modify you code in this way

    std::size_t txtLength = strlen(txtInput)+1; // from txtInput, not txtBuffer
    
    if ( 0U != (txtLength & 0xfU) )
       txtLength += 0x10U - (txtLength & 0xfU);
    
    char * txtBuffer = new char[txtLength];
    char * encBuffer = new char[txtLength];
    char * outBuffer = new char[txtLength];
    
    std::strcpy(txtBuffer, txtInput);
    

    p.s.: caution, code not tested.

    p.s.2: sorry for my bad English.