首页 > 其他分享 >20.8 OpenSSL 套接字SSL传输文件

20.8 OpenSSL 套接字SSL传输文件

时间:2023-11-06 09:33:37浏览次数:38  
标签:1024 lib ssl 20.8 OpenSSL char SSL include

有了上面的基础那么传输文件的实现就变得简单了,在传输时通常我们需要打开文件,并每次读入1024个字节的数据包,通过SSL加密传输即可,此处的文件传输功能在原生套接字章节中也进行过详细讲解,此处我们还是使用原来的密钥对,实现一个服务端等待客户端上传,当客户端连接到服务端后则开始传输文件,服务端接收文件的功能。

服务端代码部分,此处我们只需要实现一个DownloadFile函数,该函数接收一个SSL套接字,与保存文件路径即可,其他部分同上。

#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 1024

// 从路径中获取当前文件名
char* GetFileName(char* Path)
{
  if (strchr(Path, '\\'))
  {
    char ch = '\\';
    char* ref = strrchr(Path, ch) + 1;
    return ref;
  }
  else
  {
    char ch = '/';
    char* ref = strrchr(Path, ch) + 1;
    return ref;
  }
}

// 下载文件到当前目录
// 传入套接字句柄,以及放置根目录
void DownloadFile(SSL* ptr, const char* RootPath)
{
  int FileSize = 0;
  char FilePath[1024] = { 0 };
  char buffer[1024] = { 0 };

  // 接收文件长度
  SSL_read(ptr, &FileSize, 4);

  // 接收文件路径
  SSL_read(ptr, FilePath, 1024);

  // 获取到文件名
  char* FileName = GetFileName(FilePath);

  // 拼接路径
  char sz[1024] = { 0 };
  strcpy(sz, RootPath);
  strcat(sz, FileName);
  std::cout << sz << std::endl;

  // 保存文件到当前目录
  FILE* pointer = fopen(sz, "wb");

  if (pointer != NULL)
  {
    DWORD length = 0;
    DWORD total_length = 0;

    // 循环接收字节数据,每次接收1024字节
    while ((length = SSL_read(ptr, buffer, 1024)) > 0)
    {
      // 写出文件并判断是否写出成功
      if (fwrite(buffer, sizeof(char), length, pointer) < length)
      {
        break;
      }

      // 每次累加递增
      total_length += length;
      memset(buffer, 0, 1024);

      // 判断文件长度是否全部接收完毕
      if (total_length >= FileSize)
      {
        std::cout << "[传输完成] " << total_length << std::endl;
        fclose(pointer);
        return;
      }
    }
    fclose(pointer);
  }
}

int main(int argc, char** argv)
{
  SOCKET sockfd, new_fd;
  struct sockaddr_in socket_ptr, their_addr;
  char buf[MAXBUF + 1];
  SSL_CTX* ctx;

  SSL_library_init();
  OpenSSL_add_all_algorithms();
  SSL_load_error_strings();

  ctx = SSL_CTX_new(SSLv23_server_method());
  if (ctx == NULL)
  {
    return 0;
  }

  if (SSL_CTX_use_certificate_file(ctx, "d://cacert.pem", SSL_FILETYPE_PEM) <= 0)
  {
    return 0;
  }

  if (SSL_CTX_use_PrivateKey_file(ctx, "d://privkey.pem", SSL_FILETYPE_PEM) <= 0)
  {
    return 0;
  }

  if (!SSL_CTX_check_private_key(ctx))
  {
    return 0;
  }

  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 = inet_addr("127.0.0.1");
  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);
    }

    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, new_fd);
    if (SSL_accept(ssl) == -1)
    {
      closesocket(new_fd);
      break;
    }

    // 调用下载文件函数
    DownloadFile(ssl, "d://lyshark/");

  finish:
    SSL_shutdown(ssl);
    SSL_free(ssl);
    closesocket(new_fd);
  }

  closesocket(sockfd);
  WSACleanup();
  SSL_CTX_free(ctx);

  system("pause");
  return 0;
}

客户端部分,同样代码中只需要实现一个UploadFile函数,该函数用于发送本地文件到远程,其他部分同上。

#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 1024

// 获取文件大小
int GetFileSize(std::string FileName)
{
  FILE* pointer = NULL;
  pointer = fopen(FileName.c_str(), "rb");
  if (pointer != NULL)
  {
    fseek(pointer, 0, SEEK_END);
    int size = ftell(pointer);
    fclose(pointer);
    return size;
  }
  return 0;
}

// 上传文件,传入socket套接字句柄,需要发送的文件路径
void UploadFile(SSL* ptr, const char* FilePath)
{
  int FileSize = GetFileSize(FilePath);
  char buffer[1024] = { 0 };

  // 发送文件长度
  SSL_write(ptr, &FileSize, 4);

  // 发送完整文件路径
  SSL_write(ptr, FilePath, strlen(FilePath));
  FILE* pointer = fopen(FilePath, "rb");
  if (pointer != NULL)
  {
    int length = 0;
    DWORD total_length = 0;

    while ((length = fread(buffer, sizeof(char), 1024, pointer)) > 0)
    {
      SSL_write(ptr, buffer, length);
      memset(buffer, 0, 1024);
    }
  }
}

int main(int argc, char** argv)
{
  int sockfd, len;
  struct sockaddr_in dest;
  char buffer[MAXBUF + 1] = { 0 };
  SSL_CTX* ctx;
  SSL* ssl;

  SSL_library_init();
  OpenSSL_add_all_algorithms();
  SSL_load_error_strings();

  ctx = SSL_CTX_new(SSLv23_client_method());
  if (ctx == NULL)
  {
    WSACleanup();
    return 0;
  }

  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)) < 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;
  }

  ssl = SSL_new(ctx);
  SSL_set_fd(ssl, sockfd);

  if (SSL_connect(ssl) != -1)
  {
    printf("SSL 连接类型: %s \n", SSL_get_cipher(ssl));
  }

  // 发送文件
  UploadFile(ssl, "d://lyshark.exe");

finish:
  SSL_shutdown(ssl);
  SSL_free(ssl);
  closesocket(sockfd);
  SSL_CTX_free(ctx);

  system("pause");
  return 0;
}

读者可自行编译这段代码,并首先启动服务端等待传输,接着打开客户端,此时客户端中的d://lyshark.exe将被传输到服务端的特定目录下,如下图所示;

标签:1024,lib,ssl,20.8,OpenSSL,char,SSL,include
From: https://www.cnblogs.com/LyShark/p/17811833.html

相关文章

  • 20.7 OpenSSL 套接字SSL加密传输
    OpenSSL中的SSL加密是通过SSL/TLS协议来实现的。SSL/TLS是一种安全通信协议,可以保障通信双方之间的通信安全性和数据完整性。在SSL/TLS协议中,加密算法是其中最核心的组成部分之一,SSL可以使用各类加密算法进行密钥协商,一般来说会使用RSA等加密算法,使用TLS加密针对服务端来说......
  • 20.7 OpenSSL 套接字SSL加密传输
    OpenSSL中的SSL加密是通过SSL/TLS协议来实现的。SSL/TLS是一种安全通信协议,可以保障通信双方之间的通信安全性和数据完整性。在SSL/TLS协议中,加密算法是其中最核心的组成部分之一,SSL可以使用各类加密算法进行密钥协商,一般来说会使用RSA等加密算法,使用TLS加密针对服务端来......
  • 20.6 OpenSSL 套接字分发RSA公钥
    通过上一节的学习读者应该能够更好的理解RSA加密算法在套接字传输中的使用技巧,但上述代码其实并不算完美的,因为我们的公钥和私钥都必须存储在本地文本中且公钥与私钥是固定的无法做到更好的保护效果,而一旦公钥与私钥泄密则整个传输流程都将会变得不安全,最好的保护效果是RSA密钥在每......
  • 20.6 OpenSSL 套接字分发RSA公钥
    通过上一节的学习读者应该能够更好的理解RSA加密算法在套接字传输中的使用技巧,但上述代码其实并不算完美的,因为我们的公钥和私钥都必须存储在本地文本中且公钥与私钥是固定的无法做到更好的保护效果,而一旦公钥与私钥泄密则整个传输流程都将会变得不安全,最好的保护效果是RSA密钥在......
  • shell 升级openssl-1.1.1n openssh-8.9p1
    #!/bin/bash#基于CentOS7.5编写#功能实现升级openssl-1.1.1nopenssh-8.9p1#检测基础环境是否安装yumupdateopenssh-yyuminstall-ygccgcc-c++glibcmakeautoconfopensslopenssl-develpcre-develpam-develyuminstall-ypam*zlib*#configure:error:......
  • 20.5 OpenSSL 套接字RSA加密传输
    RSA算法同样可以用于加密传输,但此类加密算法虽然非常安全,但通常不会用于大量的数据传输,这是因为RSA算法加解密过程涉及大量的数学运算,尤其是模幂运算(即计算大数的幂模运算),这些运算对于计算机而言是十分耗时。其次在RSA算法中,加密数据的长度不能超过密钥长度减去一定的填充长度。......
  • SSL证书链及使用
    什么是证书链证书链简单来说是域名钥证书、CA公钥、根证书形成的一个颁发链条,属于公钥的一部分。更白话一点,就是证书链文件包含一系列CA机构公钥的证书。证书链格式一般证书链格式是.chain,证书定义顺序是倒序的,即先权威CA再根CA。以根CA+一个权威CA举例:-----BEGINCERTIFICA......
  • SSL证书检查与报警
    不管是iOSAPP,微信小程序,还是浏览器,随着对安全要求的提高,HTTPS已经几乎是所有网站的标配的。作为运维,监控并保证SSL证书的可用性就成了一个很现实的问题。在早期,域名不是很多的情况下,使用的SSL证书数量有限。可以采用手动录入,定期检查的方式来确保SSL证书在有效期内。但是随着业务......
  • 未能创建 SSL/TLS 安全通道
    事件背景对接ebay的时候,报错:未能创建SSL/TLS安全通道调试发现使用RestSharp并不会,HttpClient不行,猜测是RestSharp底层处理了TLS1.2的支持查阅资料"未能创建SSL/TLS安全通道"错误通常是由于TLS版本或加密协议不匹配引起的。通常情况下,你可以通过更新你的.NET版本来......
  • 20.4 OpenSSL 套接字AES加密传输
    在读者了解了加密算法的具体使用流程后,那么我们就可以使用这些加密算法对网络中的数据包进行加密处理,加密算法此处我们先采用AES算法,在网络通信中,只需要在发送数据之前对特定字符串进行加密处理,而在接收到数据后在使用相同的算法对数据进行恢复即可,读者如果有了套接字编程的基础,那......