使用OpenSSL实现AES加密后无法显示密文输出的问题求助
问题
正在学习OpenSSL的使用方法,编写了一段实现AES加密明文并输出密文的C语言代码,但无法正确显示加密后的密文。查阅OpenSSL文档了解到BIO_dump_fp函数可用于打印十六进制值,但代码运行后无法得到预期输出。附上代码如下:
#include <openssl/evp.h> #include <openssl/rand.h> #include <openssl/err.h> #include <stdint.h> int main() { unsigned char *buf; int num; int rn = RAND_bytes(buf, num); //if(rn != 1) //{ // ERR_print_errors(bp); //} if(rn == 1) { EVP_CIPHER_CTX *ctx; const EVP_CIPHER *type = EVP_aes_128_cbc(); const unsigned char *iv; unsigned char *out; int *outl; unsigned char *in; int inl; iv = buf; // Random numbers from RAND_bytes const unsigned char *key = (const unsigned char *) "\x00\x01\x02\x03\x04\x05\x06\x07" "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17" "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"; in = "password"; // Plaintext to be decrypted ctx = EVP_CIPHER_CTX_new(); // Alocate ctx variable EVP_EncryptInit(ctx, type, key, iv); EVP_EncryptUpdate(ctx, out, outl, in, inl); EVP_EncryptFinal(ctx, out, outl); const char *ciphertext = out; uintptr_t ciphertext_len = (uintptr_t)outl; // Convert pointer type variable to non-pointer type variable // Bio dump BIO_dump_fp(stdout, out, ciphertext_len); // Clean up EVP_CIPHER_CTX_free(ctx); } }
请帮忙排查问题,指导如何正确显示加密后的密文输出。
问题排查与修正
你的代码存在多处未定义行为和逻辑错误,导致无法正常输出密文,以下是具体问题和修正方案:
1. 未初始化的指针与变量
buf是野指针,未分配内存就传给RAND_bytes,会导致非法内存访问;num未赋值,RAND_bytes不知道要生成多少字节(AES-CBC的IV长度等于块大小,即16字节)。out是野指针,未分配加密输出缓冲区;outl是指针但未指向有效int变量,无法存储加密输出长度。inl未赋值,EVP_EncryptUpdate不知道明文长度,应该用strlen((char*)in)获取。
2. 密钥与加密算法不匹配
你使用EVP_aes_128_cbc()(128位AES),但提供的key是32字节(256位),两者不匹配。要么将key改为16字节,要么改用EVP_aes_256_cbc()。
3. 加密输出缓冲区分配错误
AES-CBC模式需要填充,输出缓冲区的大小至少为明文长度 + AES块大小(16字节),才能容纳加密后的所有数据。
4. 密文长度计算错误
EVP_EncryptUpdate和EVP_EncryptFinal会分别返回各自写入的字节数,需要累加这两个值得到总密文长度,不能直接用同一个指针变量存储。
5. 缺失错误处理
未检查RAND_bytes、EVP_CIPHER_CTX_new()、EVP_EncryptInit()等函数的返回值,无法定位失败原因。
修正后的代码
#include <openssl/evp.h> #include <openssl/rand.h> #include <openssl/err.h> #include <string.h> #include <stdio.h> #include <stdlib.h> int main() { // 1. 初始化IV(AES-CBC的IV长度等于块大小16字节) unsigned char iv[16]; int rn = RAND_bytes(iv, sizeof(iv)); if (rn != 1) { fprintf(stderr, "生成随机IV失败:"); ERR_print_errors_fp(stderr); return 1; } // 2. 配置加密参数:改用256位AES匹配32字节密钥 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) { fprintf(stderr, "创建加密上下文失败:"); ERR_print_errors_fp(stderr); return 1; } const EVP_CIPHER *type = EVP_aes_256_cbc(); const unsigned char key[] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f }; unsigned char *in = (unsigned char*)"password"; int in_len = strlen((char*)in); // 3. 分配输出缓冲区:明文长度 + 块大小(16字节) int out_len_max = in_len + EVP_CIPHER_block_size(type); unsigned char *out = malloc(out_len_max); if (!out) { fprintf(stderr, "分配内存失败\n"); EVP_CIPHER_CTX_free(ctx); return 1; } // 4. 初始化加密操作 if (EVP_EncryptInit_ex(ctx, type, NULL, key, iv) != 1) { fprintf(stderr, "初始化加密失败:"); ERR_print_errors_fp(stderr); free(out); EVP_CIPHER_CTX_free(ctx); return 1; } // 5. 执行加密更新 int out_len_update = 0; if (EVP_EncryptUpdate(ctx, out, &out_len_update, in, in_len) != 1) { fprintf(stderr, "加密更新失败:"); ERR_print_errors_fp(stderr); free(out); EVP_CIPHER_CTX_free(ctx); return 1; } // 6. 完成加密(处理填充) int out_len_final = 0; if (EVP_EncryptFinal_ex(ctx, out + out_len_update, &out_len_final) != 1) { fprintf(stderr, "加密完成失败:"); ERR_print_errors_fp(stderr); free(out); EVP_CIPHER_CTX_free(ctx); return 1; } // 总密文长度 int ciphertext_len = out_len_update + out_len_final; // 7. 用BIO_dump_fp打印十六进制密文 printf("加密后的密文(十六进制):\n"); BIO_dump_fp(stdout, out, ciphertext_len); // 8. 资源清理 free(out); EVP_CIPHER_CTX_free(ctx); return 0; }
编译与运行
编译时需要链接OpenSSL库:
gcc -o aes_encrypt aes_encrypt.c -lcrypto
运行后会输出加密后的十六进制密文,格式类似:
加密后的密文(十六进制): 0000 - 7a 3b d2 6a 8c 2f 9e 5a-7f 0d 4c 3a 1e 8b 0f 63 z;.j./.Z..L:...c
内容的提问来源于stack exchange,提问作者yel1337
相关产品推荐
相关产品推荐

