3

考虑以下 C++ 代码片段:

#include <iostream>
#include <openssl/aes.h>

#define AES_KEY_LENGTH 32

using namespace std;

int main()
{
    AES_KEY encryption_key;
    AES_KEY decryption_key;

    unsigned char key[AES_KEY_LENGTH] = {'t', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't'};

    unsigned char iv[AES_BLOCK_SIZE] = {'t', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't', 't', 'e', 's', 't'};

    unsigned char iv_enc[AES_BLOCK_SIZE];
    unsigned char iv_dec[AES_BLOCK_SIZE];

    memcpy(iv_enc, iv, AES_BLOCK_SIZE);
    memcpy(iv_dec, iv, AES_BLOCK_SIZE);

    AES_set_encrypt_key(key, AES_KEY_LENGTH * 8, &(encryption_key));
    AES_set_decrypt_key(key, AES_KEY_LENGTH * 8, &(decryption_key));

    char message[] = "Attack at dawn! Attack.";

    unsigned char * encryption_output = new unsigned char[32];
    encryption_output[31] = 3;

    AES_cbc_encrypt((unsigned char *) message, encryption_output, sizeof(message), &encryption_key, iv_enc, AES_ENCRYPT);

    unsigned char * decryption_output = new unsigned char[32];

    AES_cbc_encrypt(encryption_output, decryption_output, 32, &decryption_key, iv_dec, AES_DECRYPT);
}

我在这里所做的是使用 openssl aes 库加密然后解密消息。我关心的是长度加密输出。据我了解,由于 AES 以大小为 AES_BLOCK_SIZE(又名 16 字节)的块进行加密,因此输出字节数应等于消息的大小,四舍五入为最接近的 AES_BLOCK_SIZE 倍数。这个对吗?特别是,如果我将消息扩展为正好 32 个字节长,会发生什么?这仍然有效,还是会添加 16 个空填充字节,从而在尝试在加密输出中写入字节 32 到 47 时导致分段错误?

4

1 回答 1

6

正确的 PKCS#7 填充:

  • 如果之前不是倍数, 则将长度四舍五入为块大小的倍数
  • 否则它会添加一个完整的块

否则,在解密时,您不可能知道最后一个密文块是“真实的”还是只是填充。(也指定了要填充的实际字节值,但是您真正的最后一个块可能包含这些 => 再次无法识别它)。

除了 PKCS#7 之外,还有其他方案,但这在这里不相关。

但是,使用AES_cbc_encrypt,您必须自己实现,即。加密前填充,解密后删除填充。加密本身将适用于非多个长度,但使用的“填充”存在上述问题。要回答您的原始问题,AES_cbc_encrypt不会添加块,将长度四舍五入是它唯一要做的事情。

对于具有适当填充的函数(并且没有 的其他几个缺点AES_cbc_encrypt,例如缺少 AESNI 支持等),请查看 OpenSSL 的 EVP 部分。AES_cbc_encrypt是一个更底层的部分,这取决于它也被高层函数使用的情况。

顺便说一句,关于 C++ 的一些事情:如果你没有遇到分段错误,
这并不意味着代码是正确的。

于 2015-07-05T02:49:02.930 回答