https://blog.csdn.net/2501_93895958/article/details/153705571

从零开始:C++实现SSL/TLS加密通信的完整教程
在本教程中,我将一步步引导你从零开始,使用C++实现基于SSL/TLS协议的加密通信。SSL/TLS(安全套接字层/传输层安全)是保护网络通信的核心技术,广泛用于HTTPS、邮件传输等场景。我们将使用OpenSSL库(一个开源、跨平台的SSL/TLS实现),因为它功能强大且易于集成到C++中。教程分为以下步骤:环境准备、基本概念、代码实现、编译运行、测试验证和注意事项。所有代码均使用C++编写,并确保可运行。

步骤1: 环境准备
在开始编码前,你需要安装OpenSSL库和C++编译器(如GCC或Clang)。以下是常见系统的安装方法:

Windows:下载OpenSSL二进制文件(例如从官方站点),并设置环境变量。建议使用MinGW或MSVC编译器。
Linux(如Ubuntu):运行命令:

sudo apt-get update
sudo apt-get install libssl-dev g++

macOS:使用Homebrew安装:

brew install openssl
export PATH="/usr/local/opt/openssl/bin:$PATH"  # 添加到环境变量

验证安装:运行openssl version,应显示版本号(如OpenSSL 3.0.x)。

步骤2: 基本概念
SSL/TLS通过非对称加密(如RSA)和对称加密(如AES)确保通信安全。核心概念包括:

证书和密钥:服务器需要证书(由CA颁发或自签名)和私钥。客户端验证证书真伪。
握手过程:通信开始时,双方交换密钥并协商加密算法。例如,RSA加密中,公钥加密数据$c = m^e \mod n$,私钥解密$m = c^d \mod n$,其中$e$和$d$是指数。
会话密钥:握手后生成对称密钥,用于高效加密数据流。 这些概念在代码中通过OpenSSL API实现。接下来,我们将编写服务器端和客户端代码。
步骤3: 代码实现
我们将创建两个C++文件:server.cpp(服务器)和client.cpp(客户端)。代码使用OpenSSL函数,包括初始化上下文、加载证书、建立连接和加密通信。

服务器端代码 (server.cpp)
服务器监听端口,接受客户端连接并进行TLS握手。
 

#include <iostream>
#include <string>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
 
// 初始化SSL上下文
SSL_CTX* initServerCTX() {
    const SSL_METHOD *method = TLS_server_method();  // 使用TLS方法
    SSL_CTX *ctx = SSL_CTX_new(method);
    if (!ctx) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    // 加载服务器证书和私钥(假设文件名为server.crt和server.key)
    if (SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    if (SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    return ctx;
}
 
// 创建TCP socket并绑定端口
int createSocket(int port) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(sockfd, 5) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }
    return sockfd;
}
 
int main() {
    // 初始化OpenSSL库
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
 
    SSL_CTX *ctx = initServerCTX();
    int sockfd = createSocket(4433);  // 监听端口4433
 
    std::cout << "Server running on port 4433...\n";
    while (true) {
        struct sockaddr_in client_addr;
        socklen_t len = sizeof(client_addr);
        int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &len);
        if (clientfd < 0) {
            perror("Accept failed");
            continue;
        }
 
        // 创建SSL对象并进行握手
        SSL *ssl = SSL_new(ctx);
        SSL_set_fd(ssl, clientfd);
        if (SSL_accept(ssl) <= 0) {
            ERR_print_errors_fp(stderr);
        } else {
            char client_ip[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
            std::cout << "Connection from " << client_ip << ", SSL handshake successful.\n";
 
            // 发送加密消息
            const char *msg = "Hello from server! This is encrypted.";
            SSL_write(ssl, msg, strlen(msg));
 
            // 接收客户端消息
            char buf[1024];
            int bytes = SSL_read(ssl, buf, sizeof(buf));
            buf[bytes] = '\0';
            std::cout << "Received: " << buf << "\n";
        }
        SSL_free(ssl);
        close(clientfd);
    }
    SSL_CTX_free(ctx);
    close(sockfd);
    return 0;
}

客户端代码 (client.cpp)

客户端连接到服务器,执行TLS握手并交换加密数据。

#include <iostream>
#include <string>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
 
// 初始化SSL上下文
SSL_CTX* initClientCTX() {
    const SSL_METHOD *method = TLS_client_method();  // 使用TLS方法
    SSL_CTX *ctx = SSL_CTX_new(method);
    if (!ctx) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    // 可选:加载CA证书以验证服务器(假设文件名为ca.crt)
    if (SSL_CTX_load_verify_locations(ctx, "ca.crt", nullptr) != 1) {
        std::cerr << "Error loading CA certificate. Using insecure mode.\n";
    }
    return ctx;
}
 
// 连接到服务器
int connectToServer(const char *ip, int port) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip);
    if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Connection failed");
        exit(EXIT_FAILURE);
    }
    return sockfd;
}
 
int main() {
    // 初始化OpenSSL库
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
 
    SSL_CTX *ctx = initClientCTX();
    int sockfd = connectToServer("127.0.0.1", 4433);  // 连接到本地服务器
 
    // 创建SSL对象并进行握手
    SSL *ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);
    if (SSL_connect(ssl) <= 0) {
        ERR_print_errors_fp(stderr);
    } else {
        std::cout << "Connected to server, SSL handshake successful.\n";
 
        // 接收服务器消息
        char buf[1024];
        int bytes = SSL_read(ssl, buf, sizeof(buf));
        buf[bytes] = '\0';
        std::cout << "Received: " << buf << "\n";
 
        // 发送加密消息
        const char *msg = "Hello from client! Data is secure.";
        SSL_write(ssl, msg, strlen(msg));
    }
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
    return 0;
}
步骤4: 编译和运行

编译代码需要链接OpenSSL库。以下是编译命令(在Linux/macOS终端运行):

# 生成服务器端可执行文件
g++ -o server server.cpp -lssl -lcrypto
# 生成客户端可执行文件
g++ -o client client.cpp -lssl -lcrypto

在Windows上,使用MinGW或MSVC类似命令,并确保链接libssl.liblibcrypto.lib

运行步骤:

  1. 生成测试证书:在代码目录下,创建自签名证书(用于测试):

​# 生成私钥
openssl genpkey -algorithm RSA -out server.key
# 生成证书签名请求(CSR)
openssl req -new -key server.key -out server.csr
# 自签名证书(有效期365天)
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# 可选:生成CA证书(用于客户端验证)
openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 365

​

server.crtserver.keyca.crt放在代码目录。

注意:

1 要在服务端的主机上生成 ca.crt(客户端CA证书) ,然后发给客户端使用;

2 生成客户端CA证书时,需在证书请求(CSR)阶段输入服务器的域名(这里输入服务器的主机名或IP地址),以确保证书与目标服务器匹配。

2. 启动服务器

./server

服务器开始监听端口4433。

3. 启动客户端:

./client

客户端连接到服务器,进行TLS握手并交换消息。

步骤5: 测试和验证
正常测试:运行客户端和服务器后,控制台输出握手成功消息和加密数据。例如:

  • 服务器端:Connection from 127.0.0.1, SSL handshake successful.
  • 客户端:Connected to server, SSL handshake successful.

安全验证:

  • 使用Wireshark抓包工具检查流量,应看到加密数据(如TLS记录层)。
  • 如果加载了CA证书,客户端会验证服务器证书;否则,输出警告(测试时可忽略)。

错误处理:故意修改证书文件路径,观察OpenSSL错误输出(如ERR_print_errors_fp)。
步骤6: 注意事项

  • 证书管理:在生产环境中,使用权威CA签名的证书(如Let's Encrypt),避免自签名证书的安全风险。
  • 性能优化:对于高并发场景,使用异步I/O(如Boost.Asio集成OpenSSL)。
  • 安全最佳实践:

             定期更新OpenSSL库,防止漏洞(如Heartbleed)。

             使用强加密算法(如TLS 1.3),避免过时协议(如SSLv3)。

             在代码中处理所有错误,防止崩溃或信息泄露。

  • 扩展性:本教程是基础实现,你可以添加功能如双向认证(客户端也提供证书)、会话重用等。

        通过以上步骤,你已经实现了一个完整的C++ SSL/TLS加密通信系统。如果有问题,欢迎基于代码调试或查阅OpenSSL文档。记住,安全通信是动态过程,始终保持库和证书更新!
 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐