Socket_Tcp加密文件传输系统

代码下载链接:Socket_Tcp

原文链接:https://blog.csdn.net/weixin_45746588/article/details/107683901

这是一个课程的作业,我是初学者,所以写完这个代码还是花了我好几周的时间,在这里整理下,如有错误请批评指正。

仅供学习参考!

文件传输系统设计

1. Socket通信

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

socket()函数
int socket(int domain, int type, int protocol);

socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

socket函数的三个参数分别为:

domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

在这里插入图片描述

type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。

在这里插入图片描述

protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

TCP通信

在这里插入图片描述

tcp 编程一般的步骤:

在这里插入图片描述

2. 文件传输

文件发送将文件进行分片传输,每次传输不大于4096字节。

1.	file_length = File_Length(fr); //得到文件大小  
2.	n = (file_length%DEFAULT_BUFFER)?  
3.	          ((file_length/DEFAULT_BUFFER)+1):(file_length/DEFAULT_BUFFER);//对文件进行切片,每4096字节一片  
4.	rmd = (file_length%DEFAULT_BUFFER)?(file_length%DEFAULT_BUFFER):DEFAULT_BUFFER; //剩余最后一片长度的字节  

每一片文件信息传输包的格式定义如下:

1.	typedef struct {  
2.	    int  file_tag;  //是否最后一片标志位
3.	    int  file_rmd;  //最后一片文件字节长度
4.	    char buffer[DEFAULT_BUFFER];  //要发送的文件字节
5.	}File_Info;  

若发送的文件大小是4096个字节,则file_tag=0; file_rmd=0;
若发送的文件为最后一片,则file_tag=1; file_rmd=rmd;

1.	fread(file_packet.buffer, 1, DEFAULT_BUFFER, fr);  
2.	        if(i!=n)  
3.	            file_packet.file_tag = 0; file_packet.file_rmd = 0;  
4.	        else  
5.	            file_packet.file_tag = 1; file_packet.file_rmd = rmd;  
6.	        sendto(sock, (char *)&file_packet, sizeof(file_packet), 0,  
7.	            (struct sockaddr far *)&raddr, sizeof(raddr));  

文件接收:接收到文件并直接保存。

1.	recv(udp_receiver, (char *)&file_packet, sizeof(File_Info), 0);  
2.	      if (file_packet.file_tag == 0)  //是否最后一片标志位
3.	          fwrite(file_packet.buffer, 1, DEFAULT_BUFFER, fp);  //非最后一片接收4096字节
4.	      else 
5.	      { 
6.	          fwrite(file_packet.buffer, 1, file_packet.file_rmd, fp);  //最后一片接收rmd个字节
7.	          break;  
8.	      } 

3. RSA加密

RSA加解密公式
加密:公钥(E,N) 密文=(明文^E) mod N
解密:密钥(D,N) 明文=(密文^D) mod N
RSA的安全基于大数分解的难度。公钥和私钥是一对大素数的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积。

RSA密钥产生的过程:
  1. 随机选择两个不相等的质数p和q。
  2. 计算p和q的乘积n,n=pq。
  3. 计算n的欧拉函数φ(n)。
  4. 随机选择一个整数e,条件是1<e<φ(n),并且e与φ(n)互质。
  5. 计算e对于φ(n)的模反元素d,使de=1 mod φ(n) ——(de)modφ(n)=1
  6. 产生公钥(e,n)。私钥(d,n)
举例:
  1. 选择p=3,q=11.
  2. n=pq=33.
  3. φ(n)=(p-1)x(q-1)=20.
  4. 选择e=3,e与φ(n)互质
  5. (de)mod φ(n)=(d3)mod20,d=7
  6. 公钥(3,33),私钥(7,33)
    设计过程:密钥产生,由于对文件加密为逐字节加密,因此n的值要大于256。所以p和q的值要大于16。又为了使一个字节加密后的大小小于0xFFFF,则p和q的值要小于256。
1.	void RSA::ProduceKeys() {  
2.	    long prime1 = ProducePrime();//随机选取16-256之间的素数  
3.	    long prime2 = ProducePrime();//随机选取16-256之间的素数  
4.	    while (prime1 == prime2)  
5.	        prime2 = ProducePrime();//确保两素数不相等  
6.	    _key.share_key = ProduceShareKey(prime1, prime2);  
7.	    long orla = ProduceOrla(prime1, prime2);  
8.	    _key.public_key = ProducePublicKey(orla);   //产生公钥  
9.	    _key.private_key = ProducePrivateKey(_key.public_key, orla);  //产生私钥  
10.	}  
RSA加密解密:
1.	long RSA::Ecrept(long msg, long key, long share_key) {  
2.	    unsigned long a = (unsigned long)msg;//msg为要加密或解密的信息  
3.	    long b = key;  
4.	    int c = share_key;  
5.	    long r = 1;  
6.	    while (b-- != 0)  
7.	        r = (r * a) % c;  
8.	    return r;  
9.	}  

对文件进行加密解密:对文件加密时,读取文件为单字节读取,存储为long类型:

1.	fread(buffer, sizeof(char), DEFAULT_BUFFER, fp); //对字节加密  
2.	fwrite(dat, sizeof(long), DEFAULT_BUFFER, save_fp); //存储为long类型  

对文件解密时,读取为long类型,储存为char类型:

1.	fread(buffer, sizeof(long), DEFAULT_BUFFER, fp); //对long类型解密  
2.	fwrite(dat, sizeof(char), DEFAULT_BUFFER, save_fp); //存储为char类型  

4. MD5生成摘要

MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要。MD5的算法原理为以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
对文件生成摘要:将文件以二进制打开,这里仅对大小不超过4096字节的文件进行加密,若文件大于4096字节,则仅加密前4096字节。

1.	fp = fopen(file_dir, "rb"); //  打开要加密的文件
2.	fr = fopen("client_signature_cache.dat", "w+b");  //打开保存摘要的文件
3.	memset(buffer, 0, DEFAULT_BUFFER);  
4.	fread(buffer, sizeof(char), DEFAULT_BUFFER, fp);  
5.	getMD5Code(buffer, signature);  //生成数字摘要  
6.	fwrite(signature, sizeof(char), 16, fr);  //保存数字摘要到文件  

5. 数字签名和身份鉴定

数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。数字签名是非对称密钥加密技术与数字摘要技术的应用。当客户端要向服务器传输文件时,客户端先用MD5算法对将要发送的文件生成数字摘要,然后用自己的私钥对摘要进行加密得到数字签名。客户端将数字签名随文件一起发给服务器,服务器收到文件和数字签名后,首先用公钥将数字签名进行解密得到客户端发送的摘要,再用MD5算法对接收到的文件生成摘要。最后将两份摘要进行对比,若完全一致,说明是客户端发送的文件,并且文件没有被篡改。若不是一致的,则说明文件被篡改或则不是指定客户端发送的,用户被冒用了。

1.	//客户端私钥加密数字摘要得到数字签名  
2.	rsa.Ecrept("client_signature_cache.dat", "client_signature_Ecrept.dat", key.private_key, key.share_key);  
1.	//服务器公钥解密数字签名得到文件的数字摘要  
2.	sa.DEcrept("server_signature_recevie.dat","server_signature_DEcrept.dat",key.public_key,key.share_key);  

6. 程序设计及运行

6.1. 与服务器连接并登录

首先开启服务器并监听。打开客户端,客户端会生成一对密钥。输入密码,客户端与服务器建立连接。客户端将公钥发给服务器。运行界面如下图所示:
在这里插入图片描述

6.2. List命令获得文件目录

我们已准备两个文件夹,一个是服务器文件夹,一个是客户端文件夹。在客户端输入l或list命令可以得到服务器文件夹下的文件目录。如图所示:
在这里插入图片描述

6.3. get命令从服务器下载文件,并加密传输

我们使用get或g命令从服务器下载文件,在文件传输过程中会服务器端会生成加密文件,然后将加密的文件传输给客户端,客户端接收到加密的文件后先缓存,待接收完毕后进行解密,最终得到要下载的文件,并且我们可以看到文件也没有被损坏。运行如下图:
在这里插入图片描述

6.4. delet命令从服务器端删除文件

使用delet或d命令可以从服务器文件夹下删除文件,运行如下图:
在这里插入图片描述

6.5. put命令上传文件

使用put命令可以上传文件,上传时先将文件生成摘要,再对摘要进行私钥加密。服务器收到文件和摘要后,同样对接收到的文件生成摘要,并对签名使用公钥进行解密。验证两份摘要是否一致。运行结果如下:
在这里插入图片描述

文件生成的摘要是:9be686ad1f4e1438ef5bc6ec7ad107d7
我们改变文件的一个字符再次上传,可以看到仅改变一个字符,生成的摘要就完全不一样,得到如下结果:
在这里插入图片描述

6.6. help命令和echo命令

输入help命令可以打印帮助页,echo命令可以从服务器得到文件的详细信息。运行如图:

在这里插入图片描述

一个课程的作业,我是初学者,所以写完这个代码还是花了我好几周的时间,在这里整理下,如有错误请批评指正。

仅供学习参考!

代码下载链接:Socket_Tcp

  • 9
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
Python可以通过使用加密算法和网络编程库来实现加密传输系统。以下是一种基本的实现方式: 1. 导入所需的库: ```python import socket import hashlib from Crypto.Cipher import AES ``` 2. 创建一个TCP服务器和客户端: ```python # 服务器端 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 12345)) server_socket.listen(1) client_socket, address = server_socket.accept() # 客户端 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect(('localhost', 12345)) ``` 3. 生成密钥和初始化向量: ```python key = hashlib.sha256(b'my_secret_key').digest() iv = b'my_initial_vector' ``` 4. 定义加密和解密函数: ```python def encrypt(plain_text): cipher = AES.new(key, AES.MODE_CBC, iv) cipher_text = cipher.encrypt(plain_text) return cipher_text def decrypt(cipher_text): cipher = AES.new(key, AES.MODE_CBC, iv) plain_text = cipher.decrypt(cipher_text) return plain_text ``` 5. 在服务器端发送和接收加密数据: ```python # 发送加密数据 message = 'Hello, World!' encrypted_message = encrypt(message.encode()) client_socket.sendall(encrypted_message) # 接收加密数据 received_data = client_socket.recv(1024) decrypted_data = decrypt(received_data) print(decrypted_data.decode()) ``` 6. 在客户端发送和接收加密数据: ```python # 发送加密数据 message = 'Hello, Server!' encrypted_message = encrypt(message.encode()) client_socket.sendall(encrypted_message) # 接收加密数据 received_data = client_socket.recv(1024) decrypted_data = decrypt(received_data) print(decrypted_data.decode()) ``` 这只是一个简单的示例,实际的加密传输系统可能需要更复杂的实现和安全性措施。你可以根据具体需求选择适合的加密算法和网络协议来实现更强大的加密传输系统
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值