一、概述
Socket编程,将DES加密算法应用到网络通信,使用RSA算法自动分配密钥,设计好界面,可验证自动生成的密钥和加解密的正确结果。
二、功能需求
- 客户端和服务器建立连接后,客户端生成一个随机DES密钥
- 服务器端生成一个随机的RSA公私钥对,并将公钥发给客户端
- 客户端收到公钥后加密DES密钥,发给服务器,服务器用私钥解密
- 客户端和服务器使用DES密钥通信,进行聊天会话
三、总体设计
3.1 设计思想
- 利用Socket建立服务端和客户端的连接
- 实现服务端和客户端的简单会话,能发送数据和接收数据
- 服务端生成一个RSA公私钥对,并把公钥发送给客户端
- 客户端利用接收到的公钥对DES密钥进行加密,然后发给服务端
- 服务端利用私钥对加密后的DES密钥进行解密,即得到了DES密钥
- 发送端将数据先用DES加密,然后转化为utf-8格式,接收端将utf-8格式转为字符,然后再用DES解密,显示出来
- 利用threading多线程实现服务端和客户端能同时发送和接收数据
3.2 总体架构
3.3 开发环境
操作系统为Windows 10 企业版,64位操作系统。实现语言为Python 3.7.0,实验平台为Jupyter Notebook。
四、详细设计
- 服务端,创建Socket对象,绑定地址(host, port)到套接字,开始 TCP 监听,最大连接数量为5,等待连接;客户端,创建Socket对象,建立与服务器的连接。
- 利用recv()和send()函数来接收和发送数据,再加上while True实现服务端和客户端的简单会话,简单测试,结果正确进行下一步
- 客户端发送‘changekey’开始进行密钥交换,服务端收到消息后,利用RSA,产生一对公钥和私钥,并将公钥发送给客户端,客户端收到消息后,用公钥对DES密钥进行加密,并将加密结果发送给服务端,服务端收到消息后,用私钥进行解密,即得到了DES密钥
- 服务端和客户端进行聊天交互,首先判断key是否为0,为0则等待客户端发送密钥交换指令,不为0则正常通信。正常通信流程为,发送端将数据先用DES加密,然后转化为utf-8格式,接收端将utf-8格式转为字符,然后再用DES解密,显示出来。简单测试,结果正确进行下一步。
- 最后利用threading实现发送和接收的同时进行。客户端,首先判断key是否为0,然后调用一个线程用来接收消息,最后在当前线程进行发送消息;客户端,首先进行交换密钥,然后调用一个线程用来发送消息,最后在当前线程进行接收消息。当接收到的信息为‘quit’时,关闭套接字。
五、测试
5.1 环境
Python 3.7.0 & Jupyter Notebook
5.2 测试方案
采用有意义的英文句子作为明文输出,输出算法配置参数,和中间的加密结果以及解密结果。
5.3 测试结果
服务器端初始化
客户端和服务器端交换密钥
服务端和客户端分别发送信息
服务端和客户端分别连续发送信息(可同时发送和接收信息)
服务器和客户端分别发送长信息(最大为512个英文字符)
5.4 源代码
# socket
'''****server端****'''
'''/****20201124***/'''
from socket import *
import DES as des
import rsa
import threading
import time
print("当前时间:"+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
#key = '6A4B3C7D9E2F1F3F'
IV = [0x51, 0xA2, 0x6C, 0x32, 0x11, 0xF1, 0xD4, 0x09]
key = ''
# AF_INET --> IPv4 SOCK_STREAM --> TCP
HOST = ''
PORT = 6666
BUFF = 1024
ADDR = (HOST,PORT)
s1 = socket(AF_INET,SOCK_STREAM)
s1.bind(ADDR)
s1.listen(5)
print('sever is running')
print('waiting for connection...')
conn, addr = s1.accept()
print('...connecting from:', addr)
def _SendMessage():
while True:
s1_send_data = input(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) + ' 服务器>>>:')
s1_send_data = des._DES(s1_send_data, key, IV, 0)
s1_send_data = s1_send_data.encode('utf-8')
if len(s1_send_data) > 0:
conn.send(s1_send_data)
def _RecvMessage():
while True:
s1_recv_data = conn.recv(BUFF)
if not s1_recv_data:
break
s1_recv_data = s1_recv_data.decode()
print('加密信息:'+s1_recv_data)
s1_recv_data = des._DES(s1_recv_data, key, IV, 1)
if s1_recv_data == 'quit':
break
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) + ' 客户端>>>:' + s1_recv_data)
class A(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
_RecvMessage()
while True:
if not key:
s1_recv_data = conn.recv(BUFF)
if s1_recv_data.decode('utf-8') == 'changekey':
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' start to change key!')
(pubkey, privkey) = rsa.newkeys(512, poolsize=8)
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' create pubkey & privkey')
modulus = pubkey.n
exponent = pubkey.e
conn.send(str(modulus).encode('utf-8'))
conn.send(str(exponent).encode('utf-8'))
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' send pubkey')
key = conn.recv(BUFF)
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' recv encrypted des-key')
key = rsa.decrypt(key, privkey)
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' decrypt des-key')
key = key.decode()
a = A()
a.start()
_SendMessage()
#s1.close()
# socket
'''****client端****'''
'''/****20201124***/'''
from socket import *
import DES as des
import rsa
import threading
import time
print("当前时间:"+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
IV = [0x51, 0xA2, 0x6C, 0x32, 0x11, 0xF1, 0xD4, 0x09]
HOST = 'localhost'
PORT = 6666
BUFF =1024
ADDR = (HOST,PORT)
t = 2
s2 = socket(AF_INET,SOCK_STREAM)
s2.connect(ADDR)
key = '6A4B3C7D9E2F1F3F'
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' start to change key!')
s2.send('changekey'.encode('utf-8'))
modulus = int(s2.recv(BUFF).decode('utf-8'))
exponent = int(s2.recv(BUFF).decode('utf-8'))
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' start to build pubkey')
pubkey = rsa.PublicKey(modulus, exponent)
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' encrypt des-key')
crypto = rsa.encrypt(key.encode('utf8'), pubkey)
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+' send encrypted des-key')
s2.send(crypto)
def _SendMessage():
while True:
s2_send_data = input(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) + ' 客户端>>>:')
s2_send_data = des._DES(s2_send_data, key, IV, 0)
s2_send_data = s2_send_data.encode('utf-8')
if len(s2_send_data) > 0:
s2.send(s2_send_data)
def _RecvMessage():
while True:
time.sleep(t)
s2_recv_data = s2.recv(BUFF)
if not s2_recv_data:
break
s2_recv_data = s2_recv_data.decode()
print('加密信息:'+s2_recv_data)
s2_recv_data = des._DES(s2_recv_data, key, IV, 1)
if s2_recv_data == 'quit':
break
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) + ' 服务端>>>:' + s2_recv_data)
class A(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
_SendMessage()
a = A()
a.start()
while True:
_RecvMessage()
#s2.close()