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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:17:11