Linxu下c语言实现socket+openssl数据传输加密

文章目录

  • 1. Socket连接建立流程
  • 2、Socket+SSL的初始化流程
  • 3、初始化SSL环境,证书和密钥
  • 4、Socket+SSL 的c语言实现
    • 4.1 编写SSL连接函数
    • 4.2 编写加密服务端server.c
    • 4.3 编写加密客户端client.c
  • 5、使用tcpdump检验
    • 源码获取

在进行网络编程的时候,我们通常使用socket进行数据的传输。然而socket作为一个数据传输协议,其本身对数据并不会作加密。所以数据传输的过程可以很轻松地被监听并截获到传输的数据。openssl提供了SSL的加密库,通过ssl+socket的方式可以保证连接安全和数据的加密。

1. Socket连接建立流程

在做socket加密之前,还是先与普通的socket做一个对比。

Client Server connect() accept() send(data) recv(data) send(response) recv(response) close() close() Client Server

上面的是我们通常在做一个socket连接的时候会涉及到的握手过程。服务端会通过accept去接收客户端的请求。客户端通过connect去连接到客户端。使用sendrecv去做数据的传输。那么传输过程中的参数data也就是我们交互的数据了。当我们建立连接开始发送数据的时候。使用一些抓包工具wireshark,或者tcpdump去监听socket端口就能很轻松地获取到传输的明文数据了。

2、Socket+SSL的初始化流程

所以为了避免数据的监听,我们就需要使用SSL去建立一个安全的通道。这里我们先把SSL的建立当作一个子流程

Client Server conn_fd=connect() accept_fd=accept() SSL Sub-Process Begins Initialize SSL Environment(准备证书,私钥) Initialize SSL Environment(准备证书,私钥) Create new SSL session (绑定conn_fd) Create new SSL session (绑定accept_fd) SSL_connect() (传入证书,私钥,和conn_fd进行握手) SSL_accept() (传入证书,私钥,和accept_fd进行握手) SSL Sub-Process Ends SSL_write(data) SSL_read(data) SSL_write(response) SSL_read(response) SSL Shutdown Sub-Process Begins SSL_shutdown() SSL_shutdown() SSL Shutdown Sub-Process Ends close() close() Client Server

SSL子过程主要插入在socket的connect()/accept()和数据交换之间。通过SSL建立完成的所以,一旦SSL握手完成,数据发送和接收的流程与普通的socket通信非常相似,只需要使用SSL_write()和SSL_read()来代替send()和recv()。c

替换 send()SSL_write(ssl, buffer, length)
替换recv()SSL_read(ssl, buffer, length)

3、初始化SSL环境,证书和密钥

  • openssl 生成证书(分别生成私钥和自签名证书),确保环境上已经安装完成了openssl
    • openssl genpkey -algorithm RSA -out key.pem
    • openssl req -new -x509 -key key.pem -out cert.pem -days 365
      在这里插入图片描述
      days为证书的有效期。命令执行完成后在当前目录下就会生成key.pemcert.pem 。记下文件路径,后续会作为参数传入到我们的函数中去。

4、Socket+SSL 的c语言实现

4.1 编写SSL连接函数

在进行SSL初始化的时候需要注意的是,由于连接协商的过程使用的是非对称加密,因此客户端和服务端在初始化的时候是使用的不同的算法。因此,我在函数中加入了一个SSL_MODE参数。用来指明当前是服务端还是客户端的SSL。

SSL* sync_initialize_ssl(const char* cert_path, const char* key_path, SSL_MODE mode, int fd) {const SSL_METHOD *method;SSL_CTX *ctx;SSL *ssl = NULL;// 初始化OpenSSL库SSL_library_init();OpenSSL_add_all_algorithms();SSL_load_error_strings();// 根据模式(客户端/服务端)选择合适的方法if (mode == SSL_MODE_SERVER) {method = SSLv23_server_method();} else if (mode == SSL_MODE_CLIENT) {method = SSLv23_client_method();} else {// 未知模式printf("Not found method");return NULL;}// 创建SSL上下文ctx = SSL_CTX_new(method);if (!ctx) {printf("Unable to create SSL context");return NULL;}// 配置SSL上下文if (SSL_CTX_use_certificate_file(ctx, cert_path, SSL_FILETYPE_PEM) <= 0 || SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) <= 0 ) {printf("Not found certificate or private key");SSL_CTX_free(ctx);return NULL;}// SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);// 创建SSL对象ssl = SSL_new(ctx);if (!ssl) {printf("Failed to create SSL object.");return NULL;}// 设置文件描述符if (SSL_set_fd(ssl, fd) == 0) {printf("Failed to set fd to SSL object.");return NULL;}// SSL握手if ((mode == SSL_MODE_CLIENT && SSL_connect(ssl) <= 0) ||(mode == SSL_MODE_SERVER && SSL_accept(ssl) <= 0)) {int ssl_result;if (mode == SSL_MODE_CLIENT) {ssl_result = SSL_connect(ssl);} else if (mode == SSL_MODE_SERVER) {ssl_result = SSL_accept(ssl);}int ssl_err = SSL_get_error(ssl, ssl_result);const char *err_str;switch (ssl_err) {case SSL_ERROR_NONE:err_str = "No error";break;case SSL_ERROR_SSL:err_str = "Error in the SSL protocol";break;case SSL_ERROR_WANT_READ:err_str = "SSL read operation did not complete";break;case SSL_ERROR_WANT_WRITE:err_str = "SSL write operation did not complete";break;case SSL_ERROR_WANT_X509_LOOKUP:err_str = "SSL X509 lookup operation did not complete";break;case SSL_ERROR_SYSCALL:err_str = "Syscall error";break;case SSL_ERROR_ZERO_RETURN:err_str = "SSL connection was shut down cleanly";break;case SSL_ERROR_WANT_CONNECT:err_str = "SSL connect operation did not complete";break;case SSL_ERROR_WANT_ACCEPT:err_str = "SSL accept operation did not complete";break;default:err_str = "Unknown error";break;}printf("===============SSL handshake failed. Error: %s========!\n", err_str ? err_str : "Unknown");return NULL;}return ssl;
}

4.2 编写加密服务端server.c

#include <stdio.h>  
#include <stdlib.h>  
#include <stddef.h>
#include <string.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <arpa/inet.h>
#include <netinet/in.h>  
#include <openssl/ssl.h>  
#include <openssl/err.h>  #define SERVER_PORT 9990  
#define MAXLINE 4096  typedef enum {SSL_MODE_SERVER,SSL_MODE_CLIENT
} SSL_MODE;int main(int argc, char **argv) {  int listenfd, connfd;  struct sockaddr_in servaddr, cliaddr;  char buf[MAXLINE];  // 创建监听套接字  listenfd = socket(AF_INET, SOCK_STREAM, 0);  // 绑定地址和端口  memset(&servaddr, 0, sizeof(servaddr));  servaddr.sin_family = AF_INET;  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  servaddr.sin_port = htons(SERVER_PORT);  bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));  // 监听连接  listen(listenfd, 10);  printf("Listening on port %d...\n", SERVER_PORT);  while (1) {  // 接受连接请求  socklen_t len = sizeof(cliaddr);  connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &len);  printf("Accepted connection from %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));  // 创建 SSL 对象并进行握手  SSL *ssl = sync_initialize_ssl("cert.pem", "key.pem", SSL_MODE_SERVER, connfd); // 读取客户端发送的数据并回复  memset(buf, 0, MAXLINE);  SSL_read(ssl, buf, MAXLINE);  printf("Received: %s\n", buf);  SSL_write(ssl, "Hello, client!", strlen("Hello, client!"));  // 关闭连接和清理资源  close(connfd);  SSL_shutdown(ssl);  SSL_free(ssl);  }  return 0;  
}

4.3 编写加密客户端client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <openssl/ssl.h>
#include <openssl/err.h>#define SERVER_IP "127.0.0.1"  // 请根据需要更改服务器IP
#define SERVER_PORT 9990  
#define MAXLINE 4096  typedef enum {SSL_MODE_SERVER,SSL_MODE_CLIENT
} SSL_MODE;int main(int argc, char **argv) {int sockfd;struct sockaddr_in servaddr;char buf[MAXLINE];// 创建 socketsockfd = socket(AF_INET, SOCK_STREAM, 0);// 设置服务器地址和端口memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = inet_addr(SERVER_IP);servaddr.sin_port = htons(SERVER_PORT);// 连接到服务器connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));// 创建 SSL 对象并进行握手SSL *ssl = sync_initialize_ssl("cert.pem", "key.pem", SSL_MODE_CLIENT, sockfd); // 发送数据给服务器SSL_write(ssl, "Hello, server!", strlen("Hello, server!"));// 读取服务器的回复memset(buf, 0, MAXLINE);SSL_read(ssl, buf, MAXLINE);printf("Received: %s\n", buf);// 关闭连接和清理资源close(sockfd);SSL_shutdown(ssl);SSL_free(ssl);return 0;
}

5、使用tcpdump检验

服务端和客户端编写完成后,分别运行起来,这里我运行的端口是9990。使用tcpdump抓取9990端口的传输数据
tcpdump -i any port 9990 -A

在这里插入图片描述
此时分别运行后,服务端客户端数据完成交互后,抓包所看到的数据已经是密文传输了。

源码获取

需要获取源码的可以关注公众号"一颗程序树",点击菜单栏的免费源码输入关键词socket即可

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

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

相关文章

给出一个数组,分析当下的位置他左边有几个比他上的。

给出一个数组&#xff0c;分析当下的位置他左边有几个比他上的。 6 4 3 0 5 1 2 0 0 0 3 1 2 #include<iostream> using namespace std;int cnt(int arr[], int idx) {if (idx 0) {return 0;}int s 0;for (int i 0; i < idx; i)if (arr[i] < arr[idx])s 1;ret…

【BUG】循环中重复使用对象一定要注意

“ 有时候博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能未同步&#xff0c;请认准https://blog.zysicyj.top ” 首发博客地址 文章更新计划 系列文章地址 报错内容 报错信息显示ID重复。 原因分析 在最终添加的方法中&#xff0c;出现了重复ID的报…

体育运动模板推荐

最近的朋友圈一半是晒国庆城市布置的美景的&#xff0c;一半当然就是杭州亚运会了。目前杭州亚运会正在如火如荼的进行中&#xff0c;绝美的开幕式&#xff0c;运动健儿们奋力拼搏的精神&#xff0c;在杭州亚运会的舞台上&#xff0c;每个人都是独一无二的英雄。亚运会的舞台&a…

C语言学习(1)—— 环境安装和配置

运行C语言和C程序需要安装MinGW和VSCode。 一. 安装MinGW 1、进入官网下载MinGW&#xff1a;https://sourceforge.net/projects/mingw-w64/files/ 2、解压缩 3、配置环境变量 4、检查是否安装成功 二. 安装VSCode 1、进入官网下载VSCode&#xff1a;https://code.visualstud…

Frp内网穿透

Frp简介 Frp 是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 Frp工作原理&#xff1a; 服务端运行&#xff0c;监听一个主端口&#xff0c;等待…

如何扫描MSI安装文件的路径

今天有个需求&#xff0c;需要扫描已经安装应用, 其中有个华云桌面 其中的UninstallString 值是 MsiExec.exe /X{D20A661B-0CBA-4DE3-A1F6-353D8153725D} 无法直接获取其安装目录&#xff0c; MsiGetProductInfoW 等API INSTALLPROPERTY_INSTALLLOCATION 也不好使 自己写一个…

使用Velodyne传感器生成的点云进行快速且稳健的聚类处理:一个C++实践指南

一、引言 点云数据在现今的自动驾驶、机器人以及三维建模领域中扮演着越来越重要的角色。其中&#xff0c;Velodyne传感器作为业内知名的激光雷达产品&#xff0c;其生成的点云数据质量上乘。然而&#xff0c;对于这样的数据进行有效、快速、稳健的聚类处理仍是一个挑战。本文…

01贪心:算法理论知识

贪心&#xff1a;01算法理论知识 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 这么说有点抽象&#xff0c;来举一个例子&#xff1a; 例如&#xff0c;有一堆钞票&#xff0c;你可以拿走十张&#xff0c;如果想达到最大的金额&#xff0…

leetcode345. 反转字符串中的元音字母 【简单题】

简单题竟然想了一个小时&#xff0c;呜呜 题目 给你一个字符串 s &#xff0c;仅反转字符串中的所有元音字母&#xff0c;并返回结果字符串。 元音字母包括 a、e、i、o、u&#xff0c;且可能以大小写两种形式出现不止一次。 示例 1&#xff1a; 输入&#xff1a;s "h…

YTM32的LINFlexD实现UART功能详解

文章目录 引言简介原理与机制同UART模式相关的寄存器时钟与波特率数据缓冲区发送过程接收过程 软件参考文献 引言 初看YTM32B1ME的手册时&#xff0c;一眼看上去&#xff0c;竟然没有找到UART模块的章节&#xff0c;心想这车规MCU的产品定义也太激进了&#xff0c;直接把工业和…

Vue之vue-cli搭建SPA项目

目录 ​编辑 前言 一、vue-cli简介 1. 什么是vue-cli 2. vue-cli的重要性 3. vue-cli的应用场景 二、Vue-cli搭建SPA项目 1. 构建前提&#xff08;node.js安装完成&#xff09; 2. 安装vue-cli 3. 使用脚手架vue-cli(2.X版)来构建项目 4. 分析创建spa项目的八个问题 …

Rust 学习笔记

Rust 学习笔记 Hello world 代码一 fn main() { // 在这里编写你的 Rust 代码 println!("Hello world!"); } 什么是Rust 语言&#xff1f; Rust是一门系统编写语言 &#xff0c;专注于安全 &#xff0c;尤其是并发安全&#xff0c;支持函数式和命令式等编程…

基于规则架构-架构案例2019(三十九)

电子商务 某电子商务公司为了更好地管理用户&#xff0c;提升企业销售业绩&#xff0c;拟开发一套用户管理系统。该系统的基本功能是根据用户的消费级别、消费历史、信用情况等指标将用户划分为不同的等级&#xff0c;并针对不同等级的用户提供相应的折扣方案。在需求分析与架…

axios添加缓存请求,防止多次请求,单页面多个同一组件造成多次请求解决方案

在axios中&#xff0c;添加 const cacheMap {};响应拦截添加 try {// 删除缓存const api res.config.url.replace(process.env.VUE_APP_BASE_API, "");if (cacheMap.hasOwnProperty(api)) {delete cacheMap[api];}} catch (err) {}创建两个请求方法 /*** Get缓存…

计算机网络相关知识点(二)

TCP如何保证传输过程的可靠性&#xff1f; 校验和&#xff1a;发送方在发送数据之前计算校验和&#xff0c;接收方收到数据之后同样需要计算&#xff0c;如果不一致&#xff0c;那么代表传输有问题。 确认应答序&#xff0c;序列号&#xff1a;TCP进行传输时数据都进行了编号…

PTA 睡前速刷(C++ Java)

1167 Cartesian Tree 题意&#xff1a;要的大概就是&#xff1a;中序 -> 数组序&#xff08;层序遍历&#xff09;&#xff0c;中序不能唯一确定&#xff0c;但本题有前置添加&#xff1a;该二叉树是小顶堆 思考&#xff1a;那么最小的数值&#xff0c;一定是顶根&#xf…

Vue2+ElementUI 静态首页案例

源码 <template><div class"app-container home"><el-row type"flex" justify"space-around" class"row-bg"><el-card class"box-card cardDiv1"><el-col :span"5"><div clas…

小程序自定义tabbar,中间凸起

微信小程序自带tabbar&#xff0c;但无法实现中间按钮凸起样式和功能&#xff0c;因此按照设计重新自定义一个tabbar 1、创建tabbar文件&#xff0c;与pages同级创建一个文件夹&#xff0c;custom-tab-bar,里面按照设计图将底部tabbar样式编写 <view class"tab-bar&q…

庆国庆中秋双节多克大回馈!!!凡官方旗舰店产品,每个产品下订单的前10名,现价基础之上8 折优惠

凡官方旗舰店产品&#xff0c;每个产品下订单的前10名&#xff0c;现价基础之上8折优惠&#xff08;每单限一个产品&#xff09;&#xff1b;10名之后&#xff0c;现价基础之上9.5折优惠&#xff0c;付款之前请加官方微信&#xff0c;并将订单截图发送至官方微信&#xff01;&a…

【设计模式】四、工厂模式

文章目录 概述工厂模式简单工厂模式&#xff1a;工厂方法模式抽象工厂模式小结 概述工厂模式 传统方式&#xff1a; 简单工厂模式&#xff1a; 简单工厂模式的设计方案: 定义一个可以实例化 Pizaa 对象的类&#xff0c;封装创建对象的代码。 存在的问题&#xff1a; 简单工厂…