OpenSSL 3中C语言禁用加密填充无效问题求助
问题排查与解决
1. 核心问题:未校验EVP_CipherFinal_ex返回值
当禁用填充时,AES-CBC要求明文长度必须是块大小的整数倍(AES-128块大小为16字节)。你的明文长度是33字节,不符合要求,所以EVP_CipherFinal_ex会返回0(加密失败),但你的代码没有判断这个返回值,直接将final_len(此时为0)加到总长度里,导致程序看似正常运行,实则加密未完成。
你觉得两种场景下密文一致,只是因为前32字节(两个完整块)的加密结果相同;禁用填充时,ciphertext数组后16字节是未初始化的垃圾数据,只是巧合和启用填充时的最后一块密文看起来一致而已。
2. 禁用填充的前提:明文长度对齐块大小
要让禁用填充生效,必须保证明文长度是16的整数倍。你可以修改明文长度为32字节,或者手动给明文补充字节凑齐块大小(注意是自定义填充,而非OpenSSL自动填充)。
修改后的代码示例
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <openssl/evp.h> #define ENCRYPT 1 #define DECRYPT 0 int main() { unsigned char key[] = "0123456789ABCDEF"; unsigned char iv[] = "1111111111111111"; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { printf("Error creating cipher context.\n"); exit(EXIT_FAILURE); } if (EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, ENCRYPT) != 1) { printf("Error initializing cipher.\n"); exit(EXIT_FAILURE); } if(EVP_CIPHER_CTX_set_padding(ctx, 0)!=1){//禁用填充 printf("Error disabling padding.\n"); exit(EXIT_FAILURE); } // 修改为32字节的明文(16*2,符合块大小要求) unsigned char plaintext[] = "This is the plaintext to encryp"; // 长度32 unsigned char ciphertext[48]; int update_len, final_len; int ciphertext_len=0; if (EVP_CipherUpdate(ctx,ciphertext,&update_len,plaintext,strlen(plaintext)) != 1) { printf("CipherUpdate failed.\n"); EVP_CIPHER_CTX_free(ctx); exit(EXIT_FAILURE); } ciphertext_len+=update_len; printf("update size: %d\n",ciphertext_len); // 校验Final阶段的返回值,捕获填充禁用时的长度错误 if (EVP_CipherFinal_ex(ctx,ciphertext+ciphertext_len,&final_len) != 1) { printf("CipherFinal failed: plaintext length not multiple of block size!\n"); EVP_CIPHER_CTX_free(ctx); exit(EXIT_FAILURE); } ciphertext_len+=final_len; EVP_CIPHER_CTX_free(ctx); printf("Ciphertext length = %d\n", ciphertext_len); printf("The content inside ciphertext{"); for(int i = 0; i < ciphertext_len; i++){ if(i==ciphertext_len-1) printf("%02x", ciphertext[i]); else printf("%02x-", ciphertext[i]); } printf("}\n"); return 0; }
额外说明
- OpenSSL 3中
EVP_CIPHER_CTX_set_padding的调用时机是正确的,必须在EVP_CipherInit_ex之后、EVP_CipherUpdate之前设置。 - 若必须加密非块倍数长度的数据且禁用填充,需自行手动处理明文对齐(比如添加自定义填充字节,解密时再移除),但这不符合AES-CBC的标准使用规范,仅适用于特殊场景。
内容的提问来源于stack exchange,提问作者FilResto
相关产品推荐
相关产品推荐

