C++ OpenSSL 3.0.8 AES加解密

  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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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)即可。

你可能感兴趣的:(C++,基础问题,c++,openssl,aes,c++加解密)