You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:45:40