c语言利用openssl实现简单客户端和服务端(观察记录层最大长度)

本文主要是介绍c语言利用openssl实现简单客户端和服务端(观察记录层最大长度),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、客户端实现
  • 二、服务端实现
  • 总结


前言

本文是使用openssl111w实现的简单客户端和服务端,主要用于观察openssl一个记录层数据包的大小。


一、客户端实现

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/types.h>   
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <openssl/ssl.h>  
#include <openssl/err.h>  
#define PORT 8000
#define SERVER_IP "127.0.0.1"
#define SERVER_KEY "./rsa_cert/serverkey.pem"
#define SERVER_CERT "./rsa_cert/servercert.pem"
#define CA_CERT "./rsa_cert/cacert.pem"
// 初始化OpenSSL库 
void init_openssl() {  SSL_load_error_strings();  OpenSSL_add_all_algorithms();  SSL_library_init();  
}  
//创建原始套接字
int create_connect_fd()
{struct sockaddr_in serv_addr;int client_fd;// 创建socketif ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0){printf("\n Socket creation error \n");return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// 使用inet_pton转换IP字符串为网络字节序if(inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr)<=0){printf("\nInvalid address/ Address not supported \n");return -1;}// 连接服务器if (connect(client_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){printf("\nConnection Failed \n");return -1;}return client_fd;
}
//创建ssl上下文
SSL_CTX* create_ssl_ctx() {  const SSL_METHOD *method;  SSL_CTX *ctx;  method = TLSv1_2_client_method();  ctx = SSL_CTX_new(method);  if (!ctx) {  printf("Unable to create SSL context");  ERR_print_errors_fp(stderr);  return NULL;} // 加载服务器证书和私钥  if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {  ERR_print_errors_fp(stderr); printf("load server cert failed\n"); return NULL;  }  if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {  ERR_print_errors_fp(stderr);  printf("load server key failed\n");return NULL;}  // 检查私钥和证书是否匹配  if (!SSL_CTX_check_private_key(ctx)) {  printf("cert and key mismatch\n");return NULL;}   //加载CA证书if (!SSL_CTX_load_verify_locations(ctx, CA_CERT, NULL)) {  printf("load ca cert failed\n");return NULL; }  //必须验证服务端证书,不设置则不验证SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);  return ctx;  
}  int main()
{SSL_CTX *ctx;SSL *ssl;int client_fd,send_len;char buf[102400] = {0};/* 初始化SSL库 */init_openssl();/* 创建SSL_CTX结构体 */ctx = create_ssl_ctx();  if(ctx == NULL){printf("create ssl ctx failed\n");return -1;}/* TCP协议连接到服务器 */client_fd = create_connect_fd(); if(client_fd < 0){printf("create client fd failed\n");return -1;}//创建ssl对象ssl = SSL_new(ctx);SSL_set_fd(ssl, client_fd);//ssl握手if (SSL_connect(ssl) == -1) {ERR_print_errors_fp(stderr);return -1;}printf("Connected with %s encryption\n", SSL_get_cipher(ssl));/* 发送数据 */send_len = SSL_write(ssl, buf, sizeof(buf));if(send_len < 0){printf("SSL_write failed\n");}else{printf("write len:%d\n", send_len);}SSL_shutdown(ssl);SSL_free(ssl);close(client_fd);SSL_CTX_free(ctx);return 0;
}

二、服务端实现

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/types.h>   
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <openssl/ssl.h>  
#include <openssl/err.h>  
#define PORT 8000
#define SERVER_KEY "./rsa_cert/serverkey.pem"
#define SERVER_CERT "./rsa_cert/servercert.pem"
#define CA_CERT "./rsa_cert/cacert.pem"
// 初始化OpenSSL库  
void init_openssl() {  SSL_load_error_strings();  OpenSSL_add_all_algorithms();  SSL_library_init();  
}  // 创建ssl上下文 
SSL_CTX* create_ssl_ctx() {  const SSL_METHOD *method;  SSL_CTX *ctx;  OpenSSL_add_ssl_algorithms();  method = TLSv1_2_server_method();  ctx = SSL_CTX_new(method);  if (!ctx) {  printf("Unable to create SSL context");  ERR_print_errors_fp(stderr);  return NULL;}  // 加载服务器证书和私钥  if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {  ERR_print_errors_fp(stderr); printf("load server cert failed\n"); return NULL;  }  if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {  ERR_print_errors_fp(stderr);  printf("load server key failed\n");return NULL;}  // 检查私钥和证书是否匹配  if (!SSL_CTX_check_private_key(ctx)) {  printf("cert and key mismatch\n");return NULL;}  if (!SSL_CTX_load_verify_locations(ctx, CA_CERT, NULL)) {  printf("load ca cert failed\n");return NULL; }  //必须验证服务端证书,不设置则不验证SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);  return ctx;  
}  
//创建监听套接字
int create_listenfd()
{int listen_fd;struct sockaddr_in server_addr;int opt = 1;if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){printf("socket failed\n");return -1;}// 设置socket选项,允许重复使用地址if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,&opt, sizeof(opt))){printf("setsockopt failed\n");return -1;}server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);// 绑定socket到指定地址和端口if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))<0){printf("bind failed\n");return -1;}// 开始监听,最大等待队列长度为5if (listen(listen_fd, 5) < 0){printf("listen failed\n");return -1;}return listen_fd;
}int main() {  int listen_fd,con_fd,recv_len;char buf[20480] = {0};init_openssl();  //创建ssl上下文SSL_CTX *ctx = create_ssl_ctx();  if(ctx == NULL){printf("create ssl ctx failed\n");return -1;}//创建监听套接字listen_fd = create_listenfd();if(listen_fd < 0){printf("create listen fd failed\n");return -1;}while(1) {struct sockaddr_in client_addr;socklen_t len = sizeof(client_addr);SSL *ssl;//等待客户端发起tcp链接con_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &len);if(con_fd < 0){printf("create connetct fd failed\n");return -1;}printf("create connect fd success\n");ssl = SSL_new(ctx);SSL_set_fd(ssl, con_fd);//等待ssl握手if (SSL_accept(ssl) == -1) {ERR_print_errors_fp(stderr);return -1;} printf("SSL Connection established\n");for (;;) {//读取ssl数据recv_len = SSL_read(ssl, buf, sizeof(buf));if (recv_len > 0)printf("Received_len:%d \n", recv_len);else {ERR_print_errors_fp(stderr);break;}}SSL_shutdown(ssl);SSL_free(ssl);close(con_fd);}SSL_CTX_free(ctx);close(listen_fd);return 0;  
}

总结

服务端ssl_read能够接受的最大数据包是16384(2^14)字节,也就是一个记录层的最大数据。
在这里插入图片描述

这篇关于c语言利用openssl实现简单客户端和服务端(观察记录层最大长度)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1058804

相关文章

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

redis群集简单部署过程

《redis群集简单部署过程》文章介绍了Redis,一个高性能的键值存储系统,其支持多种数据结构和命令,它还讨论了Redis的服务器端架构、数据存储和获取、协议和命令、高可用性方案、缓存机制以及监控和... 目录Redis介绍1. 基本概念2. 服务器端3. 存储和获取数据4. 协议和命令5. 高可用性6.

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操