OpenSSL EVP_AES_128_CBC 动态获取Key/IV导致解密结果与静态输入不一致
动态获取AES-CBC加密Key/IV的正确实现
现有代码的核心错误
- 内存操作顺序完全颠倒:使用
gets拿到Key和IV的输入后,立刻执行了free(keyVal); free(ivVal);,这两块内存被释放后成为悬垂内存,后续加密流程访问到的全是随机垃圾值,根本不是用户输入的内容。 - 冗余逻辑完全混乱:后续写的逐字符读
getchar的循环,和前面的gets输入逻辑完全重复,还存在同时把同一个字符同时写入keyVal和ivVal、长度计数重叠的问题,根本读不到用户分开输入的IV值。 - 滥用不安全函数:
gets不做输入长度校验,只要用户输入长度超过预分配的100字节缓冲区,就会直接造成内存越界,属于已经被C标准废弃的危险函数。 - 长度匹配完全错误:当前使用的
EVP_aes_128_cbc算法,要求Key严格为16字节、IV严格为16字节。用户从终端输入的字符串自带\0终止符,实际长度往往和硬编码的16字节值不一致,直接把字符串指针传给EVP接口时,会把字符串末尾的垃圾内存也纳入Key/IV计算,哪怕看起来输入内容和硬编码值一样,最终加解密结果也必然不一致。
正确实现步骤
- 调整内存生命周期:加密、解密全流程执行完成后,再释放对应的Key/IV内存,绝对不能在流程未走完时提前free。
- 替换输入读取逻辑:使用
fgets代替gets,严格限制单次读入的长度,避免内存越界。 - 严格匹配算法要求的固定长度:
- AES-128-CBC的Key固定需要16字节,IV固定需要16字节
- 预初始化Key和IV缓冲区为全0,将用户输入的内容拷贝到缓冲区头部,不足16字节的部分自动补0,超出16字节的部分自动截断
- 明确区分Key和IV的输入读取流程,不要将两者混在同一个循环逻辑里
- 清理冗余的错误循环代码:删除那段逐字符读
getchar的无意义逻辑,避免输入流残留造成的读取错乱。
参考实现片段
// 固定长度常量,对应AES-128-CBC要求 const int AES128_KEY_SIZE = 16; const int AES128_IV_SIZE = 16; // 预初始化全0缓冲区,不足长度的部分自动补0 unsigned char key[AES128_KEY_SIZE] = {0}; unsigned char iv[AES128_IV_SIZE] = {0}; char input_cache[128] = {0}; printf("\n Enter your key value : "); // 安全读入用户输入,最大读入127字节,避免越界 fgets(input_cache, sizeof(input_cache), stdin); // 替换读入的换行符为字符串终止符 input_cache[strcspn(input_cache, "\n")] = '\0'; // 最多拷贝16字节到Key缓冲区,超出长度的部分自动忽略 memcpy(key, input_cache, strnlen(input_cache, AES128_KEY_SIZE)); // 清理输入缓存,准备读IV memset(input_cache, 0, sizeof(input_cache)); printf("\n Enter your iv value : "); fgets(input_cache, sizeof(input_cache), stdin); input_cache[strcspn(input_cache, "\n")] = '\0'; memcpy(iv, input_cache, strnlen(input_cache, AES128_IV_SIZE));
生产环境注意:直接将用户输入的短字符串作为Key是非常不安全的实践,正式场景下应使用标准密钥派生函数(如PBKDF2)从用户口令中生成熵值足够、长度符合要求的Key,避免直接明文使用用户输入值。
内容的提问来源于stack exchange,提问作者Adeolu Temitope Olofintuyi
相关产品推荐
相关产品推荐

