使用OpenSSL加解密字符串:缓冲区调整、Base64转换及代码异常
AES加密问题解析与代码修正
问题描述
- 不清楚如何调整存储加解密字符串的
cipher_buf和buffer的大小 - 不知道如何将加密后的
buffer转换为Base64,是否需要第三方库还是OpenSSL自带API可用 - 当前代码存在异常:执行最后一次
buffer.append后,Visual Studio调试器显示buffer内容为空,但buffer.size()返回值为31
原代码
#include <openssl/aes.h> #include <openssl/evp.h> #include <Windows.h> #include <string> void decryptOrEncrypt() { bool encrypt = true; std::string str = "testing testing"; const int MAX_BUFFER_SIZE = str.length(); int out_len; EVP_CIPHER_CTX * ctx = EVP_CIPHER_CTX_new(); std::string key = "abcdabcdabcdabcd"; std::string iv = "abcdabcdabcdabcd"; size_t len = key.size(); byte* keyPtr = (byte*)key.data(); byte* ivPtr = (byte*)iv.data(); EVP_CipherInit(ctx, EVP_aes_128_cbc(), keyPtr, ivPtr , encrypt); int blocksize = EVP_CIPHER_CTX_block_size(ctx); std::string cipher_buf; cipher_buf.resize(MAX_BUFFER_SIZE + blocksize); std::string buffer; buffer.resize(MAX_BUFFER_SIZE); EVP_CipherUpdate(ctx, reinterpret_cast<uchar *>(cipher_buf.data()) , &out_len, reinterpret_cast<uchar *>(str.data()), str.length()); buffer.append(cipher_buf.data(), out_len); EVP_CipherFinal(ctx, reinterpret_cast<uchar *>(cipher_buf.data()), &out_len); buffer.append(cipher_buf.data(), out_len); auto s = buffer.size(); //std::string test = base64_encode(buffer.c_str(), buffer.length()); //std::string test = base64_decode(buffer); EVP_CIPHER_CTX_free(ctx); return; } INT main(INT argc, PCHAR* argv) { decryptOrEncrypt(); }
问题解决与优化
1. 解决buffer显示为空但size异常的问题
你的代码中buffer.resize(MAX_BUFFER_SIZE)会先给buffer填充14个空字符('\0',原字符串长度为14),后续两次append又添加了17个加密后的数据,最终buffer的前14位都是'\0',调试器通常会在第一个'\0'处停止显示内容,所以看起来为空,但实际size是正确的14+17=31。
修正方法:初始化buffer时不要提前resize,直接用空字符串起步,仅通过append添加有效数据:
std::string buffer; // 初始为空,无需提前分配空间
2. 调整cipher_buf与buffer的大小
- cipher_buf:作为单次加密的临时输出缓冲区,只需满足单次输出的最大可能长度。
EVP_CipherUpdate的单次输出最大长度为输入长度 + 块大小,你当前设置的MAX_BUFFER_SIZE + blocksize完全足够;如果处理的字符串不大,也可以直接固定设为1024这类足够大的数值,避免动态计算。 - buffer:
std::string的append方法会自动扩容,无需提前预设大小。如果想优化性能减少扩容次数,可以提前预估加密后的总长度(AES-CBC加密后长度为原长度向上取整到块大小的整数倍,最多比原长度多一个块大小),用reserve预分配空间:
buffer.reserve(str.length() + blocksize);
3. 加密后转Base64:使用OpenSSL自带API
OpenSSL自带完整的Base64编解码工具,无需依赖第三方库。可以使用EVP_EncodeBlock(适合小数据量)或EVP_EncodeInit_ex/EVP_EncodeUpdate/EVP_EncodeFinal(适合大数据流)。
示例:加密后转Base64
在你的代码中,加密完成后添加以下代码即可:
// 计算Base64输出的最大长度 int base64_max_len = EVP_ENCODE_LENGTH(buffer.size()); std::string base64_result(base64_max_len, '\0'); // 执行Base64编码,EVP_EncodeBlock会自动添加换行符 int actual_len = EVP_EncodeBlock( reinterpret_cast<unsigned char*>(base64_result.data()), reinterpret_cast<const unsigned char*>(buffer.data()), buffer.size() ); // 去掉末尾自动添加的换行符(如果不需要) if (base64_result.back() == '\n') { base64_result.pop_back(); actual_len--; } // 调整字符串到实际长度 base64_result.resize(actual_len);
Base64解码示例(如果需要)
// 假设base64_str是要解码的Base64字符串 std::string decoded_data; decoded_data.reserve(base64_str.size() * 3 / 4); // 预估解码后的最大长度 int out_len; EVP_DecodeBlock( reinterpret_cast<unsigned char*>(decoded_data.data()), reinterpret_cast<const unsigned char*>(base64_str.data()), base64_str.size() ); // 注意:需要根据实际情况调整解码后的长度,通常需要去掉填充的'='
内容的提问来源于stack exchange,提问作者Cesar
相关产品推荐
相关产品推荐

