1

我在正确解密字符串时遇到了一些麻烦。令人愤怒的是,它只是前几个字节搞砸了,其余字符都是正确的。

因此,当我只是使用硬编码的 IV 进行加密和解密时,我的测试程序运行良好。该程序接受一个字符串,对其进行加密(使用 AES),然后我得到加密二进制文件的十六进制表示。当我试图将 IV 附加到密文的末尾时,问题就出现了。奇怪的是,十六进制字符串的长度在附加 IV 后并没有增加。但是,解密功能似乎是从密文末尾获取IV,否则它无法解密任何内容,对吧?

我尝试了很多不同的东西,比如创建一个精确大小的缓冲区,并使用memcpy. 这是代码:

AES 加密

int encryptAes(const char *plainText, char *cipherText, const char *key) {
    unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };

    int plainTextLength = strlen(plainText);
    int cipherTextLength = 0;
    int blockLength = 0;
    static const int MAX_PADDING_LENGTH = 16;

    EVP_CIPHER_CTX encryptCtx;
    EVP_CIPHER_CTX_init(&encryptCtx);

    EVP_EncryptInit_ex(&encryptCtx, EVP_aes_256_cbc(), NULL, key, iv);

    if (!EVP_EncryptUpdate(&encryptCtx, cipherText, &blockLength, (unsigned char *) plainText, plainTextLength) ) {
        printf("Error in EVP_EncryptUpdate \n");
        return 1;
    }
    cipherTextLength += blockLength;

    if (!EVP_EncryptFinal_ex(&encryptCtx, cipherText + cipherTextLength, &blockLength)) {
        printf("Error in EVP_EncryptFinal_ex \n");
        return 1;
    }
    cipherTextLength += blockLength;

    // Append the IV
    memcpy(cipherText + cipherTextLength, iv, 16);

    EVP_CIPHER_CTX_cleanup(&encryptCtx);
    return cipherTextLength;
}

AES 解密

int decryptAes(const char *cipherText, char *decipheredPlainText, const size_t cipherTextLength, const char *key) {
//    unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
    unsigned char iv[16];
    memcpy(iv, cipherText + cipherTextLength, 16);

    int plainTextLength = 0;
    int blockLength = 0;

    EVP_CIPHER_CTX decryptCtx;
    EVP_CIPHER_CTX_init(&decryptCtx);

    EVP_DecryptInit_ex(&decryptCtx, EVP_aes_256_cbc(), NULL, key, iv);

    if (!EVP_DecryptUpdate(&decryptCtx, decipheredPlainText, &blockLength, cipherText, cipherTextLength)) {
        printf("Error in EVP_DecryptUpdate\n");
        return 1;
    }

    plainTextLength += blockLength;

    if (!EVP_DecryptFinal_ex(&decryptCtx, decipheredPlainText + plainTextLength, &blockLength)) {
        printf("Error in EVP_DecryptFinal_ex\n");
        return 1;
    }

    plainTextLength += blockLength;
    decipheredPlainText[plainTextLength] = '\0';

    EVP_CIPHER_CTX_cleanup(&decryptCtx);
    return plainTextLength;
}

这将产生输出:

Original Plain Text     [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
Hexadecimal is          [be1c1aaa5827be124023a96a3360da922c244acd845e8914d03cfac69d312948e10f8ef7a99a64acbc6996724315f6cb0bf441ba3b08ab25cae64389f6ded77b1579e847d3e18ca89e71a3c4ec5ca4e3089b7bc2e6bc9ef8d175406bf4b53005a91e285d117e5990176d85793bd75853]
Decrypted Plain Text    [�}kaw&d��~C�Rmfpher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]

如果我memcpy(cipherText + cipherTextLength, iv, 16);从加密函数中删除该行,并在解密函数的开头取消注释硬编码的 IV(并注释以下两行),则输出是正确的:

Original Plain Text     [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
Hexadecimal is          [be1c1aaa5827be124023a96a3360da922c244acd845e8914d03cfac69d312948e10f8ef7a99a64acbc6996724315f6cb0bf441ba3b08ab25cae64389f6ded77b1579e847d3e18ca89e71a3c4ec5ca4e3089b7bc2e6bc9ef8d175406bf4b53005a91e285d117e5990176d85793bd75853]
Decrypted Plain Text    [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]

笔记!, 十六进制在两种情况下都是相同的。

谁能看到我在这里出错的地方。我以前遇到过类似的事情,但似乎不记得我是如何解决的。显然,在尝试附加 IV 时有一些事情正在进行中。有足够的空间cipherText来容纳 IV 的添加。

提前致谢。

4

2 回答 2

2

使用相同的密钥但不正确的 IV 解密文本实际上会破坏明文输出的第一个块并正确解密其余部分。所以我会说你的 IV 是不正确的,即使在前几个字节之后明文是正​​确的。

于 2013-09-12T13:34:32.977 回答
1

应该代表的返回值是encryptAes()什么?在我看来,它应该代表加密过程产生的数据的字节长度。您是否考虑到您需要处理的数据比这长 16 个字节的事实?如果您在一个地方加密您的数据,然后将其复制到另一个地方进行调用decryptAes(),您可能会忘记考虑额外的 16 个字节。

如果是这种情况,那么您实际上正在做的是:

  1. 调用encryptAes(),将要加密的文本、输出缓冲区和加密密钥传递给它。
  2. encryptAes()中,您生成 IV,执行加密,将加密数据写入输出缓冲区,计算长度。
  3. 接下来,将 IV 复制到加密数据的末尾,而不将其添加到cipherTextLengthcounter
  4. Return from encryptAes(),返回cipherTextLength给调用者。请注意,这是一个比您的实际数据短 16 个字节的值。
  5. 使用此返回值作为您的数据长度,将您的数据复制到您将要从中解密的位置。
  6. 调用decryptAes(),将要解密的文本、输出缓冲区、加密数据的大小和密钥传递给它。
  7. decryptAes()中,将紧跟加密数据的 16 个随机字节数据复制到 IV 中。
  8. 使用此随机数据作为您的 IV 来运行解密。

这是我能想到的最可能的解释,为什么您的 IV 会损坏。

于 2013-09-12T22:01:39.883 回答