OpenSSL EVP AES加密后Base64编码结果不符问题求助
问题描述
已在C#、JScript、Python、Java中实现AES加密+Base64编码的数据混淆操作,现用C语言基于OpenSSL EVP库复现,出现以下问题:
- 加密后的字节与Python版本完全一致,但Base64编码结果完全不符(其他语言均与Python匹配)
- 待加密数据长度可变(1至100个数据点),可能存在内存管理问题
相关代码与运行结果
C语言代码
#include <X11/Xlib.h> #include <assert.h> #include <unistd.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <malloc.h> #include <time.h> #include <errno.h> #include <linux/input.h> #include <fcntl.h> #include <string.h> #include <openssl/sha.h> #include <openssl/hmac.h> #include <openssl/evp.h> #include <openssl/kdf.h> #include <openssl/params.h> #include <openssl/bio.h> #include <openssl/buffer.h> void PBKDF2_HMAC_SHA_1(const char* pass, int passlen, const unsigned char* salt, int saltlen, int32_t iterations, uint32_t outputBytes, char* hexResult, uint8_t* binResult) { unsigned int i; unsigned char digest[outputBytes]; PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iterations, EVP_sha1(), outputBytes, digest); for (i = 0; i < sizeof(digest); i++) { sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]); binResult[i] = digest[i]; } } int main(void){ char intext[] = "[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]"; int outlen, final_length; EVP_CIPHER_CTX *ctx; ctx = EVP_CIPHER_CTX_new(); size_t i; char sid[] = "u9SXNMeTkvyBr3n81SJ7Lj216w04gJ99"; char pk[] = "jeIHjod1cZeM1U04cy8z7488AeY1Sl25"; uint32_t outputBytes = 48; uint32_t iterations = 128; unsigned char byteresult[2*outputBytes+1]; char hexresult[2*outputBytes+1]; memset(byteresult,0,sizeof(byteresult)); uint8_t binResult[outputBytes+1]; memset(binResult,0,sizeof(binResult)); char *finResult = NULL; char key[65]; memset(key,0,sizeof(key)); char * keystart = hexresult +32; char iv[33]; memset(iv,0,sizeof(iv)); PBKDF2_HMAC_SHA_1(sid,strlen(sid),pk,strlen(pk),iterations,outputBytes,hexresult,binResult); memcpy(key, keystart,64); memcpy(iv, hexresult,32); EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL,(unsigned char *)key, (unsigned char *)iv, 1); unsigned char *outbuf; int outbuflen = sizeof(intext) + EVP_MAX_BLOCK_LENGTH - (sizeof(intext) % 16); outbuf = (unsigned char *)malloc(outbuflen); EVP_CipherUpdate(ctx, outbuf, &outbuflen,(unsigned char *)intext, strlen(intext)); EVP_CipherFinal_ex(ctx, outbuf + outbuflen, &final_length); outlen += final_length; EVP_CIPHER_CTX_free(ctx); char bytesout[strlen(outbuf) + outbuflen]; int buflen = 0; for (i=0;i< outbuflen + final_length;i++) { buflen += 1; sprintf(bytesout + (i * 2),"%02x", outbuf[i]); } printf("bytesout: %s\n", bytesout); char outtext[sizeof(bytesout)]; memset(outtext,0, sizeof(outtext)); int outtext_len = sizeof(outtext); EVP_ENCODE_CTX *ectx = EVP_ENCODE_CTX_new(); EVP_EncodeInit(ectx); EVP_EncodeBlock(outtext, bytesout, sizeof(bytesout)); EVP_EncodeFinal(ectx, (unsigned char*)outtext, &outtext_len); EVP_ENCODE_CTX_free(ectx); printf("b64Encoded String %s \n", outtext);}
Makefile
gcc simplecipher.c -o simplecipher -lX11 -lncurses -lssl -lcrypto
C运行结果
bytesout: eafafcde5c00eb6e649d61a09f9b52d13dd8c783d73afcbc03dfb5cea0cd3ab627528ec1b2997105871d570c0b972349943800aacd063093d97f7f39554775aa4256bd26599dde66bb76b925d9f021f6b657d1a91eb08e1900b6ad91f7f65b97e1a7e17b8d959a65d6893af458e26761536b3ffdf470f89f1aac24ca02782fb8a691c25b368549387890dc73143bb213e0ce616264e5b30add3b480c24f5edc6 b64Encoded String ZWFmYWZjZGU1YzAwZWI2ZTY0OWQ2MWEwOWY5YjUyZDEzZGQ4Yzc4M2Q3M2FmY2JjMDNkZmI1Y2VhMGNkM2FiNjI3NTI4ZWMxYjI5OTcxMDU4NzFkNTcwYzBiOTcyMzQ5OTQzODAwYWFjZDA2MzA5M2Q5N2Y3ZjM5NTU0Nzc1YWE0MjU2YmQyNjU5OWRkZTY2YmI3NmI=
Python代码
import base64 from Cryptodome.Cipher import AES from Cryptodome.Random import get_random_bytes from Cryptodome.Protocol.KDF import PBKDF2 from Crypto.Util.Padding import pad import binascii symmetric_key = "u9SXNMeTkvyBr3n81SJ7Lj216w04gJ99" salt = "jeIHjod1cZeM1U04cy8z7488AeY1Sl25" pbbytes = PBKDF2(symmetric_key.encode("utf-8"), salt.encode("utf-8"), 48, 128) iv = pbbytes[0:16] key = pbbytes[16:48] half_iv=iv[0:8] half_key=key[0:16] cipher = AES.new(key, AES.MODE_CBC, iv) cipher = AES.new(binascii.hexlify(bytes(half_key)), AES.MODE_CBC, binascii.hexlify(bytes(half_iv))) print("test encoding:") intext = b"[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]" print("intext pre padding: ", intext) paddedtext = pad(intext,16) print("intext post padding: ", paddedtext) en_bytes = cipher.encrypt(paddedtext) print("encrypted bytes: ", binascii.hexlify(bytearray(en_bytes))) en_data = base64.b64encode(en_bytes) en_bytes_string = ''.join(map(chr, en_bytes)) print("encoded bytes: ", en_data)
Python运行结果
encrypted bytes: b'eafafcde5c00eb6e649d61a09f9b52d13dd8c783d73afcbc03dfb5cea0cd3ab627528ec1b2997105871d570c0b972349943800aacd063093d97f7f39554775aa4256bd26599dde66bb76b925d9f021f6b657d1a91eb08e1900b6ad91f7f65b97e1a7e17b8d959a65d6893af458e26761536b3ffdf470f89f1aac24ca02782fb8a691c25b368549387890dc73143bb213e0ce616264e5b30add3b480c24f5edc6' encoded bytes: b'6vr83lwA625knWGgn5tS0T3Yx4PXOvy8A9+1zqDNOrYnUo7BsplxBYcdVwwLlyNJlDgAqs0GMJPZf385VUd1qkJWvSZZnd5mu3a5JdnwIfa2V9GpHrCOGQC2rZH39luX4afhe42VmmXWiTr0WOJnYVNrP/30cPifGqwkygJ4L7imkcJbNoVJOHiQ3HMUO7IT4M5hYmTlswrdO0gMJPXtxg=='
问题排查与解决方案
核心问题:Base64编码对象错误
你的C代码中,错误地对加密字节的十六进制字符串(bytesout)做了Base64编码,而Python是直接对原始加密字节做Base64编码。这是导致结果不符的根本原因。
此外还有几处内存和逻辑问题,逐一修正如下:
1. 移除不必要的十六进制转换步骤
不需要把加密后的outbuf转成十六进制字符串bytesout,直接对outbuf中的原始加密字节做Base64编码即可。
2. 修复未初始化变量
outlen未初始化就进行outlen += final_length,会导致未定义行为,需要初始化为outbuflen。
3. 修正Base64编码的正确用法
使用EVP_EncodeUpdate和EVP_EncodeFinal正确处理任意长度的输入,而不是误用EVP_EncodeBlock(该函数仅处理单个块,且会添加换行)。
4. 对齐Python的密钥/IV处理逻辑
Python中对PBKDF2结果做了截取:取前8字节作为half_iv,中间16字节作为half_key,再将这两个片段转成十六进制字符串作为AES实际使用的key和iv。原C代码的密钥截取逻辑有误,需修正对齐。
5. 内存管理优化
- 动态分配Base64输出缓冲区,避免栈溢出(尤其当数据量大时)
- 确保所有分配的内存最终释放
修正后的C代码
#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <openssl/evp.h> #include <openssl/kdf.h> void PBKDF2_HMAC_SHA_1(const char* pass, int passlen, const unsigned char* salt, int saltlen, int32_t iterations, uint32_t outputBytes, uint8_t* binResult) { PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iterations, EVP_sha1(), outputBytes, binResult); } int main(void){ char intext[] = "[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]"; int outbuflen, final_length; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); char sid[] = "u9SXNMeTkvyBr3n81SJ7Lj216w04gJ99"; char pk[] = "jeIHjod1cZeM1U04cy8z7488AeY1Sl25"; uint32_t outputBytes = 48; uint32_t iterations = 128; uint8_t binResult[outputBytes]; memset(binResult, 0, sizeof(binResult)); // 生成PBKDF2密钥材料,直接用二进制结果 PBKDF2_HMAC_SHA_1(sid, strlen(sid), (unsigned char*)pk, strlen(pk), iterations, outputBytes, binResult); // 和Python对齐:取前8字节作为half_iv,中间16字节作为half_key uint8_t half_iv[8], half_key[16]; memcpy(half_iv, binResult, 8); memcpy(half_key, binResult + 16, 16); // 将half_iv和half_key转成十六进制字符串(每个字节对应2个字符) char iv_hex[17], key_hex[33]; for(int i=0; i<8; i++) sprintf(iv_hex + i*2, "%02x", half_iv[i]); for(int i=0; i<16; i++) sprintf(key_hex + i*2, "%02x", half_key[i]); // 初始化AES-256-CBC上下文 EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)key_hex, (unsigned char*)iv_hex, 1); // 计算加密所需缓冲区大小 int inlen = strlen(intext); int block_size = EVP_CIPHER_block_size(EVP_aes_256_cbc()); outbuflen = inlen + block_size - (inlen % block_size); unsigned char *outbuf = (unsigned char *)malloc(outbuflen); if(!outbuf){ perror("malloc failed"); return 1; } // 执行加密 EVP_CipherUpdate(ctx, outbuf, &outbuflen, (unsigned char *)intext, inlen); EVP_CipherFinal_ex(ctx, outbuf + outbuflen, &final_length); int total_enc_len = outbuflen + final_length; EVP_CIPHER_CTX_free(ctx); // 计算Base64输出所需大小:每个3字节转4字符,向上取整,加上终止符 int b64_len = ((total_enc_len + 2) / 3) * 4 + 1; char *b64_out = (char*)malloc(b64_len); if(!b64_out){ perror("malloc failed"); free(outbuf); return 1;
相关产品推荐
相关产品推荐

