C++ OpenSSL 3.0.8 AES加解密

2023-11-02

  2023年后,openssl进入3.0版本,openssl的加解密代码也出现了一些变化,例如编译时会有如下错误:

error C4996: ‘AES_set_encrypt_key’: Since OpenSSL 3.0

  如果使用OpenSSL 1.1.1 sdk编译则没有上述错误,使用3.0以上的openssl sdk就会报错,那是因为3.0的不兼容1.0的sdk。如果你想继续使用已弃用的函数,并且不想更改代码,可以考虑禁用特定的编译警告。在 Visual Studio 中,你可以使用 #pragma warning(disable: 4996) 来禁用这个特定的警告。请注意,这并不是一个推荐的解决方案,因为它可能会掩盖潜在的问题。最佳的解决方案通常是更新你的代码,以使用新的API。这样可以确保你的代码与最新的库版本兼容,并且可以从新版本中获得的安全和性能改进中受益。

  下面是C++ OpenSSL 3.0 AES加解密的代码:

#pragma once

#include <iostream>
#include <vector>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <string>
#include <codecvt>
#include <sstream>
#include <iomanip>

class CEncrypt3 {
private:
    CEncrypt3() {
        const unsigned char fixed_key[32] = { 0x71, 0x02, 0x03, 0x04, 0x05, 0x06, 0x17, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x4A, 0x0F, 0x10,
                                              0x11, 0x12, 0x53, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0xFC, 0x10, 0x1E, 0x1F, 0x20 };
        const unsigned char fixed_iv[16] = { 0x21, 0x02, 0x03, 0xA4, 0x05, 0x06, 0x23, 0x08, 0x09, 0x0A, 0x1B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };

        std::copy(fixed_key, fixed_key + sizeof(key), key);
        std::copy(fixed_iv, fixed_iv + sizeof(iv), iv);
    }

public:
    static CEncrypt3& Instance() {
        static CEncrypt3 instance;
        return instance;
    }

    CEncrypt3(const CEncrypt3&) = delete;
    CEncrypt3& operator=(const CEncrypt3&) = delete;

    std::wstring Encrypt(const std::wstring& plaintext)
    {
        if (plaintext.empty())
            return L"";

        std::vector<unsigned char> ciphertext;
        EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
        if (!ctx)
        {
            throw std::runtime_error("Failed to create cipher context");
        }

        if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            throw std::runtime_error("Failed to initialize encryption");
        }

        std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
        std::string utf8_text = converter.to_bytes(plaintext);

        int len;
        ciphertext.resize(utf8_text.size() + EVP_CIPHER_block_size(EVP_aes_256_cbc()));
        if (EVP_EncryptUpdate(ctx, ciphertext.data(), &len, reinterpret_cast<const unsigned char*>(utf8_text.data()), utf8_text.size()) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            throw std::runtime_error("Failed to encrypt data");
        }

        int padding_len;
        if (EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &padding_len) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            throw std::runtime_error("Failed to finalize encryption");
        }

        ciphertext.resize(len + padding_len);
        EVP_CIPHER_CTX_free(ctx);

        std::wstringstream wss;
        for (auto c : ciphertext) {
            wss << std::hex << std::setw(2) << std::setfill(L'0') << (int)c;
        }

        return wss.str();
    }

    std::wstring Decrypt(const std::wstring& ciphertext)
    {
        if (ciphertext.empty())
            return L"";

        std::vector<unsigned char> ciphertext_bytes;
        for (size_t i = 0; i < ciphertext.size(); i += 2) {
            std::wstring byte_string = ciphertext.substr(i, 2);
            unsigned char byte = static_cast<unsigned char>(std::stoi(byte_string, nullptr, 16));
            ciphertext_bytes.push_back(byte);
        }

        std::vector<unsigned char> plaintext;
        EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
        if (!ctx)
        {
            throw std::runtime_error("Failed to create cipher context");
        }

        if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            throw std::runtime_error("Failed to initialize decryption");
        }

        int len;
        plaintext.resize(ciphertext_bytes.size());
        if (EVP_DecryptUpdate(ctx, plaintext.data(), &len, ciphertext_bytes.data(), ciphertext_bytes.size()) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            throw std::runtime_error("Failed to decrypt data");
        }

        int padding_len;
        if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &padding_len) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            throw std::runtime_error("Failed to finalize decryption");
        }

        plaintext.resize(len + padding_len);
        EVP_CIPHER_CTX_free(ctx);

        std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
        return converter.from_bytes(reinterpret_cast<const char*>(plaintext.data()), reinterpret_cast<const char*>(plaintext.data() + plaintext.size()));
    }

private:
    unsigned char key[32];
    unsigned char iv[16];
};



int main()
{
    CEncrypt3& instance = CEncrypt3::Instance();

    std::wstring plaintext = L"中文加密解密容易出现乱码";

    std::wstring ciphertext = instance.Encrypt(plaintext);
    std::wstring decrypted_text = instance.Decrypt(ciphertext);

    std::wcout << L"Original text: " << plaintext << std::endl;
    std::wcout << L"Decrypted text: " << decrypted_text << std::endl;

    return 0;
}

CEncrypt3用了单例模式,在其它地方调用时,使用CEncrypt3::Instance().Encrypt(plaintext)即可。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ OpenSSL 3.0.8 AES加解密 的相关文章

  • Exit() 时是否调用基本对象析构函数?

    我意识到这个问题已经出现过几次 但我试图获得上述问题的明确答案 但我不断遇到相互矛盾的信息 我需要知道的是 当我使用 exit 时 基本类对象是否被破坏 我知道需要删除动态内存 但我的意思更像是 include
  • 如何在 VC++ CString 中验证有效的整数和浮点数

    有人可以告诉我一种有效的方法来验证 CString 对象中存在的数字是有效整数还是浮点数吗 Use tcstol http msdn microsoft com en us library w4z2wdyc aspx and tcstod
  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • 传递 constexpr 对象

    我决定给予新的C 14的定义constexpr旋转并充分利用它 我决定编写一个小的编译时字符串解析器 然而 我正在努力保持我的对象constexpr将其传递给函数时 考虑以下代码 include
  • 无法注册时间触发的后台任务

    对于 Windows 8 应用程序 在 C Xaml 中 我尝试注册后台任务 很难说 但我想我的后台任务已正确注册 但是当我单击调试位置工具栏上的后台任务名称时 我的应用程序停止工作 没有任何消息 我查看了事件查看器上的日志 得到 具有入口
  • 语音识别编程问题入门

    所以 你们可能都看过 钢铁侠 其中托尼与一个名为贾维斯的人工智能系统进行交互 演示剪辑here http www youtube com watch v Go8zsh1Ev6Y 抱歉 这是广告 我非常熟悉 C C 和 Visual Basi
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • 如何使用 Regex.Replace 从字符串中删除数字?

    我需要使用Regex Replace从字符串中删除所有数字和符号 输入示例 123 abcd33输出示例 abcd 请尝试以下操作 var output Regex Replace input d string Empty The d标识符
  • 什么是空终止字符串?

    它与什么不同标准 字符串 http www cplusplus com reference string string 字符串 实际上只是一个数组chars 空终止字符串是指其中包含空字符的字符串 0 标记字符串的结尾 不一定是数组的结尾
  • 如何使用 ASP.NET Core 获取其他用户的声明

    我仍在学习 ASP NET Core 的身份 我正在进行基于声明的令牌授权 大多数示例都是关于 当前 登录用户的 就我而言 我的 RPC 服务正在接收身份数据库中某个用户的用户名和密码 我需要 验证是否存在具有此类凭据的用户 获取该用户的所
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • 将函数参数类型提取为参数包

    这是一个后续问题 解包 元组以调用匹配的函数指针 https stackoverflow com questions 7858817 unpacking a tuple to call a matching function pointer
  • 如何最好地以编程方式将 `__attribute__ ((unused))` 应用于这些自动生成的对象?

    In my makefile我有以下目标 它将文本 HTML 资源 编译 为unsigned char数组使用xxd i http linuxcommand org man pages xxd1 html 我将结果包装在匿名命名空间和标头保
  • 如何在 C# 中创建异步方法?

    我读过的每一篇博客文章都会告诉您如何在 C 中使用异步方法 但由于某些奇怪的原因 从未解释如何构建您自己的异步方法来使用 所以我现在有这段代码使用我的方法 private async void button1 Click object se
  • 模板类的模板构造函数的 C++ 显式模板特化

    我有一个像这样的课程 template
  • 如何解压 msgpack 文件?

    我正在将 msgpack 编码的数据写入文件 在编写时 我只是使用 C API 的 fbuffer 如 我为示例删除了所有错误处理 FILE fp fopen filename ab msgpack packer pk msgpack pa
  • 没有“对 *this”功能的右值引用的解决方法

    我有一个围绕可移动对象的代理容器类 并希望代理能够隐式生成对底层对象的右值引用 但仅当代理本身被移动时 我相信我将能够按照提案 n2439 实施此行为 将移动语义扩展到 this http www open std org jtc1 sc2
  • 无法将字符串文字分配给装箱的 std::string 向量

    这是我的类型系统的简化版本 include
  • MySqlConnectionStringBuilder - 使用证书连接

    我正在尝试连接到 Google Cloud Sql 这是一个 MySql 解决方案 我能够使用 MySql Workbench 进行连接 我如何使用 C 连接MySqlConnectionStringBuilder 我找不到提供这三个证书的

随机推荐