Search code examples
c++crypto++libgcrypt

Steps to decrypt encrypted data in Crypto++ in libgcrypt


I need to decrypt the encrypted data by Crypto++ in libgcrypt due to C language restriction on target platform. So I've decided to use libgcrypt since it supporting the AES128 and GCM mode.

In Crypto++, the data is encrypted this way:

std::string encrypt_data(const std::string &data,
                         const std::vector<unsigned char> &iv,
                         const std::vector<unsigned char> &key)
{
    CryptoPP::GCM<CryptoPP::AES>::Encryption encryptor;
    encryptor.SetKeyWithIV(&key[0], key.size(), &iv[0]);

    std::string ciphertext;
    CryptoPP::StringSource ss( data, true,
                            new CryptoPP::AuthenticatedEncryptionFilter(
                                encryptor,
                                new CryptoPP::StringSink(ciphertext)
                                )
                            );

    return ciphertext;
}

and successfully decrypted this way:

std::string decrypt_data(const std::string &data,
                         const std::vector<unsigned char> &iv,
                         const std::vector<unsigned char> &key)
{
    CryptoPP::GCM<CryptoPP::AES>::Decryption decryptor;
    decryptor.SetKeyWithIV(&key[0], key.size(), &iv[0]);

    std::string recovered;
    CryptoPP::StringSource ss( data, true,
                            new CryptoPP::AuthenticatedDecryptionFilter(
                                decryptor,
                                new CryptoPP::StringSink( recovered )
                                )
                            );

    return recovered;
}                       

But the decoded data is wrong when I try to decode ciphertext using libgcrypt by these steps:

  1. gcry_cipher_open()
  2. gcry_cipher_setkey()
  3. gcry_cipher_setiv()
  4. Seperate the cipher text and authentication tag
  5. gcry_cipher_decrypt(cipher text)
  6. gcry_cipher_checktag(authentication tag)

Is there any steps I missed to replicate the Crypto++ decoding process?

Gcrypt decryption code (Expected output Decrypted cipher = password):

#include <stdio.h>
#include <stdlib.h>
#include <gcrypt.h>

static unsigned char const aesSymKey[] = { 0x38, 0xb4, 0x8f, 0x1f, 0xcd, 0x63, 0xef, 0x32, 0xc5, 0xd1, 0x3f, 0x52, 0xbc, 0x4f, 0x5b, 0x24 };

static unsigned char const aesIV[] = { 0xE4, 0xEF, 0xC8, 0x08, 0xEB, 0xB8, 0x69, 0x95, 0xF3, 0x44, 0x6C, 0xE9, 0x15, 0xE4, 0x99, 0x7E };

static unsigned char const aesPass[] = { 0xda, 0x84, 0x3f, 0x01, 0xa0, 0x14, 0xfd, 0x85 };

static unsigned char const aesTag[] = { 0xdf, 0x5f, 0x9f, 0xe2, 0x9d, 0x7e, 0xc3, 0xdf, 0x7a, 0x1e, 0x59, 0xd8, 0xe6, 0x61, 0xf7, 0x7e };

#define GCRY_CIPHER GCRY_CIPHER_AES128
#define GCRY_MODE GCRY_CIPHER_MODE_GCM

int main(){
    gcry_error_t     gcryError;
    gcry_cipher_hd_t gcryCipherHd;

    if (!gcry_check_version(GCRYPT_VERSION))
     {
       fputs("libgcrypt version mismatch\n", stderr);
       exit(2);
     }

    gcry_control(GCRYCTL_DISABLE_SECMEM, 0);

    gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);

    if(!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
    {
        fputs("libgcrypt has not been initialized\n", stderr);
        abort();
    }

    size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER);
    size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER);

    char * outBuffer = malloc(blkLength);

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

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

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

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

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

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

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

    return 0;
}

EDIT: Just to be clear, the steps to decrypt I'm searching for is for the ciphertext output of the Crypto++ encryption function shown above; the encrypt_data(). So I won't accept any answer where it can't be applied to successfully decrypt ciphertext.


Solution

  • The Crpto++ encryption implementation executing this code to set the IV:

    encryptor.SetKeyWithIV(&key[0], key.size(), &iv[0]);

    Since the IV size is not passed, the default length is used which is 12. This is based on the recommended IV size by the specification which is 96bits.

    So in order for my libgrcrypt to decode the cipher correctly, I just need to change this line:

    gcryError = gcry_cipher_setiv(gcryCipherHd, aesIV, blkLength);

    into this:

    gcryError = gcry_cipher_setiv(gcryCipherHd, aesIV, 12);

    So I'll get the expected output:

    $ ./decrypt
    Decrypted cipher = password