C++网络编程之SSL/TLS加密通信

概述

        在互联网时代,数据的安全性变得尤为重要。随着网络安全威胁的不断增加,确保信息传输过程中的机密性、完整性和可用性成为了开发者必须考虑的关键因素。在C++网络编程中,使用SSL/TLS加密通信是一种常见的做法。它允许客户端和服务器之间通过互联网安全地交换信息,从而为网络通信提供隐私性和数据完整性。

        SSL,英文全称为Secure Sockets Layer,最初由Netscape公司在1990年代开发,用于保护Web浏览器与服务器间的通信。TLS,英文全称为Transport Layer Security,是IETF标准化后的版本,可以看作是SSL的继承者。尽管名字不同,但两者提供的功能非常相似,通常会把它们统称为“SSL/TLS”。

基本概念

        SSL/TLS:一种用于在两个通信应用程序之间提供保密性和数据完整性的协议。

        证书:一种数字文档,包含了一个实体的信息及其公钥。它由一个可信赖的第三方机构(CA,即Certificate Authority)签发,以证明该实体的身份。

        公钥/私钥: 每个参与者都有一对密钥,主要用于非对称加密算法。公钥公开给所有人,用于加密或验证签名。私钥则保密保存,仅用于解密或创建签名。这保证了即使数据被拦截,没有私钥也无法读取其内容。非对称加密算法的安全性在于:计算上难以从公钥推导出私钥。常见的非对称加密算法包括:RSA、ECC等。

        会话密钥:一旦客户端与服务器建立了信任关系,就会生成一个临时的对称密钥,来进行后续的数据加密和解密工作。对称加密算法因为其加密解密速度快,在大量数据传输中非常有用。常用的对称加密算法有:AES、DES等。

        公钥/私钥与会话密钥之间的主要关系在于:安全地建立对称加密会话。具体来说,有如下两个主要步骤。

        1、使用非对称加密来安全地交换会话密钥。比如:小王可以使用小张的公钥加密一个会话密钥,并将它发送给小张;只有拥有相应私钥的小张,才能解密该会话密钥。

        2、一旦会话密钥被安全地交换,小王和小张就可以使用这个会话密钥,并通过对称加密算法来加密实际传输的数据。

API接口

        OpenSSL是一个开源软件包,提供了丰富的函数用于实现SSL/TLS加密通信,一些常用的API如下。

        SSL_CTX_new:创建一个新的SSL上下文。

        SSL_CTX_use_certificate_file:用于设置证书文件路径。

        SSL_CTX_use_PrivateKey_file:用于设置私钥文件路径。

        SSL_new:根据给定的SSL上下文创建一个新的SSL结构体实例。

        SSL_set_fd:将已有的socket描述符绑定至SSL对象上。

        SSL_connect:客户端调用此函数开始SSL握手过程。

        SSL_accept:服务端调用此函数开始SSL握手过程。

        SSL_read:用于读取加密后的数据流。

        SSL_write:用于写入加密后的数据流。

        SSL_shutdown:发起关闭SSL连接的过程。

        使用OpenSSL库进行SSL/TLS加密通信的主要步骤如下。

        1、初始化OpenSSL库。通常情况下,我们需要调用SSL_library_init等函数来初始化环境。

        2、创建SSL上下文。使用SSL_CTX_new创建一个新的SSL_CTX对象,并配置相关的选项。比如:选择使用的协议版本为TLSv1.2、TLSv1.3等。

        3、加载证书文件。如果作为服务端运行,则需要加载自己的证书及私钥。如果是客户端,则可能需要指定CA证书列表,以验证服务器的身份。

        4、建立普通套接字连接。与普通的TCP/IP编程一样,先完成两台机器之间的基本连接。

        5、将普通套接字转换成SSL套接字。通过SSL_set_fd函数,关联已有的Socket句柄与SSL结构体。

        6、握手。双方交换各自的信息,并协商加密算法、生成共享的密钥等。这一过程,通过SSL_connect或SSL_accept函数完成。

        7、数据传输。使用SSL_read和SSL_write代替标准的read和write操作,以确保所有发送和接收的数据都是加密的。

        8、关闭连接。正常情况下,应先调用SSL_shutdown()进行优雅断开,之后再关闭底层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);}// 开启监听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);// 关联已有的Socket句柄与SSL结构体SSL_set_fd(pSsl, clientSock);// 执行握手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连接(比如:浏览器访问一个安全网站),客户端并不需要提供自己的证书或私钥。服务器会向客户端发送其证书,客户端使用预置的信任根证书来验证服务器的身份。

        然而,在某些对安全性要求更高的场景下,比如:企业内部网络、金融交易系统等,服务器可能会要求客户端也提供证书以证明自己的身份。这种机制,被称为双向认证。当客户端也需要进行身份验证时,除了要验证服务器提供的证书外,还需要准备好自己的证书和私钥,并将它们配置到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);}// 创建socketint 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为本地回环地址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);// 关联已有的Socket句柄与SSL结构体SSL_set_fd(pSsl, sock);// 执行握手if (SSL_connect(pSsl) <= 0){ERR_print_errors_fp(stdout);goto end;}// 发送消息给服务器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函数指定了一个或多个CA证书文件的位置,这些证书用于验证客户端提供的证书是否有效。如果没有找到合适的CA证书来验证客户端证书,握手也会失败。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/14676.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

深度图变换器的新突破:DeepGraph

人工智能咨询培训老师叶梓 转载标明出处 在图变换器领域&#xff0c;尽管其全局注意力机制在图结构数据处理上显示出了巨大潜力&#xff0c;但现有的图变换器模型却普遍较浅&#xff0c;通常不超过12层。这一现象引发了学者们对于“增加层数是否能进一步提升图变换器性能”的深…

单体架构 IM 系统之 Server 节点状态化分析

基于 http 短轮询模式的单体架构的 IM 系统见下图&#xff0c;即客户端通过 http 周期性地轮询访问 server 实现消息的即时通讯&#xff0c;也就是我们前面提到的 “信箱模型”。“信箱模型” 虽然实现非常容易&#xff0c;但是消息的实时性不高。 我们在上一篇文章&#xff08…

阿里云通义大模型团队开源Qwen2.5-Coder:AI编程新纪元

&#x1f680; 11月12日&#xff0c;阿里云通义大模型团队宣布开源通义千问代码模型全系列&#xff0c;共6款Qwen2.5-Coder模型。这些模型在同等尺寸下均取得了业界最佳效果&#xff0c;其中32B尺寸的旗舰代码模型在十余项基准评测中均取得开源最佳成绩&#xff0c;成为全球最强…

计算机网络(8)数据链路层之子层

上一篇已经讲到数据链路层可以分为两个子层&#xff0c;这次将重点讲解子层的作用和ppp协议 数据链路层的子层 数据链路层通常被分为两个子层&#xff1a; 逻辑链路控制子层&#xff08;LLC&#xff0c;Logical Link Control&#xff09;&#xff1a; LLC子层负责在数据链路…

【操作系统】输入/输出(I/O)管理

王道笔记 一、I/O管理描述 1.1 I/O设备的概念和分类 1.1.1 什么是I/O设备 “I/O”就是“输入/输出”&#xff08;Input/Output&#xff09; I/O设备机会可以将数据输入到计算机&#xff0c;或者可以接收计算机输出数据的外部设备&#xff0c;属于计算机中的硬件部件。下图就…

Day44 | 动态规划 :状态机DP 买卖股票的最佳时机IV买卖股票的最佳时机III309.买卖股票的最佳时机含冷冻期

Day44 | 动态规划 &#xff1a;状态机DP 买卖股票的最佳时机IV&&买卖股票的最佳时机III&&309.买卖股票的最佳时机含冷冻期 动态规划应该如何学习&#xff1f;-CSDN博客 本次题解参考自灵神的做法&#xff0c;大家也多多支持灵神的题解 买卖股票的最佳时机【…

Koa进阶:掌握中间件和参数校验的艺术

目录 一、首先下载依赖 二、在index.js中引入koa-parameter&#xff0c;一般挂载这个中间件时会放在注册请求体的后面 三、使用实例 四、如果跟我们所需求的参数不同&#xff0c;返回结果直接会返回422 koa-parameter一般是用来校验请求传过来的参数是否是自己所需要的的 G…

opencv(c++)----图像的读取以及显示

opencv(c)----图像的读取以及显示 imread: 作用&#xff1a;读取图像文件并将其加载到 Mat 对象中。参数&#xff1a; 第一个参数是文件路径&#xff0c;可以是相对路径或绝对路径。第二个参数是读取标志&#xff0c;比如 IMREAD_COLOR 表示以彩色模式读取图像。 返回值&#x…

git config是做什么的?

git config是做什么的&#xff1f; git config作用配置级别三种配置级别的介绍及使用&#xff0c;配置文件说明 使用说明git confi查看参数 默认/不使用这个参数 情况下 Git 使用哪个配置等级&#xff1f; 一些常见的行为查看配置信息设置配置信息删除配置信息 一些常用的配置信…

【计算机网络】【传输层】【习题】

计算机网络-传输层-习题 文章目录 10. 图 5-29 给出了 TCP 连接建立的三次握手与连接释放的四次握手过程。根据 TCP 协议的工作原理&#xff0c;请填写图 5-29 中 ①~⑧ 位置的序号值。答案技巧 注&#xff1a;本文基于《计算机网络》&#xff08;第5版&#xff09;吴功宜、吴英…

【二叉搜素树】——LeetCode二叉树问题集锦:6个实用题目和解题思路

文章目录 计算布尔二叉树的值求根节点到叶节点的数字之和二叉树剪枝验证二叉搜索树二叉搜索树中第K小的元素二叉树的所有路径 计算布尔二叉树的值 解题思路&#xff1a; 这是一个二叉树的布尔评估问题。树的每个节点包含一个值&#xff0c;其中叶子节点值为 0 或 1&#xff0…

2023年MathorCup数学建模A题量子计算机在信用评分卡组合优化中的应用解题全过程文档加程序

2023年第十三届MathorCup高校数学建模挑战赛 A题 量子计算机在信用评分卡组合优化中的应用 原题再现&#xff1a; 在银行信用卡或相关的贷款等业务中&#xff0c;对客户授信之前&#xff0c;需要先通过各种审核规则对客户的信用等级进行评定&#xff0c;通过评定后的客户才能…

嵌入式开发套件(golang版本)

1. watchdog&#xff08;软件看门狗&#xff1a;守护升级&#xff09; 2. gate&#xff08;主程序&#xff09; 3. web&#xff08;api版本 升级包&#xff09; OTA 升级流程 watchdog启动后检查守护进程gate是否正在运行&#xff0c;如果没有&#xff0c;api对比版本号&am…

解压专家 2.4.12| 多功能解压缩工具,支持密码共享、音乐播放和歌词匹配。

解压专家是一款功能强大的解压缩软件&#xff0c;提供了类似于WIFI万能钥匙的密码分享功能&#xff0c;帮助用户快速获取共享的解压密码。作为专业的解压缩工具&#xff0c;它支持多种常见和不常见的压缩包格式&#xff0c;如ZIP、RAR、7z、TAR.GZ和ISO等&#xff0c;并且还支持…

并发编程(10)——内存模型和原子操作

文章目录 十、day101. 内存模型基础1.1 对象和内存区域1.2 改动序列 2. 原子操作及其类型2.1 原子操作2.2 原子类型2.3 内存次序2.4 std::atomic_flag2.4.1 自旋锁 2.5 std::atomic&#xff1c;bool&#xff1e;2.6 std::atomic<T*>2.7 标准整数原子类型2.8 std::atomic&…

【Flink】-- flink新版本发布:v2.0-preview1

目录 1、简介 2、非兼容变更 2.1、API 2.2、连接器适配计划 2.3、配置 2.4、其它 3、重要新特性 3.1、存算分离状态管理 3.2、物化表 3.3、批作业的自适应执行 3.4、流式湖仓 4、附加 4.1、非兼容性的 api 程序变更 4.1.2、Removed Classes # 4.1.3、Modified Cl…

ffmpeg+D3D实现的MFC音视频播放器,支持录像、截图、音视频播放、码流信息显示等功能

一、简介 本播放器是在vs2019下开发&#xff0c;通过ffmpeg实现拉流解码功能&#xff0c;通过D3D实现视频的渲染功能。截图功能采用libjpeg实现&#xff0c;可以截取jpg图片&#xff0c;图片的默认保存路径是在C:\MYRecPath中。录像功能采用封装好的类Mp4Record实现&#xff0c…

webpack指南

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;webpack篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来webpack篇专栏内容:webpack-指南 概念 中文&#xff1a; webpack | webpack中文文档 | webpack中文网 英文&…

把越南语翻译成中文一般用什么翻译工具?《越南语翻译通》App或许能满足你的技术痛点需求!

在多语言交流日益频繁的今天&#xff0c;掌握越南语对于商务、旅游或学术交流都是一项重要技能。《越南语翻译通》App应运而生&#xff0c;旨在通过技术手段简化越南语学习和翻译过程&#xff0c;满足用户在不同场景下的需求。 核心技术 《越南语翻译通》App采用了先进的自然语…

Android Framework AMS(16)进程管理

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读AMS 进程方面的知识。关注思维导图中左上侧部分即可。 我们本章节主要是对Android进程管理相关知识有一个基本的了解。先来了解下L…