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

能否在基于OpenSSL EVP的C文件加解密程序中集成OpenSSL BIO?

OpenSSL EVP与BIO集成相关问题

背景说明

查阅OpenSSL文档可知,可通过OpenSSL EVP API复现如下命令的功能:

$ openssl aes-256-cbc -in text.txt -out text_out.txt -e -kfile encryption.key

对应的示例C程序如下:

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>

int main (void)
{
    /*
     * Set up the key and iv. Do I need to say to not hard code these in a
     * real application? :-)
     */

    /* A 256 bit key */
    unsigned char *key = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
                           0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
                           0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33,
                           0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31
                         };

    /* A 128 bit IV */
    unsigned char *iv = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
                          0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
                        };

    /* Message to be encrypted */
    unsigned char *plaintext =
        (unsigned char *)"The quick brown fox jumps over the lazy dog";

    /*
     * Buffer for ciphertext. Ensure the buffer is long enough for the
     * ciphertext which may be longer than the plaintext, depending on the
     * algorithm and mode.
     */
    unsigned char ciphertext[128];

    /* Buffer for the decrypted text */
    unsigned char decryptedtext[128];

    int decryptedtext_len, ciphertext_len;

    /* Encrypt the plaintext */
    ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
                              ciphertext);

    /* Do something useful with the ciphertext here */
    printf("Ciphertext is:\n");
    BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);

    /* Decrypt the ciphertext */
    decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
                                decryptedtext);

    /* Add a NULL terminator. We are expecting printable text */
    decryptedtext[decryptedtext_len] = '\0';

    /* Show the decrypted text */
    printf("Decrypted text is:\n");
    printf("%s\n", decryptedtext);


    return 0;
}

加密函数实现如下:

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
            unsigned char *iv, unsigned char *ciphertext)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int ciphertext_len;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new()))
        handleErrors();

    /*
     * Initialise the encryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     */
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
        handleErrors();

    /*
     * Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can be called multiple times if necessary
     */
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
        handleErrors();
    ciphertext_len = len;

    /*
     * Finalise the encryption. Further ciphertext bytes may be written at
     * this stage.
     */
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
        handleErrors();
    ciphertext_len += len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}

解密函数实现如下:

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
            unsigned char *iv, unsigned char *plaintext)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int plaintext_len;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new()))
        handleErrors();

    /*
     * Initialise the decryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     */
    if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
        handleErrors();

    /*
     * Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary.
     */
    if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
        handleErrors();
    plaintext_len = len;

    /*
     * Finalise the decryption. Further plaintext bytes may be written at
     * this stage.
     */
    if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
        handleErrors();
    plaintext_len += len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return plaintext_len;
}

技术问题解答

1. 是否可以在这类使用OpenSSL EVP进行文件加解密的C程序中集成OpenSSL BIO工具?

完全可以。OpenSSL的BIO(Basic Input/Output)框架本身就支持与EVP加密模块集成,可将BIO链与EVP加解密操作结合,实现对文件的流式加解密处理。比如创建BIO_f_cipher类型的BIO,将其与文件BIO(BIO_s_file)串联,直接通过BIO读写操作完成加解密,无需手动调用EVP的EncryptUpdate/DecryptUpdate等接口。

2. 若可行,相较于仅使用OpenSSL EVP进行加解密,集成BIO有哪些优势?

  • 简化代码逻辑:BIO封装了底层EVP加解密细节和文件IO操作,无需手动管理缓冲区、分块调用EVP接口,只需通过标准的BIO读写函数(如BIO_read/BIO_write)即可完成整个加解密流程,代码更简洁。
  • 流式处理能力:BIO天然支持流式数据处理,对于大文件无需一次性加载到内存,边读边处理,节省内存资源,避免内存溢出风险。
  • 模块化与可扩展性:BIO采用链状结构,可轻松添加其他功能模块,比如同时集成Base64编码BIO、压缩BIO等,无需修改核心加解密逻辑,直接扩展BIO链即可实现复合功能。
  • 统一的IO接口:无论是文件、网络套接字还是内存数据,BIO都提供一致的读写接口,切换数据源时无需修改加解密相关代码,适配性更强。

3. 哪些场景下使用BIO处理文件比普通文件操作更为便捷?

  • 大文件加解密:处理GB级以上的大文件时,BIO的流式处理可避免将整个文件加载到内存,大幅降低内存占用,提升程序稳定性。
  • 多功能复合处理:如果需要同时对文件进行加解密+Base64编码/解码、加解密+压缩/解压缩等操作,使用BIO链可将这些功能无缝串联,无需单独编写多步处理逻辑。
  • 跨IO场景适配:如果程序后续可能需要支持网络套接字、内存缓冲区等其他数据源的加解密,使用BIO可保持加解密逻辑不变,仅替换BIO链的末端节点即可,减少代码改动量。
  • 简化错误处理:BIO框架内置了统一的错误处理机制,结合OpenSSL的错误栈,可更方便地排查IO或加解密过程中出现的问题,无需手动处理每一步EVP和文件IO的错误返回。

内容的提问来源于stack exchange,提问作者rguibuesretpo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:54:57