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 ()