我想使用OpenSSL AES-256-cbc加密以100字节为块对输入数据进行加密。但是,EVP_EncryptUpdate仅加密96个字节(参数tmp = 96)。下一次对EVP_EncryptUpdate的调用将加密其余数据(除了丢失的那四个数据)。
解密很好,除了那4个丢失的字节。
如果我只调用一次EVP_EncryptUpdate,然后一次传递所有数据,一切都很好。
如果我仅将100个字节传递给EVP_EncryptUpdate,我不明白为什么这4个字节会丢失。
std::string data = "A12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123hgfedcba";
unsigned char key[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
unsigned char iv[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
int i = 0, tmp = 0, ol = 0;
int res = EVP_EncryptInit(&ctx, EVP_aes_256_ecb(), key, iv);
std::unique_ptr<unsigned char[]> ret(new unsigned char[dataLen+EVP_CIPHER_CTX_block_size(&ctx)]);
for (i = 0; i < dataLen / 100; i++)
{
EVP_EncryptUpdate(&ctx,
&ret[ol], &tmp, &data[ol], 100);
ol += tmp;
}
if (dataLen % 100)
{
EVP_EncryptUpdate(&ctx, &ret[ol], &tmp, &data[ol], dataLen % 100);
ol += tmp;
}
EVP_EncryptFinal(&ctx, &ret[ol], &tmp);
答案 0 :(得分:0)
EVP_EncryptUpdate
之后必须是EVP_EncryptFinal
。 CBC模式只能加密/解密完整的块。 lib不知道对EVP_EncryptUpdate
的最后一次调用不会再接一个,因此EVP_EncryptFinal
必须用于表示要加密的纯文本消息的结尾/解密。
EVP_EncryptUpdate
将尝试加密尽可能多的块,并将其余块留在内部缓冲区中。在EVP_EncryptFinal
期间,将与PKCS#7兼容的填充添加到缓冲区中的数据中,并对最后一个块进行加密,并返回密文的最后一部分。请注意,即使内部缓冲区为空,也会始终应用填充。
总而言之,当您调用EVP_EncryptFinal
或使用更新添加足够的数据以创建完整的纯文本块进行加密时,将填充并加密最后四个字节。如果您不调用EVP_EncryptFinal
,则不会填充密文,并且您的解密将失败或-如果密文的最后一部分可以被视为有效的填充-它将剥离末尾有一些字节,然后返回剩余的内容。同样,在使用更新程序时,您必须完成。
如果您不喜欢这种行为,则可以考虑CTR模式-至少从理论上讲是流模式,可以直接返回加密字节,而无需填充。这称为分组密码模式的“在线”属性。有时,实现仍会缓冲纯文本,直到出现完整的块为止,因此请注意。
编码说明:
100并非块大小(16字节)的倍数,因此显然只剩下4个字节。
对于CBC模式,CBC需要唯一且不可预测的密钥/ IV,而CTR需要唯一的随机数。
您最好研究这些算法,否则您将无法创建安全代码。为了传输安全,您将需要使用经过身份验证的密码。