AES_cbc_encrypt 是否添加填充?

2022-01-07 00:00:00 openssl aes c++ cbc-mode

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

Consider the following snippet of C++ code:

#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 库加密然后解密消息.我关心的是长度encryption_output.就我的理解而言,由于 AES 以大小为 AES_BLOCK_SIZE(又名 16 字节)的块进行加密,因此输出字节数应等于消息的大小,四舍五入到最接近的 AES_BLOCK_SIZE 倍数.这个对吗?特别是,如果我将消息扩展为恰好 32 个字节长,会发生什么情况?这仍然有效,还是会添加 16 个空填充字节,从而在尝试在加密输出中写入字节 32 到 47 时导致分段错误?

What I do here is encrypt and then decrypt a message using openssl aes library. What I am concerned about is the length encryption_output. As far as my understanding goes, since AES encrypts in blocks of size AES_BLOCK_SIZE (aka 16 bytes) the number of output bytes should be equal to the size of the message, rounded up to the closest multiple of AES_BLOCK_SIZE. Is this correct? In particular, what happens if I extend the message to be exactly 32 bytes long? Will this still work, or will 16 empty padding bytes be added thus causing a segmentation fault when trying to write bytes 32 to 47 in encryption_output?

推荐答案

正确的 PKCS#7 填充:

Proper PKCS#7 padding:

  • 将长度四舍五入为块大小的倍数 如果它不是之前的倍数
  • 它添加一个完整的块否则
  • rounds the length up to a multiple of the blocksize if it wasn′t a multiple before
  • and it adds a whole block otherwise

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

Else, when decrypting, you couldn′t possibly know if the last ciperhtext block is "real" or only padding. (The actual byte values to pad with are specified too, but your real last block could contain these => again not possible to recognize it).

除了 PKCS#7 之外还有其他方案,但这与此处无关.

There are other schemes than PKCS#7, but this is not relevant here.

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

However, with AES_cbc_encrypt, you′ll have to implement this yourself, ie. pad before encrypting and remove the padding after decrypting. The encrypting itself will work with non-multiple lengths, but the used "padding" has the problem mentioned above. To answer your original question, AES_cbc_encrypt won′t add blocks, rounding up the length is the only thing it does.

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

For functions with proper padding (and without several other disadvantages of AES_cbc_encrypt, like missing AESNI support etc.etc.), look into the EVP part of OpenSSL. AES_cbc_encrypt is a more lowlevel part, depending on the situation it′s used by the highlevel function too.

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

Btw., something about C++: If you don′t get a segmentation fault,
it doesn′t mean that the code is correct.

相关文章