6.7. OpenSSL
OpenSSL 是最常用的加密库,提供 SSL/TLS 和加密算法支持。
6.7.1. 安装
# Ubuntu
sudo apt install libssl-dev
# macOS
brew install openssl
# 编译
g++ -lssl -lcrypto program.cpp
6.7.2. 初始化
#include <openssl/ssl.h>
#include <openssl/err.h>
// OpenSSL 1.1.0+ 自动初始化,但显式初始化更安全
void init_openssl() {
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
}
void cleanup_openssl() {
EVP_cleanup();
ERR_free_strings();
}
6.7.3. 哈希函数
#include <openssl/evp.h>
std::string sha256(const std::string& data) {
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr);
EVP_DigestUpdate(ctx, data.c_str(), data.size());
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int len;
EVP_DigestFinal_ex(ctx, hash, &len);
EVP_MD_CTX_free(ctx);
// 转换为十六进制字符串
std::stringstream ss;
for (unsigned int i = 0; i < len; ++i) {
ss << std::hex << std::setw(2) << std::setfill('0')
<< (int)hash[i];
}
return ss.str();
}
// 也支持 MD5, SHA1, SHA512 等
std::string md5(const std::string& data) {
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_md5(), nullptr);
// ... 同上
}
6.7.4. HMAC
#include <openssl/hmac.h>
std::string hmac_sha256(const std::string& key, const std::string& data) {
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int len;
HMAC(EVP_sha256(),
key.c_str(), key.size(),
(unsigned char*)data.c_str(), data.size(),
hash, &len);
std::stringstream ss;
for (unsigned int i = 0; i < len; ++i) {
ss << std::hex << std::setw(2) << std::setfill('0')
<< (int)hash[i];
}
return ss.str();
}
6.7.5. AES 加密
#include <openssl/evp.h>
#include <openssl/rand.h>
class AES256 {
public:
static std::vector<unsigned char> encrypt(
const std::string& plaintext,
const unsigned char* key,
const unsigned char* iv)
{
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv);
std::vector<unsigned char> ciphertext(
plaintext.size() + EVP_CIPHER_block_size(EVP_aes_256_cbc())
);
int len;
EVP_EncryptUpdate(ctx, ciphertext.data(), &len,
(unsigned char*)plaintext.c_str(),
plaintext.size());
int ciphertext_len = len;
EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len);
ciphertext_len += len;
ciphertext.resize(ciphertext_len);
EVP_CIPHER_CTX_free(ctx);
return ciphertext;
}
static std::string decrypt(
const std::vector<unsigned char>& ciphertext,
const unsigned char* key,
const unsigned char* iv)
{
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv);
std::vector<unsigned char> plaintext(ciphertext.size());
int len;
EVP_DecryptUpdate(ctx, plaintext.data(), &len,
ciphertext.data(), ciphertext.size());
int plaintext_len = len;
EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len);
plaintext_len += len;
EVP_CIPHER_CTX_free(ctx);
return std::string(plaintext.begin(),
plaintext.begin() + plaintext_len);
}
static void generate_key_iv(unsigned char* key, unsigned char* iv) {
RAND_bytes(key, 32); // 256 bits
RAND_bytes(iv, 16); // 128 bits
}
};
6.7.6. RSA 加密
#include <openssl/rsa.h>
#include <openssl/pem.h>
class RSACrypto {
public:
// 生成密钥对
static void generate_keys(const std::string& pub_file,
const std::string& priv_file) {
EVP_PKEY* pkey = EVP_PKEY_new();
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048);
EVP_PKEY_keygen(ctx, &pkey);
// 保存公钥
FILE* pub = fopen(pub_file.c_str(), "wb");
PEM_write_PUBKEY(pub, pkey);
fclose(pub);
// 保存私钥
FILE* priv = fopen(priv_file.c_str(), "wb");
PEM_write_PrivateKey(priv, pkey, nullptr, nullptr, 0, nullptr, nullptr);
fclose(priv);
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
}
// 公钥加密
static std::vector<unsigned char> encrypt(
const std::string& plaintext,
const std::string& pub_key_file)
{
FILE* f = fopen(pub_key_file.c_str(), "rb");
EVP_PKEY* pkey = PEM_read_PUBKEY(f, nullptr, nullptr, nullptr);
fclose(f);
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, nullptr);
EVP_PKEY_encrypt_init(ctx);
size_t outlen;
EVP_PKEY_encrypt(ctx, nullptr, &outlen,
(unsigned char*)plaintext.c_str(),
plaintext.size());
std::vector<unsigned char> ciphertext(outlen);
EVP_PKEY_encrypt(ctx, ciphertext.data(), &outlen,
(unsigned char*)plaintext.c_str(),
plaintext.size());
ciphertext.resize(outlen);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return ciphertext;
}
};
6.7.7. SSL/TLS 客户端
#include <openssl/ssl.h>
class SSLClient {
SSL_CTX* ctx_;
SSL* ssl_;
int sock_;
public:
SSLClient() {
ctx_ = SSL_CTX_new(TLS_client_method());
SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr);
SSL_CTX_set_default_verify_paths(ctx_);
}
~SSLClient() {
if (ssl_) SSL_free(ssl_);
if (ctx_) SSL_CTX_free(ctx_);
if (sock_ >= 0) close(sock_);
}
bool connect(const std::string& host, int port) {
// 创建 TCP 连接
sock_ = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
// 解析主机名...
if (::connect(sock_, (sockaddr*)&addr, sizeof(addr)) < 0) {
return false;
}
// 建立 SSL 连接
ssl_ = SSL_new(ctx_);
SSL_set_fd(ssl_, sock_);
SSL_set_tlsext_host_name(ssl_, host.c_str()); // SNI
return SSL_connect(ssl_) == 1;
}
int send(const std::string& data) {
return SSL_write(ssl_, data.c_str(), data.size());
}
std::string recv() {
char buffer[4096];
int n = SSL_read(ssl_, buffer, sizeof(buffer) - 1);
if (n > 0) {
buffer[n] = '\0';
return std::string(buffer);
}
return "";
}
};
6.7.8. Base64 编码
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
std::string base64_encode(const std::string& data) {
BIO* bio = BIO_new(BIO_s_mem());
BIO* b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bio = BIO_push(b64, bio);
BIO_write(bio, data.c_str(), data.size());
BIO_flush(bio);
BUF_MEM* buffer;
BIO_get_mem_ptr(bio, &buffer);
std::string result(buffer->data, buffer->length);
BIO_free_all(bio);
return result;
}
小技巧
OpenSSL 使用要点:
检查所有返回值和错误
正确释放资源
使用安全的随机数生成器
保持 OpenSSL 版本更新
生产环境验证证书