You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
12 KiB

import base64
import struct
from tkinter import *
import time
from tkinter import filedialog
import pickle
import socket
import threading
import tkinter.messagebox
from algorithms import AESalgorithm, generateKey, RSAalgorithm, hashalg
import json
import sys
# 使用tkinter建立GUI
IP = '127.0.0.1'
PORT = 4396
BUFF = 5120
FIP='127.0.0.1'
FPORT=7932
# CLIENTPUBLICs
# SERVERPUBLICs
# SERVERPRIVATEs
def initKey():
global SERVERPUBLICs, SERVERPRIVATEs
(SERVERPRIVATEs, SERVERPUBLICs) = generateKey.generateMyKey("keys/server/server")
def fileDecrypt(data):
(message,encrykey)=pickle.loads(data)
onceKey= RSAalgorithm.RsaDecrypt(encrykey, SERVERPRIVATEs)
print("接收到的密钥",onceKey,type(onceKey))
message= AESalgorithm.AesDecrypt(message, onceKey.decode('unicode_escape'))
message=pickle.loads(message)
content=base64.b64decode(message['Message'])
print('传送的内容是',content)
digest=message['digest']
if RSAalgorithm.VerRsaSignal(content, digest, CLIENTPUBLICs):
return content
def initFileListen():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口为9001
s.bind((FIP, FPORT))
# 设置监听数
s.listen(10)
except socket.error as msg:
print(msg)
sys.exit(1)
print('Waiting connection...')
while True:
# 等待请求并接受(程序会停留在这一旦收到连接请求即开启接受数据的线程)
conn, addr = s.accept()
# 接收数据
t = threading.Thread(target=deal_data, args=(conn, addr))
t.start()
def deal_data(conn, addr):
print('Accept new connection from {0}'.format(addr))
txtMsgList.insert(END, '文件系统收到一个新的连接,地址来自 {0}'.format(addr), 'greencolor')
# conn.settimeout(500)
# 收到请求后的回复
conn.send('你好,连接建立成功了'.encode('utf-8'))
while True:
# 申请相同大小的空间存放发送过来的文件名与文件大小信息
fileinfo_size = struct.calcsize('128sl')
# 接收文件名与文件大小信息
buf = conn.recv(fileinfo_size)
# 判断是否接收到文件头信息
if buf:
# 获取文件名和文件大小
filename, filesize = struct.unpack('128sl', buf)
fn = filename.strip(b'\00')
fn = fn.decode()
print('file new name is {0}, filesize if {1}'.format(str(fn), filesize))
txtMsgList.insert(END, '收到的文件名字为 {0}, 文件大小为 {1}'.format(str(fn), filesize), 'greencolor')
recvd_size = 0 # 定义已接收文件的大小
# 存储在该脚本所在目录下面
fp = open('./' + str(fn), 'wb')
print('start receiving...')
txtMsgList.insert(END, '开始接受...', 'greencolor')
# 将分批次传输的二进制流依次写入到文件
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
lens=conn.recv(1024).decode('utf-8')
lens=int(lens)
print('该段发送长度为',lens)
data = conn.recv(lens)
data=fileDecrypt(data)
recvd_size += len(data)
else:
lens = conn.recv(1024).decode('utf-8')
lens = int(lens)
print('该段发送长度为', lens)
data = conn.recv(lens)
data = fileDecrypt(data)
recvd_size = filesize
conn.send('I have receive the past one'.encode('utf-8'))
fp.write(data)
fp.close()
print('end receive...')
txtMsgList.insert(END, '接收完毕...', 'greencolor')
# 传输结束断开连接
conn.close()
break
def mainPage():
def sendMsg(Sock): # 发送消息
strMsg = "我:" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '\n'
txtMsgList.insert(END, strMsg, 'greencolor')
Mes = txtMsg.get('0.0', END)
txtMsgList.insert(END, Mes)
print(Mes)
onceKey = AESalgorithm.genKey() # 一次一密 密钥
print("oncekey", onceKey)
digest = RSAalgorithm.RsaSignal(Mes, SERVERPRIVATEs) # 先hash再签名# 生成消息摘要
message = {'Message': Mes, 'digest': digest.decode("utf-8")} # 把消息和摘要打包
message = json.dumps(message) # 转成json字符串
message = AESalgorithm.AesEncrypt(message, onceKey) # 合并加密
encrykey = RSAalgorithm.RsaEncrypt(onceKey, CLIENTPUBLICs) # 用服务器公钥加密一次密钥
txtMsg.delete('0.0', END)
Message = pickle.dumps([message, encrykey.decode('utf-8')]) # 序列化消息,用于传输
Sock.send(Message)
def RecvMsg(Sock, test):
global CLIENTPUBLICs
while True:
Message = Sock.recv(BUFF) # 收到文件
(message, encrykey) = pickle.loads(Message)
mykey = RSAalgorithm.RsaDecrypt(encrykey, SERVERPRIVATEs) # 用私钥解密获得一次密钥
decryMes = AESalgorithm.AesDecrypt(message, mykey.decode('utf-8')) # 用一次密钥解密消息获得包含消息内容和摘要的json
decryMes = json.loads(decryMes) # 将json转换为python字典
content = decryMes['Message']
digest = decryMes['digest'].encode('utf-8')
if RSAalgorithm.VerRsaSignal(content, digest, CLIENTPUBLICs):
strMsg = "对方:" + time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime()) + "通过数字签名认证,本次密钥为" + mykey.decode('utf-8') + '\n'
txtMsgList.insert(END, strMsg, 'greencolor')
txtMsgList.insert(END, content + '\n')
def cancelMsg(): # 取消信息
txtMsg.delete('0.0', END)
def sendMsgEvent(event, Sock): # 发送消息事件
if event.keysym == 'Up':
sendMsg(Sock)
def UploadAction(event=None):
filename = filedialog.askopenfilename()
print('Selected:', filename)
def addSysTip(mes):
global txtMsgList
txtMsgList.insert(END, "系统消息:" + mes)
def exchangePublicKey(dir):
global ConSock, txtMsgList
with open(dir, 'rb') as fi:
publicKey = fi.read()
# print(publicKey)
has = hashalg.hash_sha256(publicKey)
Message = pickle.dumps([publicKey, has])
try:
ConSock.send(Message)
txtMsgList.insert(END, "发送公钥成功\n")
except:
txtMsgList.insert(END, "密钥发送失败,正在尝试重新发送...\n")
exchangePublicKey(dir)
def verifyKey(Sock):
global txtMsgList, CLIENTPUBLICs
while True:
Message = Sock.recv(BUFF)
# print("shoudao:",Message)
(publickey, hash_256) = pickle.loads(Message)
if hash_256 == hashalg.hash_sha256(publickey):
txtMsgList.insert(END, "公钥完整性验证完成,可以开始传输文件\n")
CLIENTPUBLICs = publickey
txtMsgList.insert(END, "收到公钥\n" + CLIENTPUBLICs.decode('utf-8') + "\n")
# print("publicc:", CLIENTPUBLICs)
break
else:
txtMsgList.insert(END, "验证失败\n")
def cnct():
global txtMsgList, ConSock
HOSTIP = '127.0.0.1'
ServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ServerSock.bind((HOSTIP, PORT))
ServerSock.listen(8)
print("本机IP地址为", HOSTIP, "端口号为", PORT, ",正在监听中")
txtMsgList.insert(END, "系统消息:" + "本机IP地址为" + HOSTIP + "端口号为" + str(PORT) + ",正在监听中\n")
ConSock, addr = ServerSock.accept()
print('连接成功')
txtMsgList.insert(END, "系统消息:连接成功\n")
exchangePublicKey("keys/server/serverpublic.pem")
verifyKey(ConSock)
thread_rev = threading.Thread(target=RecvMsg, args=(ConSock, None))
thread_rev.start()
return ConSock
def setIpWindows():
def setNewIP(newip, newport):
print(newip, newport)
global IP
IP = str(newip)
global PORT
PORT = int(newport)
set.destroy()
try:
cnct()
except:
addSysTip("连接异常ip或端口不可访问")
tkinter.messagebox.showwarning('连接失败', '连接异常ip或端口不可访问\n')
print("连接异常ip或端口不可访问\n")
set = Tk()
set.title('设置ip地址和端口号')
set.geometry('350x200')
set.resizable(0, 0)
# ip
Label(set, text='IP地址').place(x=10, y=10)
ent1 = Entry(set)
ent1.place(x=150, y=10)
# port
Label(set, text='端口号:').place(x=10, y=50)
ent2 = Entry(set)
ent2.place(x=150, y=50)
bt_connect = Button(set, text='连接', command=lambda: setNewIP(ent1.get(), ent2.get()))
bt_connect.place(x=150, y=130)
set.mainloop()
def start():
global app, frmLT, frmLC, frmLB, txtMsgList, txtMsg, btnSend, btnCancel, btnFile, btnSet
# 创建窗口
app = Tk()
app.title('Server')
app.resizable(0, 0)
# 创建frame容器
frmLT = Frame(width=500, height=320, bg='white')
frmLC = Frame(width=500, height=150, bg='white')
frmLB = Frame(width=500, height=30)
# frmRT = Frame(width = 200, height = 500)
# 创建控件
txtMsgList = Text(frmLT)
txtMsgList.tag_config('greencolor', foreground='#008C00') # 创建tag
txtMsg = Text(frmLC)
txtMsg.bind("<KeyPress-Up>", sendMsgEvent)
btnSend = Button(frmLB, text='发送', width=8, command=lambda: sendMsg(ServerSocket))
btnCancel = Button(frmLB, text='取消', width=8, command=cancelMsg)
btnFile = Button(frmLB, text='上传文件', width=8, command=UploadAction)
btnSet = Button(frmLB, text='设置ip', width=8, command=setIpWindows)
# btnFile.pack()
# imgInfo = PhotoImage(file = "timg-2.gif")
# lblImage = Label(frmRT, image = imgInfo)
# lblImage.image = imgInfo
# 窗口布局
frmLT.grid(row=0, column=0, columnspan=2, padx=1, pady=3)
frmLC.grid(row=1, column=0, columnspan=2, padx=1, pady=3)
frmLB.grid(row=2, column=0, columnspan=2)
# frmRT.grid(row = 0, column = 2, rowspan = 3, padx =2, pady = 3)
# 固定大小
frmLT.grid_propagate(0)
frmLC.grid_propagate(0)
frmLB.grid_propagate(0)
# frmRT.grid_propagate(0)
btnSend.grid(row=2, column=0)
btnCancel.grid(row=2, column=1)
btnFile.grid(row=2, column=2)
btnSet.grid(row=2, column=3)
# lblImage.grid()
txtMsgList.grid()
txtMsg.grid()
# 主事件循环
app.mainloop()
thread_gui = threading.Thread(target=start)
thread_gui.start()
ServerSocket = cnct()
# try:
# ServerSocket=cnct()
# except:
# addSysTip("连接异常ip或端口不可访问")
# tkinter.messagebox.showwarning('连接失败', '连接异常ip或端口不可访问点击设置按钮重新设置\n')
# print("连接异常ip或端口不可访问\n")
def main():
initKey()
thread_1=threading.Thread(target=initFileListen)
# thread_2=threading.Thread(target=mainPage)
mainPage()
thread_1.start()
# thread_2.start()
if __name__ == "__main__":
main()