欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中如何實現(xiàn)SSL/TLS加密通信

 更新時間:2025年01月11日 09:47:42   作者:希望睿智的技術小屋  
在互聯(lián)網(wǎng)時代,確保信息傳輸過程中的機密性、完整性和可用性成為了開發(fā)者必須考慮的關鍵因素,在C++網(wǎng)絡編程中,使用SSL/TLS加密通信是一種常見的做法,它允許客戶端和服務器之間通過互聯(lián)網(wǎng)安全地交換信息,從而為網(wǎng)絡通信提供隱私性和數(shù)據(jù)完整性

概述

在互聯(lián)網(wǎng)時代,數(shù)據(jù)的安全性變得尤為重要。隨著網(wǎng)絡安全威脅的不斷增加,確保信息傳輸過程中的機密性、完整性和可用性成為了開發(fā)者必須考慮的關鍵因素。在C++網(wǎng)絡編程中,使用SSL/TLS加密通信是一種常見的做法。它允許客戶端和服務器之間通過互聯(lián)網(wǎng)安全地交換信息,從而為網(wǎng)絡通信提供隱私性和數(shù)據(jù)完整性。

SSL,英文全稱為Secure Sockets Layer,最初由Netscape公司在1990年代開發(fā),用于保護Web瀏覽器與服務器間的通信。TLS,英文全稱為Transport Layer Security,是IETF標準化后的版本,可以看作是SSL的繼承者。盡管名字不同,但兩者提供的功能非常相似,通常會把它們統(tǒng)稱為“SSL/TLS”。

C++網(wǎng)絡編程之SSL/TLS加密通信_網(wǎng)絡編程

基本概念

SSL/TLS:一種用于在兩個通信應用程序之間提供保密性和數(shù)據(jù)完整性的協(xié)議。

證書:一種數(shù)字文檔,包含了一個實體的信息及其公鑰。它由一個可信賴的第三方機構(CA,即Certificate Authority)簽發(fā),以證明該實體的身份。

公鑰/私鑰: 每個參與者都有一對密鑰,主要用于非對稱加密算法。公鑰公開給所有人,用于加密或驗證簽名。私鑰則保密保存,僅用于解密或創(chuàng)建簽名。這保證了即使數(shù)據(jù)被攔截,沒有私鑰也無法讀取其內(nèi)容。非對稱加密算法的安全性在于:計算上難以從公鑰推導出私鑰。常見的非對稱加密算法包括:RSA、ECC等。

會話密鑰:一旦客戶端與服務器建立了信任關系,就會生成一個臨時的對稱密鑰,來進行后續(xù)的數(shù)據(jù)加密和解密工作。對稱加密算法因為其加密解密速度快,在大量數(shù)據(jù)傳輸中非常有用。常用的對稱加密算法有:AES、DES等。

公鑰/私鑰與會話密鑰之間的主要關系在于:安全地建立對稱加密會話。具體來說,有如下兩個主要步驟。

1、使用非對稱加密來安全地交換會話密鑰。比如:小王可以使用小張的公鑰加密一個會話密鑰,并將它發(fā)送給小張;只有擁有相應私鑰的小張,才能解密該會話密鑰。

2、一旦會話密鑰被安全地交換,小王和小張就可以使用這個會話密鑰,并通過對稱加密算法來加密實際傳輸?shù)臄?shù)據(jù)。

API接口

OpenSSL是一個開源軟件包,提供了豐富的函數(shù)用于實現(xiàn)SSL/TLS加密通信,一些常用的API如下。

SSL_CTX_new:創(chuàng)建一個新的SSL上下文。

SSL_CTX_use_certificate_file:用于設置證書文件路徑。

SSL_CTX_use_PrivateKey_file:用于設置私鑰文件路徑。

SSL_new:根據(jù)給定的SSL上下文創(chuàng)建一個新的SSL結構體實例。

SSL_set_fd:將已有的socket描述符綁定至SSL對象上。

SSL_connect:客戶端調(diào)用此函數(shù)開始SSL握手過程。

SSL_accept:服務端調(diào)用此函數(shù)開始SSL握手過程。

SSL_read:用于讀取加密后的數(shù)據(jù)流。

SSL_write:用于寫入加密后的數(shù)據(jù)流。

SSL_shutdown:發(fā)起關閉SSL連接的過程。

使用OpenSSL庫進行SSL/TLS加密通信的主要步驟如下。

1、初始化OpenSSL庫。通常情況下,我們需要調(diào)用SSL_library_init等函數(shù)來初始化環(huán)境。

2、創(chuàng)建SSL上下文。使用SSL_CTX_new創(chuàng)建一個新的SSL_CTX對象,并配置相關的選項。比如:選擇使用的協(xié)議版本為TLSv1.2、TLSv1.3等。

3、加載證書文件。如果作為服務端運行,則需要加載自己的證書及私鑰。如果是客戶端,則可能需要指定CA證書列表,以驗證服務器的身份。

4、建立普通套接字連接。與普通的TCP/IP編程一樣,先完成兩臺機器之間的基本連接。

5、將普通套接字轉換成SSL套接字。通過SSL_set_fd函數(shù),關聯(lián)已有的Socket句柄與SSL結構體。

6、握手。雙方交換各自的信息,并協(xié)商加密算法、生成共享的密鑰等。這一過程,通過SSL_connect或SSL_accept函數(shù)完成。

7、數(shù)據(jù)傳輸。使用SSL_read和SSL_write代替標準的read和write操作,以確保所有發(fā)送和接收的數(shù)據(jù)都是加密的。

8、關閉連接。正常情況下,應先調(diào)用SSL_shutdown()進行優(yōu)雅斷開,之后再關閉底層socket。

在C++中如何進行SSL/TLS加密通信,可參考下面服務端的代碼。

#include <iostream>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstdlib>

using namespace std;

int main()
{
    if (OPENSSL_init_crypto(0, nullptr) != 1)
    {
        cout << "Failed to initialize OpenSSL crypto library." << endl;
        exit(EXIT_FAILURE);
    }

    if (OPENSSL_init_ssl(0, nullptr) != 1)
    {
        cout << "Failed to initialize OpenSSL SSL library." << endl;
        exit(EXIT_FAILURE);
    }

    // 使用最新的TLS版本
    const SSL_METHOD *method = TLS_server_method();
    SSL_CTX *ctx = SSL_CTX_new(method);
    if (ctx == nullptr)
    {
        ERR_print_errors_fp(stdout);
        exit(EXIT_FAILURE);
    }

    // 配置服務器證書
    if (SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stdout);
        exit(EXIT_FAILURE);
    }

    // 配置服務器私鑰
    if (SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stdout);
        exit(EXIT_FAILURE);
    }

    // 檢查私鑰是否匹配證書
    if (!SSL_CTX_check_private_key(ctx))
    {
        cout << "Private key does not match the certificate public key." << endl;
        exit(EXIT_FAILURE);
    }

    // 開啟監(jiān)聽
    int serverSock = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSock < 0)
    {
        cout << "Failed to create socket." << endl;
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(443);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(serverSock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
    {
        cout << "Failed to bind socket." << endl;
        exit(EXIT_FAILURE);
    }

    listen(serverSock, 5);
    while (true)
    {
        cout << "Wait client connecting..." << endl;

        struct sockaddr_in client_addr;
        socklen_t addr_len = sizeof(client_addr);
        int clientSock = accept(serverSock, (struct sockaddr*)&client_addr, &addr_len);

        SSL *pSsl = SSL_new(ctx);
        // 關聯(lián)已有的Socket句柄與SSL結構體
        SSL_set_fd(pSsl, clientSock);

        // 執(zhí)行握手
        if (SSL_accept(pSsl) <= 0)
        {
            ERR_print_errors_fp(stdout);
        }
        else
        {
            char pBuff[1024] = { 0 };
            int nBytesReceived = SSL_read(pSsl, pBuff, sizeof(pBuff) - 1);
            if (nBytesReceived > 0)
            {
                cout << "Received msg: " << pBuff << endl;

                // 向客戶端回傳消息
                string strRsp = "Hello from Hope Wisdom";
                SSL_write(pSsl, strRsp.c_str(), strRsp.size());
            }
        }

        SSL_free(pSsl);
        close(clientSock);
    }

    close(serverSock);
    SSL_CTX_free(ctx);
    return 0;
}

雙向認證

通常情況下,對于標準的HTTPS連接(比如:瀏覽器訪問一個安全網(wǎng)站),客戶端并不需要提供自己的證書或私鑰。服務器會向客戶端發(fā)送其證書,客戶端使用預置的信任根證書來驗證服務器的身份。

然而,在某些對安全性要求更高的場景下,比如:企業(yè)內(nèi)部網(wǎng)絡、金融交易系統(tǒng)等,服務器可能會要求客戶端也提供證書以證明自己的身份。這種機制,被稱為雙向認證。當客戶端也需要進行身份驗證時,除了要驗證服務器提供的證書外,還需要準備好自己的證書和私鑰,并將它們配置到SSL/TLS上下文中。

下面的示例代碼,演示了客戶端程序如何設置證書與私鑰來完成雙向認證。

#include <iostream>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;

int main() 
{
    if (OPENSSL_init_crypto(0, nullptr) != 1)
    {
        cout << "Failed to initialize OpenSSL crypto library." << endl;
        exit(EXIT_FAILURE);
    }

    if (OPENSSL_init_ssl(0, nullptr) != 1)
    {
        cout << "Failed to initialize OpenSSL SSL library." << endl;
        exit(EXIT_FAILURE);
    }

    // 使用最新的TLS版本
    const SSL_METHOD *method = TLS_client_method();
    SSL_CTX *ctx = SSL_CTX_new(method);
    if (ctx == NULL)
    {
        ERR_print_errors_fp(stdout);
        exit(EXIT_FAILURE);
    }

    // 配置客戶端證書
    if (SSL_CTX_use_certificate_file(ctx, "client.crt", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stdout);
        exit(EXIT_FAILURE);
    }

    // 配置客戶端私鑰
    if (SSL_CTX_use_PrivateKey_file(ctx, "client.key", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stdout);
        exit(EXIT_FAILURE);
    }

    // 創(chuàng)建socket
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        cout << "Failed to create socket." << endl;
        return -1;
    }

    // 設置服務器地址
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(443);
    // 假設服務器IP為本地回環(huán)地址
    inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

    // 連接到服務器
    if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
    {
        cout << "Failed to connect" << endl;
        close(sock);
        return -1;
    }

    SSL *pSsl = SSL_new(ctx);
    // 關聯(lián)已有的Socket句柄與SSL結構體
    SSL_set_fd(pSsl, sock);

    // 執(zhí)行握手
    if (SSL_connect(pSsl) <= 0)
    {
        ERR_print_errors_fp(stdout);
        goto end;
    }

    // 發(fā)送消息給服務器
    const char* pMsg = "Hi, Hope Wisdom";
    SSL_write(pSsl, pMsg, strlen(pMsg));

    // 接收響應
    char pBuff[1024] = {0};
    int nBytesReceived = SSL_read(pSsl, pBuff, sizeof(pBuff) - 1);
    if (nBytesReceived > 0)
    {
        cout << "Received msg: " << pBuff << endl;
    }
    else
    {
        cout << "Failed to receive msg" << endl;
    }

end:
    SSL_free(pSsl);
    close(sock);
    SSL_CTX_free(ctx);
    return 0;
}

在上面的示例代碼中,client.crt和client.key表示客戶端的證書和私鑰文件。這些文件必須預先生成好,并放置于程序可以訪問的位置。另外,還需要確保服務端已正確配置允許客戶端認證,并且加載了用于驗證客戶端證書的CA證書。

至于服務端如何配置,可參考下面的示例代碼。

// 設置驗證模式為需要客戶端證書
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);

// 加載CA證書
if (SSL_CTX_load_verify_locations(ctx, "ca.crt", nullptr) != 1)
{
    ERR_print_errors_fp(stdout);
    exit(EXIT_FAILURE);
}

在上面的示例代碼中,SSL_CTX_set_verify設置了客戶端驗證策略。我們設置了標志位SSL_VERIFY_PEERh和SSL_VERIFY_FAIL_IF_NO_PEER_CERT,這意味著服務端會強制要求客戶端提供證書。如果客戶端沒有提供證書,則握手失敗。SSL_CTX_load_verify_locations函數(shù)指定了一個或多個CA證書文件的位置,這些證書用于驗證客戶端提供的證書是否有效。如果沒有找到合適的CA證書來驗證客戶端證書,握手也會失敗。

總結

到此這篇關于C++中如何實現(xiàn)SSL/TLS加密通信的文章就介紹到這了,更多相關C++中SSL/TLS加密通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++實現(xiàn)簡單計算器

    C++實現(xiàn)簡單計算器

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡單計算器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • C語言實現(xiàn)制作通訊錄(新手推薦)

    C語言實現(xiàn)制作通訊錄(新手推薦)

    本文推薦給C語言學習到結構體的新手們,供其練習。這篇文章主要是利用C語言制作一個簡單的通訊錄功能,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-09-09
  • C語言實現(xiàn)通用數(shù)據(jù)結構之通用鏈表

    C語言實現(xiàn)通用數(shù)據(jù)結構之通用鏈表

    這篇文章主要為大家詳細介紹了c語言實現(xiàn)通用數(shù)據(jù)結構之通用鏈表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C++ 函數(shù)指針的實現(xiàn)

    C++ 函數(shù)指針的實現(xiàn)

    本文主要介紹了C++ 函數(shù)指針的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-02-02
  • C++中vector和數(shù)組之間的轉換及其效率問題詳解

    C++中vector和數(shù)組之間的轉換及其效率問題詳解

    c++?vector轉數(shù)組是一種將vector容器的元素轉換為數(shù)組的方法,主要能幫助提高程序的性能和效率,下面這篇文章主要給大家介紹了關于C++中vector和數(shù)組之間的轉換及其效率問題的相關資料,需要的朋友可以參考下
    2023-03-03
  • 淺談C++ IO流

    淺談C++ IO流

    這篇文章主要介紹了C++ IO流的相關資料,幫助大家更好的理解和學習c++,感興趣的朋友可以了解下
    2020-08-08
  • C++使用一棵紅黑樹同時封裝出map和set實例代碼

    C++使用一棵紅黑樹同時封裝出map和set實例代碼

    紅黑樹(Red?Black?Tre)是一種自平衡二叉查找樹,是在計算機科學中用到的一種數(shù)據(jù)結構,典型的用途是實現(xiàn)關聯(lián)數(shù)組,下面這篇文章主要給大家介紹了關于C++使用一棵紅黑樹同時封裝出map和set的相關資料,需要的朋友可以參考下
    2023-04-04
  • C++ 詳細講解對象的構造順序

    C++ 詳細講解對象的構造順序

    對象的構造往往和構造函數(shù)會牽扯在一起,構造函數(shù)的函數(shù)可能會由非常復雜的邏輯所組成,不同類的構造函數(shù)的程序邏輯很可能是相互依賴的,當這種相互依賴一旦成立,那么對象的構造順序很可能導致難以調(diào)試的Bug出現(xiàn)
    2022-04-04
  • 淺析C++中strlen函數(shù)的使用與模擬實現(xiàn)strlen的方法

    淺析C++中strlen函數(shù)的使用與模擬實現(xiàn)strlen的方法

    這篇文章主要介紹了strlen函數(shù)的使用與模擬實現(xiàn)strlen的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • C語言rand和srand函數(shù)使用方法介紹

    C語言rand和srand函數(shù)使用方法介紹

    rand()函數(shù)用來產(chǎn)生隨機數(shù),但是,rand()的內(nèi)部實現(xiàn)是用線性同余法實現(xiàn)的,是偽隨機數(shù),由于周期較長,因此在一定范圍內(nèi)可以看成是隨機的。srand()用來設置rand()產(chǎn)生隨機數(shù)時的隨機數(shù)種子。參數(shù)seed是整數(shù),通??梢岳胻ime(0)或geypid(0)的返回值作為seed
    2023-02-02

最新評論