AES CBC模式加解密结果不符问题求助
AES-CBC加解密结果不匹配的问题分析与解决
问题根源
你遇到的核心问题是数组越界写入,以及对AES加密后二进制数据的处理误区,我们一步步拆解:
1. 数组越界导致内存破坏
先看你的缓冲区定义:
unsigned char input_data[]= "Sandeep"; // sizeof(input_data) = 8(7个字符+末尾'\0') unsigned char enc_buffer[sizeof(input_data)+1]; // 大小为9(索引范围0~8) unsigned char dec_buffer[sizeof(input_data)+1]; // 同样大小为9
而你写的终止符赋值代码:
enc_buffer[sizeof(input_data)+1]='\0'; // sizeof(input_data)=8,索引为9,超出enc_buffer最大索引8 dec_buffer[sizeof(input_data)+1]='\0'; // 同样存在越界问题
这种越界写入会破坏内存中的其他数据(比如后续初始化的iv或密钥结构),直接导致解密过程出错,输出乱码。
2. 加密后密文的输出误区
AES加密后的结果是二进制数据,包含大量不可打印字符(甚至可能包含'\0'),不能直接用cout当作字符串输出:
- 保留终止符时:越界写入破坏了内存,解密流程被干扰,输出乱码
- 注释终止符后:解密过程正常执行,得到了正确的明文,但
enc_buffer没有字符串终止符,cout会一直读取内存直到遇到第一个'\0',刚好后续内存区域是input_data,所以会附带输出原数据。
修复方案
方案一:正确处理字符串明文的加解密
如果你的明文是字符串,建议只加密有效字符(去掉末尾的'\0'),同时注意AES块加密的填充要求:
unsigned char aes_key[]= "asytfuhcilejnco"; unsigned char input_data[]= "Sandeep"; const int plaintext_len = strlen(input_data); // AES-128块大小为16字节,加密缓冲区需至少为块大小 unsigned char enc_buffer[AES_BLOCK_SIZE]; // 解密缓冲区需容纳明文+终止符 unsigned char dec_buffer[plaintext_len + 1]; AES_KEY enc_key, dec_key; unsigned char iv[AES_BLOCK_SIZE]; int main() { memset(iv, 0x00, AES_BLOCK_SIZE); AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key); // 对明文进行PKCS#7填充(补全到16字节块大小) unsigned char padded_input[AES_BLOCK_SIZE] = {0}; memcpy(padded_input, input_data, plaintext_len); padded_input[plaintext_len] = AES_BLOCK_SIZE - plaintext_len; for(int i = plaintext_len + 1; i < AES_BLOCK_SIZE; i++){ padded_input[i] = AES_BLOCK_SIZE - plaintext_len; } AES_cbc_encrypt(padded_input, enc_buffer, AES_BLOCK_SIZE, &enc_key, iv, AES_ENCRYPT); memset(iv, 0x00, AES_BLOCK_SIZE); // 解密必须使用和加密完全相同的IV AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); AES_cbc_encrypt(enc_buffer, dec_buffer, AES_BLOCK_SIZE, &dec_key, iv, AES_DECRYPT); // 移除填充并添加字符串终止符 int padding_len = dec_buffer[plaintext_len]; dec_buffer[plaintext_len] = '\0'; cout<<"input_data="<<input_data<<endl; // 密文用十六进制输出,避免不可打印字符乱码 cout<<"enc_buffer (hex): "; for(int i=0; i<AES_BLOCK_SIZE; i++){ printf("%02x", enc_buffer[i]); } cout<<endl; cout<<"dec_buffer="<<dec_buffer<<endl; }
关键注意点:
- AES块大小要求:AES-128的块大小是16字节,加密数据长度必须是块大小的整数倍,因此需要对明文进行填充(比如PKCS#7填充),否则OpenSSL的
AES_cbc_encrypt只会处理完整的块,剩余字节会被忽略。 - IV的复用:解密时必须使用和加密完全相同的IV,否则解密结果会完全错误。
- 二进制数据输出:密文是二进制格式,建议用十六进制打印才能看到真实内容,不要直接当作字符串输出。
为什么注释终止符后解密正确?
注释掉越界的终止符赋值后,内存没有被破坏,解密流程正常执行,得到了包含原明文'\0'的正确结果,所以cout能正确显示原数据。而enc_buffer因为没有终止符,cout会读取到后续内存中的input_data内容,因此看起来附带了原输入。
内容的提问来源于stack exchange,提问作者hari
相关产品推荐
相关产品推荐

