AES_cbc_encrypt 是否添加填充?
Does AES_cbc_encrypt add padding?
考虑以下 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 库加密然后解密消息。我关心的是长度encryption_output。就我的理解而言,由于 AES 以大小 AES_BLOCK_SIZE(又名 16 字节)的块进行加密,因此输出字节数应等于消息的大小,四舍五入为最接近 [=17= 的倍数].这个对吗?特别是,如果我将消息扩展为正好 32 个字节长会怎样?这仍然有效,还是会添加 16 个空填充字节,从而在尝试写入 encryption_output 中的字节 32 到 47 时导致分段错误?
正确的 PKCS#7 填充:
- 将长度四舍五入到块大小的倍数 如果它在
之前不是倍数
- 并且添加整个块否则
否则,在解密时,您不可能知道最后一个密文块是 "real" 还是仅填充。 (填充的实际字节值也已指定,但您真正的最后一个块可能包含这些 => 再次无法识别它)。
除了PKCS#7还有其他的方案,这里不相关。
但是,对于 AES_cbc_encrypt
,您必须自己实施,即。加密前填充,解密后删除填充。加密本身将使用非倍数长度,但使用的 "padding" 存在上述问题。要回答您最初的问题,AES_cbc_encrypt
不会添加块,它只会对长度进行四舍五入。
对于具有适当填充的函数(并且没有 AES_cbc_encrypt
的其他几个缺点,例如缺少 AESNI 支持 etc.etc),查看 OpenSSL 的 EVP 部分。 AES_cbc_encrypt
是一个更底层的部分,也取决于它被高级函数使用的情况。
顺便说一句,关于 C++ 的一些事情:如果您没有遇到分段错误,
这并不意味着代码是正确的。
考虑以下 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 库加密然后解密消息。我关心的是长度encryption_output。就我的理解而言,由于 AES 以大小 AES_BLOCK_SIZE(又名 16 字节)的块进行加密,因此输出字节数应等于消息的大小,四舍五入为最接近 [=17= 的倍数].这个对吗?特别是,如果我将消息扩展为正好 32 个字节长会怎样?这仍然有效,还是会添加 16 个空填充字节,从而在尝试写入 encryption_output 中的字节 32 到 47 时导致分段错误?
正确的 PKCS#7 填充:
- 将长度四舍五入到块大小的倍数 如果它在 之前不是倍数
- 并且添加整个块否则
否则,在解密时,您不可能知道最后一个密文块是 "real" 还是仅填充。 (填充的实际字节值也已指定,但您真正的最后一个块可能包含这些 => 再次无法识别它)。
除了PKCS#7还有其他的方案,这里不相关。
但是,对于 AES_cbc_encrypt
,您必须自己实施,即。加密前填充,解密后删除填充。加密本身将使用非倍数长度,但使用的 "padding" 存在上述问题。要回答您最初的问题,AES_cbc_encrypt
不会添加块,它只会对长度进行四舍五入。
对于具有适当填充的函数(并且没有 AES_cbc_encrypt
的其他几个缺点,例如缺少 AESNI 支持 etc.etc),查看 OpenSSL 的 EVP 部分。 AES_cbc_encrypt
是一个更底层的部分,也取决于它被高级函数使用的情况。
顺便说一句,关于 C++ 的一些事情:如果您没有遇到分段错误,
这并不意味着代码是正确的。