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.rhkb.cn/news/473538.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据库】mysql数据库迁移前应如何备份数据?

MySQL 数据库的备份是确保数据安全的重要措施之一。在进行数据库迁移之前&#xff0c;备份现有数据可以防止数据丢失或损坏。以下是一套详细的 MySQL 数据库备份步骤&#xff0c;适用于大多数情况。请注意&#xff0c;具体的命令和工具可能因 MySQL 版本的不同而有所差异。整个…

mybatis 动态SQL语句

10. 动态SQL 10.1. 介绍 什么是动态SQL&#xff1a;动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句. 官网描述&#xff1a;MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验&#xff0c;你就能体会到根据不同条件拼接 SQL 语句的痛苦…

shell脚本_永久环境变量和字符串操作

一、永久环境变量 1. 常见的环境变量 2. 设置永久环境变量 3.1.将脚本加进PATH变量的目录中 3.2.添加进环境变量里 3.2.修改用户的 shell 配置文件 二、字符串操作 1. 字符串拼接 2. 字符串切片 3. 字符串查找 4. 字符串替换 5. 字符串大小写转换 6. 字符串分割 7…

【Go】-bufio库解读

目录 Reader和Writer接口 bufio.Reader/Writer 小结 其他函数-Peek、fill Reader小结 Writer Scanner结构体 缓冲区对于网络数据读写的重要性 Reader和Writer接口 在net/http包生成的Conn 接口的实例中有两个方法叫做Read和Write接口 type Conn interface {Read(b []b…

场景营销在企业定制开发 AI 智能名片 S2B2C 商城小程序中的应用与价值

摘要&#xff1a;本文深入剖析了品牌广告效果不佳与场景营销缺失之间的内在联系&#xff0c;阐述了场景营销对于品牌落地和转化的关键意义。同时&#xff0c;详细探讨了如何将场景营销理念与实践应用于企业定制开发的 AI 智能名片 S2B2C 商城小程序中&#xff0c;借助移动时代的…

uniapp 实现tabbar分类导航及滚动联动效果

思路&#xff1a;使用两个scroll-view&#xff0c;tabbar分类导航使用scrollleft移动&#xff0c;内容联动使用页面滚动onPageScroll监听滚动高度 效果图 <template><view class"content" ><view :class"[isSticky ? tab-sticky: ]">…

Flutter中的Material Theme完全指南:从入门到实战

Flutter作为一款热门的跨平台开发框架&#xff0c;其UI组件库Material Design深受开发者喜爱。本文将深入探讨Flutter Material Theme的使用&#xff0c;包括如何借助Material Theme Builder创建符合产品需求的主题风格。通过多个场景和代码实例&#xff0c;让你轻松掌握这一工…

aws中AcmClient.describeCertificate返回值中没有ResourceRecord

我有一个需求&#xff0c;就是让用户自己把自己的域名绑定我们的提供的AWS服务器。 AWS需要验证证书 上一篇文章中我用php的AcmClient中的requestCertificate方法申请到了证书。 $acmClient new AcmClient([region > us-east-1,version > 2015-12-08,credentials>[/…

Oracle 19c PDB克隆后出现Warning: PDB altered with errors受限模式处理

在进行一次19c PDB克隆过程中&#xff0c;发现克隆结束&#xff0c;在打开后出现了报错&#xff0c;PDB变成受限模式&#xff0c;以下是分析处理过程 09:25:48 SQL> alter pluggable database test1113 open instancesall; Warning: PDB altered with errors. Elapsed: 0…

【3D Slicer】的小白入门使用指南九

定量医学影像临床研究与实践 任务 定量成像教程 定量成像是从医学影像中提取定量测量的过程。 本教程基于两个定量成像的例子构建: - 形态学:缓慢生长肿瘤中的小体积变化 - 功能:鳞状细胞癌中的代谢活动 第1部分:使用变化跟踪模块测量脑膜瘤的小体积变化第2部分:使用PET标…

二、神经网络基础与搭建

神经网络基础 前言一、神经网络1.1 基本概念1.2 工作原理 二、激活函数2.1 sigmoid激活函数2.1.1 公式2.1.2 注意事项 2.2 tanh激活函数2.2.1 公式2.2.2 注意事项 2.3 ReLU激活函数2.3.1 公式2.3.2 注意事项 2.4 SoftMax激活函数2.4.1 公式2.4.2 Softmax的性质2.4.3 Softmax的应…

VMWare虚拟机安装华为欧拉系统

记录一下安装步骤&#xff1a; 1.在vmware中创建一个新的虚拟机&#xff0c;步骤和创建centos差不多 2.启动系统 具体的看下图&#xff1a; 启动虚拟机 耐心等待 等待进度条走完重启系统就完成了

如何进入python交互界面

Python交互模式有两种&#xff1a;图形化的交互模式或者命令行的交互模式。 打开步骤&#xff1a; 首先点击开始菜单。 然后在搜索栏中输入Python&#xff0c;即可看到图形化的交互模式&#xff08;IDLE&#xff08;Python 3.7 64-bit&#xff09;&#xff09;与命令行的交互…

NVR录像机汇聚管理EasyNVR多品牌NVR管理工具视频汇聚技术在智慧安防监控中的应用与优势

随着信息技术的快速发展和数字化时代的到来&#xff0c;安防监控领域也在不断进行技术创新和突破。NVR管理平台EasyNVR作为视频汇聚技术的领先者&#xff0c;凭借其强大的视频处理、汇聚与融合能力&#xff0c;展现出了在安防监控领域巨大的应用潜力和价值。本文将详细介绍Easy…

【STM32】USB 简要驱动软件架构图

STM32 USB 软件架构比较复杂&#xff0c;建议去看 UM 1734 或者 st wiki STM32 USB call graph STM32 USB Device Library files organization Reference [1]: https://wiki.stmicroelectronics.cn/stm32mcu/wiki/Introduction_to_USB_with_STM32 [2]: UM1734

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十三)图优化SLAM的本质

一、直白解释slam与图优化的结合 我从b站上学习理解的这个概念。 视频的大概位置是1个小时以后&#xff0c;在第75min到80min之间。图优化SLAM是怎么一回事。 slam本身是有运动方程的&#xff0c;也就是运动状态递推方程&#xff0c;也就是预测过程。通过t1时刻&#xff0c…

Vue2教程002:Vue指令

文章目录 2、Vue指令2.1 开发者工具2.2 v-html2.3 v-show和v-if2.4 v-else和v-else-if2.5 v-on2.5.1 内联语句2.5.2 methods 2、Vue指令 2.1 开发者工具 通过谷歌应用商店安装&#xff08;需要科学上网&#xff09;通过极简插件安装 2.2 v-html Vue会根据不同的指令&#x…

使用WebSocket技术实现Web应用中的实时数据更新

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用WebSocket技术实现Web应用中的实时数据更新 使用WebSocket技术实现Web应用中的实时数据更新 使用WebSocket技术实现Web应用中…

单片机学习笔记 1. 点亮一个LED灯

把基础的东西都过一下&#xff0c;用来学习记录一下。 目录 1、Keil工程 2、Keil实现代码 3、烧录程序 0、实现的功能 点亮一个LED灯 1、Keil工程 打开Keil&#xff0c;Project----New uVision Project&#xff0c;工程文件命名----OK 选择单片机类型AT89C52&#xff0c;和…

使用Web Animations API实现复杂的网页动画效果

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Animations API实现复杂的网页动画效果 使用Web Animations API实现复杂的网页动画效果 使用Web Animations API实现复杂…