OpenSSL加解密接口使用

OpenSSL库编译

https://www.openssl.org/source/
本示例均使用openssl-3.0.5.tar.gz,下载后一次执行一下命令

tar xvf openssl-3.0.5.tar.gz     
cd openssl-3.0.5

./config ----prefix=$PWD/install
make -j4
make install

最终得到openssl相关库libcrypto、libssl

工程结构

.
├── 3rdparty
│   └── openssl3
│       ├── bin
│       ├── include
│       │   └── openssl
│       ├── lib64
│       │   ├── engines-3
│       │   ├── ossl-modules
│       │   └── pkgconfig
│       └── ssl
│           ├── certs
│           ├── misc
│           └── private
├── CMakeLists.txt
├── src
│   ├── crypto_aes.cpp
│   ├── crypto_aes.hpp
│   ├── crypto_rsa.cpp
│   ├── crypto_rsa.hpp
│   ├── dbg.cpp
│   └── dbg.hpp
└── tests
    ├── aes_test.cpp
    ├── CMakeLists.txt
    └── rsa_test.cpp

AES加解密实现

// crypto_aes.hpp
#pragma once

#include "openssl/aes.h"

#include <string>
#include <memory>

class CryptoAES
{
public:
    CryptoAES();
    ~CryptoAES();

    std::string generate_aes_key(uint32_t key_len);
    uint32_t set_aes_key(const std::string &key)
    {
        _aes_key = key;
        return 0;
    }

    std::string get_aes_key() const
    {
        return _aes_key;
    }

    std::string aes_encrypt(const std::string &data);
    std::string aes_decrypt(const std::string &data);

private:
    void get_md5_digest(const std::string &data, uint8_t result[16]);
    std::unique_ptr<AES_KEY> get_aes_key(const std::string &key, int flag);

private:
    std::string _aes_key;
};
//crypto_aes.cpp
#include "crypto_aes.hpp"
#include "dbg.hpp"

#include "openssl/md5.h"

#include <cstring>
#include <fstream>
#include <memory>
#include <sstream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

CryptoAES::CryptoAES() {}
CryptoAES::~CryptoAES() {}

std::string CryptoAES::generate_aes_key(uint32_t key_len)
{
    uint32_t seed = 0;
    char output[128];

    seed = time(0);
    srand(seed);

    uint32_t flag = 0;
    for (uint32_t i = 0; i < key_len; ++i)
    {
        flag = rand() % 2;
        switch (flag)
        {
        case 0:
            output[i] = 'a' + rand() % 26;
            break;
        case 1:
            output[i] = '0' + rand() % 10;
            break;
        default:
            output[i] = 'x';
            break;
        }
    }

    return std::string(output);
}

void CryptoAES::get_md5_digest(const std::string &data, uint8_t result[16])
{
    MD5_CTX md5_ctx{};
    MD5_Init(&md5_ctx);
    MD5_Update(&md5_ctx, data.c_str(), data.length());
    MD5_Final(result, &md5_ctx);
}

std::unique_ptr<AES_KEY> CryptoAES::get_aes_key(const std::string &key, int flag)
{
    auto aes_key = std::make_unique<AES_KEY>();
    uint8_t md5_key[16]{};
    get_md5_digest(key, md5_key);
    if (flag == AES_ENCRYPT)
    {
        AES_set_encrypt_key(md5_key, sizeof(md5_key) * 8, aes_key.get());
    }
    else if (flag == AES_DECRYPT)
    {
        AES_set_decrypt_key(md5_key, sizeof(md5_key) * 8, aes_key.get());
    }
    
    return aes_key;
}

std::string CryptoAES::aes_encrypt(const std::string &data)
{
    LOG_INFO("AES Key:%s", _aes_key.c_str());
    auto aes_key = get_aes_key(_aes_key, AES_ENCRYPT);
    std::string ret_str;
    std::string data_bak = data;
    unsigned int data_length = data_bak.length();
    int padding = 0;
    if (data_bak.length() % AES_BLOCK_SIZE > 0)
    {
        padding = AES_BLOCK_SIZE - data_bak.length() % AES_BLOCK_SIZE;
    }

    data_length += padding;
    while (padding > 0)
    {
        data_bak += '\0';
        padding--;
    }

    for (unsigned int i = 0; i < data_length / AES_BLOCK_SIZE; i++)
    {
        std::string str_block = data_bak.substr(i * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
        unsigned char out[AES_BLOCK_SIZE];
        ::memset(out, 0, AES_BLOCK_SIZE);
        AES_encrypt((const unsigned char *)str_block.c_str(), out, aes_key.get());
        ret_str += std::string((const char *)out, AES_BLOCK_SIZE);
    }

    return ret_str;
}

std::string CryptoAES::aes_decrypt(const std::string &data)
{
    LOG_INFO("AES Key:%s", _aes_key.c_str());
    auto aes_key = get_aes_key(_aes_key, AES_DECRYPT);
    std::string ret_str;
    for (unsigned int i = 0; i < data.length() / AES_BLOCK_SIZE; i++)
    {
        std::string str_block = data.substr(i * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
        unsigned char out[AES_BLOCK_SIZE];
        ::memset(out, 0, AES_BLOCK_SIZE);
        AES_decrypt((const unsigned char *)str_block.c_str(), out, aes_key.get());
        ret_str += std::string((const char *)out, AES_BLOCK_SIZE);
    }

    auto pos = ret_str.find_last_not_of('\0');
    if (pos != std::string::npos)
    {
        ret_str = ret_str.substr(0, pos + 1);
    }

    return ret_str;
}

AES接口测试

// aes_test.cpp
#include "dbg.hpp"
#include "crypto_aes.hpp"

#include <string>

int main(int argc, char **argv)
{
    std::string src_data = "Hello Worl!";

    auto aes = std::make_unique<CryptoAES>();

    uint32_t aes_key_len = 16;
    std::string aes_key = aes->generate_aes_key(aes_key_len);
    aes->set_aes_key(aes_key);

    std::string enc_data = aes->aes_encrypt(src_data);
    std::string dec_data = aes->aes_decrypt(enc_data);

    LOG_INFO("[SRC]:%s", src_data.c_str());
    LOG_INFO("[DST]:%s", dec_data.c_str());

    return 0;
}

RSA加解密实现


// crypto_rsa.hpp
#pragma once

#include "openssl/rsa.h"

#include <string>

class CryptoRSA
{
public:
    CryptoRSA();
    ~CryptoRSA();

    void generate_rsa_key_pair(std::string &out_pub_key, std::string &out_priv_key);
    void set_rsa_key(const std::string &pub_key, const std::string &priv_key) {
        _rsa_pub_key = pub_key;
        _rsa_priv_key = priv_key;
    }

    std::string rsa_pub_encrypt(const std::string &data);
    std::string rsa_priv_decrypt(const std::string &data);

    std::string rsa_priv_encrypt(const std::string &data);
    std::string rsa_pub_decrypt(const std::string &data);

    uint32_t init_pub_rsa();
    uint32_t init_priv_rsa();

private:
    RSA *_rsa_pub{nullptr};
    RSA *_rsa_priv{nullptr};

    std::string _rsa_pub_key;
    std::string _rsa_priv_key;
};
// crypto_rsa.cpp
#include "crypto_rsa.hpp"
#include "dbg.hpp"

#include "openssl/err.h"
#include "openssl/rsa.h"
#include "openssl/ssl.h"

#include <cstring>
#include <fstream>
#include <memory>
#include <sstream>
#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

CryptoRSA::CryptoRSA() {}
CryptoRSA::~CryptoRSA() {}

uint32_t CryptoRSA::init_pub_rsa()
{
    BIO *keybio = BIO_new_mem_buf((char *)_rsa_pub_key.data(), -1);
    if (keybio == NULL)
    {
        LOG_ERR("BIO_new_mem_buf Failed");
        return -1;
    }

    _rsa_pub = PEM_read_bio_RSA_PUBKEY(keybio, &_rsa_pub, NULL, NULL);
    if (!_rsa_pub)
    {
        LOG_ERR("PEM_read_bio_RSA_PUBKEY Failed\n");
        BIO_set_close(keybio, BIO_CLOSE);
        BIO_free(keybio);
        return -1;
    }

    BIO_set_close(keybio, BIO_CLOSE);
    BIO_free(keybio);

    LOG_INFO("init_pub_rsa done\n");

    return 0;
}

uint32_t CryptoRSA::init_priv_rsa()
{
    BIO *keybio = BIO_new_mem_buf((char *)_rsa_priv_key.data(), -1);
    if (keybio == nullptr)
    {
        LOG_ERR("BIO_new_mem_buf Failed\n");
        return false;
    }

    _rsa_priv = PEM_read_bio_RSAPrivateKey(keybio, &_rsa_priv, NULL, NULL);
    if (!_rsa_priv)
    {
        LOG_ERR("PEM_read_bio_RSAPrivateKey failed\n");
        BIO_set_close(keybio, BIO_CLOSE);
        BIO_free(keybio);
        return false;
    }

    BIO_set_close(keybio, BIO_CLOSE);
    BIO_free(keybio);

    return true;
}

void CryptoRSA::generate_rsa_key_pair(std::string &out_pub_key, std::string &out_priv_key)
{
    const int KEY_LENGTH = 1024;
    size_t pri_len = 0;
    size_t pub_len = 0;

    RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);

    BIO *pri = BIO_new(BIO_s_mem());
    BIO *pub = BIO_new(BIO_s_mem());

    PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
    PEM_write_bio_RSA_PUBKEY(pub, keypair);

    pri_len = BIO_pending(pri);
    pub_len = BIO_pending(pub);

    char *pri_key = (char *)malloc(pri_len + 1);
    char *pub_key = (char *)malloc(pub_len + 1);

    BIO_read(pri, pri_key, pri_len);
    BIO_read(pub, pub_key, pub_len);

    pri_key[pri_len] = '\0';
    pub_key[pub_len] = '\0';

    out_pub_key = std::string(pub_key);
    out_priv_key = std::string(pri_key);

    std::ofstream pub_file("pubkey.pem", std::ios::out);
    if (!pub_file.is_open())
    {
        perror("pub key file open fail:");
        return;
    }

    pub_file << pub_key;
    pub_file.close();

    std::ofstream pri_file("prikey.pem", std::ios::out);
    if (!pri_file.is_open())
    {
        perror("pri key file open fail:");
        return;
    }

    pri_file << pri_key;
    pri_file.close();
    
    RSA_free(keypair);
    BIO_free_all(pub);
    BIO_free_all(pri);

    free(pri_key);
    free(pub_key);
}

std::string CryptoRSA::rsa_priv_encrypt(const std::string &data)
{
    std::string encrypt_text;

    int len = RSA_size(_rsa_priv);
    char *encrypt_data = (char *)malloc(len + 1);
    memset(encrypt_data, 0, len + 1);

    int ret = RSA_private_encrypt(data.length(), (const unsigned char *)data.c_str(), (unsigned char *)encrypt_data, _rsa_priv, RSA_PKCS1_PADDING);
    if (ret >= 0)
    {
        encrypt_text = std::string(encrypt_data, ret);
    }

    free(encrypt_data);
    return encrypt_text;
}

std::string CryptoRSA::rsa_pub_decrypt(const std::string &data)
{
    std::string decrypt_text;

    int len = RSA_size(_rsa_pub);
    char *decrypt_data = (char *)malloc(len + 1);
    memset(decrypt_data, 0, len + 1);

    int ret = RSA_public_decrypt(data.length(), (const unsigned char *)data.c_str(), (unsigned char *)decrypt_data, _rsa_pub, RSA_PKCS1_PADDING);
    if (ret >= 0)
    {
        decrypt_text = std::string(decrypt_data, ret);
    }

    free(decrypt_data);

    return decrypt_text;
}

std::string CryptoRSA::rsa_pub_encrypt(const std::string &data)
{
    std::string encrypt_text;
    int len = RSA_size(_rsa_pub);
    char *encrypt_data = (char *)malloc(len + 1);
    memset(encrypt_data, 0, len + 1);

    int ret = RSA_public_encrypt(data.length(), (const unsigned char *)data.c_str(), (unsigned char *)encrypt_data, _rsa_pub, RSA_PKCS1_PADDING);
    if (ret >= 0)
    {
        encrypt_text = std::string(encrypt_data, ret);
    }

    free(encrypt_data);
    return encrypt_text;
}

std::string CryptoRSA::rsa_priv_decrypt(const std::string &data)
{
    std::string decrypt_text;

    int len = RSA_size(_rsa_priv);
    char *decrypt_data = (char *)malloc(len + 1);
    memset(decrypt_data, 0, len + 1);

    int ret = RSA_private_decrypt(data.length(), (const unsigned char *)data.c_str(), (unsigned char *)decrypt_data, _rsa_priv, RSA_PKCS1_PADDING);
    if (ret >= 0)
    {
        decrypt_text = std::string(decrypt_data, ret);
    }

    free(decrypt_data);

    return decrypt_text;
}

RSA接口测试

// rsa_test.cpp
#include "dbg.hpp"
#include "crypto_rsa.hpp"

#include <memory>

int main(int argc, char **argv)
{
    auto rsa = std::make_unique<CryptoRSA>();

    std::string pub_key, priv_key;
    rsa->generate_rsa_key_pair(pub_key, priv_key);
    LOG_INFO("RSA pub_key:%s", pub_key.c_str());
    LOG_INFO("RSA pri_key:%s", priv_key.c_str());

    rsa->set_rsa_key(pub_key, priv_key);

    rsa->init_pub_rsa();
    rsa->init_priv_rsa();

    std::string src_data = "Hello Worl!";

    std::string enc_data = rsa->rsa_pub_encrypt(src_data);
    std::string dec_data = rsa->rsa_priv_decrypt(enc_data);

    LOG_INFO("[SRC]:%s", src_data.c_str());
    LOG_INFO("[DST]:%s", dec_data.c_str());

    return 0;
}

其中
CMakeLists.txt

project(practicle)

cmake_minimum_required(VERSION 3.1.3)

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if(CMAKE_COMPILER_IS_GNUCXX)
    add_compile_options(-D__STDC_FORMAT_MACROS)
    message(STATUS "-D__STDC_FORMAT_MACROS")
endif(CMAKE_COMPILER_IS_GNUCXX)

#set(CMAKE_BUILD_TYPE "Release")
if ("${CMAKE_BUILD_TYPE}" STREQUAL "")
    set(CMAKE_BUILD_TYPE "Debug")
endif ()

message(STATUS "编译类型:${CMAKE_BUILD_TYPE}")
add_compile_options(-fPIC -Wall -Wno-unused-variable -Wno-unused-value)

INCLUDE_DIRECTORIES(
    ${PROJECT_SOURCE_DIR}/src
    ${PROJECT_SOURCE_DIR}/3rdparty/openssl3/include
)

FIND_LIBRARY(COMM_CRYPTO crypto ${PROJECT_SOURCE_DIR}/3rdparty/openssl3/LIB64 NO_DEFAULT_PATH)
FIND_LIBRARY(COMM_SSL ssl ${PROJECT_SOURCE_DIR}/3rdparty/openssl3/LIB64 NO_DEFAULT_PATH)

aux_source_directory(${PROJECT_SOURCE_DIR}/src SRCLIST)
add_library(mycrypto ${SRCLIST})

set(LINK_LIB_LIST ${COMM_CRYPTO} ${COMM_SSL} mycrypto)

add_subdirectory(tests)

tests/CMakeLists.txt

aux_source_directory(. TEST_SRC_LIST)
foreach (TEST_SRC ${TEST_SRC_LIST})
    get_filename_component(TEST_EXE_NAME ${TEST_SRC} NAME_WE)
    message(STATUS "add test:${TEST_EXE_NAME}")
    add_executable(${TEST_EXE_NAME} ${TEST_SRC})
    target_link_libraries(${TEST_EXE_NAME} -Wl,--start-group ${LINK_LIB_LIST} -Wl,--end-group)
endforeach ()
使用 OpenSSL 库进行 AES 加解密的过程如下: 1. 密钥生成 首先需要生成一个密钥,可以使用 OpenSSL 提供的随机数生成函数生成一个随机的密钥。例如: ```c unsigned char key[16]; RAND_bytes(key, sizeof(key)); ``` 2. 加密 使用 AES 加密算法对数据进行加密。可以选择使用 ECB、CBC、CFB、OFB 等多种模式进行加密,这里以 CBC 模式为例: ```c // 输入数据 unsigned char *data = (unsigned char *)"hello world"; int data_len = strlen((const char *)data); // 初始化向量 unsigned char iv[AES_BLOCK_SIZE]; RAND_bytes(iv, sizeof(iv)); // 加密 unsigned char *encrypted_data = (unsigned char *)malloc(data_len); int encrypted_len; AES_KEY aes_key; AES_set_encrypt_key(key, 128, &aes_key); AES_cbc_encrypt(data, encrypted_data, data_len, &aes_key, iv, AES_ENCRYPT); encrypted_len = data_len + AES_BLOCK_SIZE - (data_len % AES_BLOCK_SIZE); // 输出加密结果和向量 printf("encrypted data: %s\n", encrypted_data); printf("iv: %s\n", iv); ``` 3. 解密 使用 AES 解密算法对加密后的数据进行解密,还原原始数据。同样使用 CBC 模式进行解密: ```c // 解密 unsigned char *decrypted_data = (unsigned char *)malloc(encrypted_len); AES_set_decrypt_key(key, 128, &aes_key); AES_cbc_encrypt(encrypted_data, decrypted_data, encrypted_len, &aes_key, iv, AES_DECRYPT); // 输出解密结果 printf("decrypted data: %s\n", decrypted_data); ``` 需要注意的是,解密后的数据可能会包含填充字节,需要通过 padding 的方式去除。另外,可以使用 EVP 接口封装上述加解密过程,使代码更加简洁易用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

血_影

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值