20.7 OpenSSL 套接字SSL加密传输

OpenSSL 中的 SSL 加密是通过 SSL/TLS 协议来实现的。SSL/TLS 是一种安全通信协议,可以保障通信双方之间的通信安全性和数据完整性。在 SSL/TLS 协议中,加密算法是其中最核心的组成部分之一,SSL可以使用各类加密算法进行密钥协商,一般来说会使用RSA等加密算法,使用TLS加密针对服务端来说则需要同时载入公钥与私钥文件,当传输被建立后客户端会自行下载公钥并与服务端完成握手,读者可将这个流程理解为上一章中RSA的分发密钥环节,只是SSL将这个过程简化了,当使用时无需关注传输密钥对的问题。

与RSA实现加密传输一致,使用SSL实现加密传输读者同样需要自行生成对应的密钥对,密钥对的生成可以使用如下命令实现;

  • 生成私钥: openssl genrsa -out privkey.pem 2048
  • 生成公钥: openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095

执行如上两条命令,读者可得到两个文件首先生成2048位的privkey.pem也就是私钥,接着利用私钥文件生成cacert.pem证书文件,该文件的有效期为1095天也就是三年,当然此处由于是测试可以使用自定义生成,如果在实际环境中还是需要购买正规签名来使用的。

服务端实现代码与原生套接字通信保持高度一致,在连接方式上同样采用了标准API实现,唯一的不同在于当accept函数接收到用于请求时,我们需要通过SSL_new产生一个SSL对象,当需要发送数据时使用SSL_write,而当需要接收数据时则使用SSL_read函数,通过使用这两个函数即可保证中间的传输流程是安全的,其他流程与标准套接字编程保持一致,如下是服务端完整代码实现。

#include <WinSock2.h>
#include <iostream>
#include <string.h>
#include <errno.h>
#include <stdlib.h>#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>extern "C"
{
#include <openssl/applink.c>
}#pragma comment(lib, "WS2_32.lib")
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")#define MAXBUF 1024int main(int argc, char** argv)
{SOCKET sockfd, new_fd;struct sockaddr_in socket_ptr, their_addr;char buf[MAXBUF + 1] = {0};SSL_CTX* ctx;// SSL库初始化SSL_library_init();// 载入所有SSL算法OpenSSL_add_all_algorithms();// 载入所有SSL错误消息SSL_load_error_strings();// 以SSLV2和V3标准兼容方式产生一个SSL_CTX即SSLContentTextctx = SSL_CTX_new(SSLv23_server_method());if (ctx == NULL){std::cout << "[-] 产生CTX上下文对象错误" << std::endl;return 0;}else{std::cout << "[+] 产生CTX上下文对象" << std::endl;}// 载入用户的数字证书,此证书用来发送给客户端,证书里包含有公钥if (SSL_CTX_use_certificate_file(ctx, "d://cacert.pem", SSL_FILETYPE_PEM) <= 0){std::cout << "[-] 载入公钥失败" << std::endl;return 0;}else{std::cout << "[+] 已载入公钥" << std::endl;}// 载入用户私钥if (SSL_CTX_use_PrivateKey_file(ctx, "d://privkey.pem", SSL_FILETYPE_PEM) <= 0){std::cout << "[-] 载入私钥失败" << std::endl;return 0;}else{std::cout << "[+] 已载入私钥" << std::endl;}// 检查用户私钥是否正确if (!SSL_CTX_check_private_key(ctx)){std::cout << "[-] 用户私钥错误" << std::endl;return 0;}// 开启Socket监听WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){WSACleanup();return 0;}// 创建套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){return 0;}socket_ptr.sin_family = AF_INET;socket_ptr.sin_addr.s_addr = htonl(INADDR_ANY);socket_ptr.sin_port = htons(9999);// 绑定套接字if (bind(sockfd, (struct sockaddr*)&socket_ptr, sizeof(struct sockaddr)) == -1){return 0;}if (listen(sockfd, 10) == -1){return 0;}while (1){SSL* ssl;int len = sizeof(struct sockaddr);// 等待客户端连接if ((new_fd = accept(sockfd, (struct sockaddr*)&their_addr, &len)) != -1){printf("客户端地址: %s --> 端口: %d --> 套接字: %d \n", inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);}// 基于ctx产生一个新的SSLssl = SSL_new(ctx);// 将连接用户的socket加入到SSLSSL_set_fd(ssl, new_fd);// 建立SSL连接if (SSL_accept(ssl) == -1){closesocket(new_fd);break;}// 开始处理每个新连接上的数据收发memset(buf, 0, MAXBUF);strcpy(buf, "[服务端消息] hello lyshark");// 发消息给客户端len = SSL_write(ssl, buf, strlen(buf));if (len <= 0){goto finish;return 0;}memset(buf, 0, MAXBUF);// 接收客户端的消息len = SSL_read(ssl, buf, MAXBUF);if (len > 0){printf("[接收到客户端消息] => %s \n", buf);}// 关闭套接字连接finish:SSL_shutdown(ssl);SSL_free(ssl);closesocket(new_fd);}closesocket(sockfd);WSACleanup();SSL_CTX_free(ctx);system("pause");return 0;
}

客户端实现代码同样与原生套接字编程保持一致,如下是完整代码,读者可以发现当使用connect连接到服务端后,依然调用了SSL_connect函数,此处的函数功能是在服务端下载证书信息,并完成证书通信验证,当验证实现后,则读者就可以向原生套接字那样去操作数据包的流向了。

#include <WinSock2.h>
#include <iostream>
#include <string.h>
#include <errno.h>
#include <stdlib.h>#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>extern "C"
{
#include <openssl/applink.c>
}#pragma comment(lib, "WS2_32.lib")
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")#define MAXBUF 1024void ShowCerts(SSL* ssl)
{X509* cert;char* line;cert = SSL_get_peer_certificate(ssl);if (cert != NULL){line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);printf("[+] 证书: %s \n", line);free(line);line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);printf("[+] 颁发者: %s \n", line);free(line);X509_free(cert);}else{printf("[-] 无证书信息 \n");}
}int main(int argc, char** argv)
{int sockfd, len;struct sockaddr_in dest;char buffer[MAXBUF + 1] = { 0 };SSL_CTX* ctx;SSL* ssl;// SSL库初始化SSL_library_init();OpenSSL_add_all_algorithms();SSL_load_error_strings();// 建立CTX上下文ctx = SSL_CTX_new(SSLv23_client_method());if (ctx == NULL){WSACleanup();return 0;}// 创建SocketWSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){WSACleanup();return 0;}if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){WSACleanup();return 0;}// 初始化服务器端(对方)的地址和端口信息dest.sin_family = AF_INET;dest.sin_addr.s_addr = inet_addr("127.0.0.1");dest.sin_port = htons(9999);// 连接服务器if (connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0){WSACleanup();return 0;}// 基于ctx产生一个新的SSLssl = SSL_new(ctx);SSL_set_fd(ssl, sockfd);// 建立 SSL 连接if (SSL_connect(ssl) != -1){printf("[+] SSL连接类型: %s \n", SSL_get_cipher(ssl));ShowCerts(ssl);}//接收服务器来的消息 最多接收MAXBUF字节len = SSL_read(ssl, buffer, MAXBUF);if (len > 0){printf("接收消息: %s --> 共 %d 字节 \n", buffer, len);}else{goto finish;}memset(buffer, 0, MAXBUF);strcpy(buffer, "[客户端消息] hello Shark");// 发消息给服务器len = SSL_write(ssl, buffer, strlen(buffer));if (len > 0){printf("[+] 发送成功 \n");}finish:// 关闭连接SSL_shutdown(ssl);SSL_free(ssl);closesocket(sockfd);SSL_CTX_free(ctx);system("pause");return 0;
}

至此读者可以分别编译服务端与客户端程序,并首先运行服务端侦听套接字,接着运行客户端,此时即可看到如下图所示的通信流程,至此两者的通信数据包将被加密传输,从而保证了数据的安全性。

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

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

相关文章

web3 dapp React项目引入 antd 对 balance 用户token信息组件进行样式改造

好 上文 web3 React dapp中编写balance组件从redux取出并展示用户资产 我们简单处理了用户资产的展示 那么 我们继续 先启动 ganache 环境 终端输入 ganache -d然后 打开我们的项目 将合约发布到区块链上 truffle migrate --reset然后 我们启动项目 确认一切正常 还原到上文…

k8s中实现mysql主备

文章目录 一、k8s中实现mysql主备1.1 环境信息1.2 部署nfs-provisioner1.2.1 安装nfs1.2.2 部署nfs-provisioner 1.3 安装mysql1.4 备库上查看是否同步 一、k8s中实现mysql主备 1.1 环境信息 机器操作系统ipmysql版本k8s版本storageClassmaster1CentOS7.8192.168.0.20mysql5.…

C++ 代码实例:多项式除法简单计算工具

文章目录 前言代码仓库代码说明核心片段 结果总结参考资料作者的话 前言 C 代码实例&#xff1a;多项式除法简单计算工具。 代码仓库 yezhening/Programming-examples: 编程实例 (github.com)Programming-examples: 编程实例 (gitee.com) 代码 说明 由于代码篇幅较多&#…

【蓝桥杯省赛真题41】Scratch电脑开关机 蓝桥杯少儿编程scratch图形化编程 蓝桥杯省赛真题讲解

目录 scratch电脑开关机 一、题目要求 编程实现 二、案例分析 1、角色分析

【数据开发】大数据平台架构,Hive / THive介绍

1、大数据引擎 大数据引擎是用于处理大规模数据的软件系统&#xff0c; 常用的大数据引擎包括Hadoop、Spark、Hive、Pig、Flink、Storm等。 其中&#xff0c;Hive是一种基于Hadoop的数据仓库工具&#xff0c;可以将结构化的数据映射到Hadoop的分布式文件系统上&#xff0c;并提…

家用电脑做服务器,本地服务器搭建,公网IP申请,路由器改桥接模式,拨号上网

先浇一盆冷水&#xff01; 我不知道其他运营商是什么情况。联通的运营商公网IP端口 80、8080、443 都会被屏蔽掉&#xff0c;想要开放必须企业备案&#xff08;个人不行&#xff09;才可以。也就是说&#xff0c;只能通过其他端口进行showtime了。 需要哪些东西&#xff1f; 申…

MySQL中的刷脏机制详解

名词解释 脏页&#xff1a;当内存数据页跟磁盘数据页内容不一致的时候&#xff0c;我们称这个内存页为“脏页”。 干净页&#xff1a;内存数据写入到磁盘后&#xff0c;内存和磁盘上的数据页的内容就一致了&#xff0c;称为“干净页”。 LSN&#xff1a;称为日志的逻辑序列号(l…

HTB——introduction to active directory

文章目录 一、Active directory structure二、Active Directory Terminology 一、Active directory structure Active Directory &#xff08;AD&#xff09; 是用于 Windows 网络环境的目录服务。它是一种分布式分层结构&#xff0c;允许集中管理组织的资源&#xff0c;包括用…

MIPI-CSI-2 RAW10笔记

好文&#xff1a; 【精选】摄像头的MIPI接口、DVP接口和CSI接口-CSDN博客【精选】摄像头的MIPI接口、DVP接口和CSI接口-CSDN博客 (56 封私信 / 24 条消息) 显示器的 VGA、HDMI、DVI 和 DisplayPort 接口有什么区别&#xff1f; - 知乎 (zhihu.com) 嵌入式工程师必备&#x…

基于白鲸算法的无人机航迹规划-附代码

基于白鲸算法的无人机航迹规划 文章目录 基于白鲸算法的无人机航迹规划1.白鲸搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用白鲸算法来优化无人机航迹规划。 1.白鲸搜索算法 …

内核态内存映射

内核态的内存映射机制&#xff0c;主要包含以下几个部分&#xff1a; 内核态内存映射函数 vmalloc、kmap_atomic 是如何工作的&#xff1b;内核态页表是放在哪里的&#xff0c;如何工作的&#xff1f;swapper_pg_dir 是怎么回事&#xff1b;出现了内核态缺页异常应该怎么办&am…

什么是智慧工地?

智慧工地将更多人工智能、传感技术、虚拟现实等高科技技术植入到建筑、机械、人员穿戴设施、场地进出关口等各类物体中&#xff0c;并且被普遍互联&#xff0c;形成“物联网”&#xff0c;再与“互联网”整合在一起&#xff0c;实现工程管理干系人与工程施工现场的整合。智慧工…

火山引擎云原生存储加速实践

在火山引擎相关的业务中绝大部分的机器学习和数据湖的算力都运行在云原生 K8s 平台上。云原生架构下存算分离和弹性伸缩的计算场景&#xff0c;极大的推动了存储加速这个领域的发展&#xff0c;目前业界也衍生出了多种存储加速服务。但是面对计算和客户场景的多样性&#xff0c…

CSS 滚动捕获 Scroll Snap

CSS 滚动捕获 Scroll Snap CSS 滚动捕获允许开发者通过声明一些位置(或叫作捕获位置)来创建精准控制的滚动体验. 通常来说轮播图就是这种体验的例子, 在轮播图中, 用户只能停在图 A 或者图 B, 而不能停在 A 和 B 的中间. 比如平时用淘宝或小红书, 当你上滑到下一个推荐内容时…

wpf Grid布局详解 `Auto` 和 `*` 是两种常见的设置方式 行或列占多个单元格,有点像excel里的合并单元格。使其余的列平均分配剩余的空间

比如只有行的界面 <Window x:Class"GenerateTokenApp.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/exp…

YOLO目标检测——红绿灯检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;红绿灯检测数据集在自动驾驶、交通安全监控、智能交通系统、交通流量监测和驾驶员辅助系统等领域都有广泛应用的潜力数据集说明&#xff1a;红绿灯检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;含有国内红绿灯…

Zeus IoT : 基于 SpringBoot 的分布式开源物联网大数据平台

Zeus IoT 是一个集设备数据采集、存储、分析、观测为一体的开源物联网平台&#xff0c;全球首创基于 Zabbix 的物联网分布式数据采集架构&#xff0c;具备超百万级物联网设备的并发监控能力&#xff0c;真正具备工业级性能与稳定性的开源物联网大数据中台。 Zeus IoT 致力于让设…

快速实现一个企业级域名 SSL 证书有效期监控巡检系统

Why 现在对于企业来说&#xff0c;HTTPS 已经不是可选项&#xff0c;已经成为一个必选项。HTTPS 协议采用 SSL 协议&#xff0c;采用公开密钥的技术&#xff0c;提供了一套 TCP/IP 传输层数据加密的机制。SSL 证书是一种遵守 SSL 协议的服务器数字证书&#xff0c;一般是由权威…

Rust编程基础核心之所有权(下)

1.变量与数据交互方式之二: 克隆 在上一节中, 我们讨论了变量与数据交互的第一种方式: 移动, 本节将介绍第二种方式:克隆。 如果我们 确实 需要深度复制 String 中堆上的数据&#xff0c;而不仅仅是栈上的数据&#xff0c;可以使用一个叫做 clone 的通用函数。 看下面的代码…

Mac苹果电脑分辨率修改管理 安装SwitchResX 完美解决

SwitchResX for Mac是一款Mac应用程序&#xff0c;可帮助您更好地管理和控制显示器分辨率和其他显示设置。使用SwitchResX&#xff0c;您可以创建自定义分辨率、旋转屏幕、调整显示器色彩配置等。 1. 自定义分辨率&#xff1a;SwitchResX允许用户创建自定义的屏幕分辨率&#…