在函数 gcry_cipher_encrypt C++ 上使用 gcrypt 时出错

Error using gcrypt on function gcry_cipher_encrypt C++

我正在尝试使用 gcrypt 将简单的密码术制作成 txt 文件。当我执行命令 gcry_cipher_encrypt 时,我收到以下错误:

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

当我使用一个txt文件的内容时会出现这种情况,如果我将文本内容硬编码到代码中这个功能就可以工作,可能的原因是什么?

文本文件内容

test test test test test 

密码:

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);
}

嗯...我不知道 libgcrypt,但是...

this page中,在gcry_cipher_encrypt()函数的描述中,我读到

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

如果我理解得很好,您正在使用 AES 作为算法,因此,根据各种来源(wikipedia,例如),AES 的块大小为 16 字节。

如果你看一下原来的 txtBuffer,你可以看到它有 63 个字节(9 个数字,26+26 个字母,2 个空格),所以(为终端零添加 +1)txtLength 是 64,正好是 16 的倍数。

您的文本是 25 个字节,所以您的 texLength 如果是 26,则不是 16 的倍数。

En passant:您使用的是 C++,因此我强烈建议避免使用 malloc() 并改用 new [];或(更好,恕我直言)std::stringreserve()c_str()data().

我想你应该使用 txtBuffer 作为中间分配的缓冲区。

使用new []解决方案,我想你应该这样修改你的代码

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.: 注意,代码未测试。

p.s.2:抱歉我的英语不好。