forked from wenjunjiecn/Cybersecurity-EncryptChatProject
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClient.py
More file actions
287 lines (245 loc) · 10.5 KB
/
Copy pathClient.py
File metadata and controls
287 lines (245 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
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
from tkinter import ttk
import json
import os
import base64
# 使用tkinter建立GUI
IP = '127.0.0.1'
PORT = 4396
BUFF = 5120
FIP='127.0.0.1'
FPORT=7932
# SERVERPUBLIC
# CLIENTPUBLIC
# CLIENTPRIVATE
def initKey():
global CLIENTPUBLIC, CLIENTPRIVATE
(CLIENTPRIVATE, CLIENTPUBLIC) = generateKey.generateMyKey("keys/client/client")
def fileEncrypt(data):
onceKey = AESalgorithm.genKey()
print("发送的密钥",onceKey)
digest = RSAalgorithm.RsaSignal(data, CLIENTPRIVATE)
message = {'Message': base64.b64encode(data), 'digest': digest.decode("utf-8")} # 把消息和摘要打包
message = pickle.dumps(message) # 转成json字符串
message = AESalgorithm.AesEncrypt(message, onceKey)
encrykey = RSAalgorithm.RsaEncrypt(onceKey, SERVERPUBLIC)
MES = pickle.dumps([message, encrykey.decode('utf-8')])
return MES
def initSendSocket(filepath):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((FIP, FPORT))
except socket.error as msg:
print(msg)
sys.exit(1)
print(s.recv(10240))
# 需要传输的文件路径
# 判断是否为文件
if os.path.isfile(filepath):
# 定义定义文件信息。128s表示文件名为128bytes长,l表示一个int或log文件类型,在此为文件大小
fileinfo_size = struct.calcsize('128sl')
# 定义文件头信息,包含文件名和文件大小
fhead = struct.pack('128sl', os.path.basename(filepath).encode('utf-8'), os.stat(filepath).st_size)
# 发送文件名称与文件大小
s.send(fhead)
# 将传输文件以二进制的形式分多次上传至服务器
fp = open(filepath, 'rb')
while True:
global rere
rere=''
data = fp.read(1024)
if not data:
print('{0} 文件发送完毕...'.format(os.path.basename(filepath)))
txtMsgList.insert(END, '{0} 文件发送完毕...'.format(os.path.basename(filepath)), 'greencolor')
break
print("发送的内容",data)
tosend=fileEncrypt(data)
s.send(str(len(tosend)).encode('utf-8'))
s.send(tosend)
while True:
if s.recv(1024).decode('utf-8')=='I have receive the past one':
break
# 关闭当期的套接字对象
s.close()
# 主页
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)
onceKey = AESalgorithm.genKey() # 一次一密 密钥
digest = RSAalgorithm.RsaSignal(Mes, CLIENTPRIVATE) # 先hash再签名# 生成消息摘要
message = {'Message': Mes, 'digest': digest.decode("utf-8")} # 把消息和摘要打包
message = json.dumps(message) # 转成json字符串
message = AESalgorithm.AesEncrypt(message, onceKey) # 合并加密
encrykey = RSAalgorithm.RsaEncrypt(onceKey, SERVERPUBLIC) # 用服务器公钥加密一次密钥
txtMsg.delete('0.0', END)
Message = pickle.dumps([message, encrykey.decode('utf-8')]) # 序列化消息,用于传输
Sock.send(Message)
def RecvMsg(Sock, test): # 接受消息函数
global SERVERPUBLICs
while True:
Message = Sock.recv(BUFF) # 收到文件
(message, encrykey) = pickle.loads(Message)
mykey = RSAalgorithm.RsaDecrypt(encrykey, CLIENTPRIVATE) # 用私钥解密获得一次密钥
print('mykey', mykey.decode('utf-8'))
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, SERVERPUBLIC):
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)
initSendSocket(filename)
def exchangePublicKey(dir):
global ClientSock, txtMsgList
with open(dir, 'rb') as fi:
publicKey = fi.read()
has = hashalg.hash_sha256(publicKey)
Message = pickle.dumps([publicKey, has])
try:
ClientSock.send(Message)
txtMsgList.insert(END, "发送公钥成功\n")
except:
txtMsgList.insert(END, "密钥发送失败,正在尝试重新发送...\n")
exchangePublicKey(dir)
def verifyKey(Sock):
global txtMsgList, SERVERPUBLIC
while True:
Message = Sock.recv(BUFF)
(publickey, hash_256) = pickle.loads(Message)
if hash_256 == hashalg.hash_sha256(publickey):
txtMsgList.insert(END, "公钥完整性验证完成,可以开始传输文件\n")
SERVERPUBLIC = publickey
txtMsgList.insert(END, "收到公钥\n" + SERVERPUBLIC.decode('utf-8') + "\n")
break
else:
txtMsgList.insert(END, "验证失败\n")
def cnct(): # 连接操作
global txtMsgList, ClientSock
ClientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ServerAddr = IP
ClientSock.connect((ServerAddr, PORT))
print('连接成功,可以开始传输消息和文件了\n')
txtMsgList.insert(END, "连接成功,可以开始传输消息和文件了" + IP + ":" + str(PORT) + "\n")
exchangePublicKey("keys/client/clientpublic.pem") # 发送公钥
verifyKey(ClientSock) # 验证对方密钥
thread = threading.Thread(target=RecvMsg, args=(ClientSock, None))
thread.start()
return ClientSock
def setIpWindows(): # 设置ip的子窗口
def setNewIP(newip, newport):
global txtMsgList
print(newip, newport)
global IP
IP = str(newip)
global PORT
PORT = int(newport)
set.destroy()
try:
cnct()
except:
txtMsgList.insert(END, "连接异常,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():
# 以下是生成聊天窗口的代码
def selectEven(*args):
print(selal.get())
global app, frmLT, frmLC, frmLB, txtMsgList, txtMsg, btnSend, btnCancel, btnFile, btnSet
# 创建窗口
app = Tk()
app.title('网络加密软件-Client')
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)
selal = StringVar()
btnSend = Button(frmLB, text='发送', width=8, command=lambda: sendMsg(ClientSocket))
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)
btnAlSel = ttk.Combobox(frmLB, textvariable=selal, state='readonly')
btnAlSel['values'] = ('AES-CBC-一次一密', '待定2')
btnAlSel.current(0)
btnAlSel.bind("<<ComboboxSelected>>", selectEven)
print("selal is ", selal.get())
# 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)
btnAlSel.grid(row=2, column=4)
# lblImage.grid()
txtMsgList.grid()
txtMsg.grid()
# 主事件循环
app.mainloop()
thread_gui = threading.Thread(target=start)
thread_gui.start()
ClientSocket = cnct()
# try:
# ClientSocket=cnct()
# except:
# addSysTip("连接异常,ip或端口不可访问")
# tkinter.messagebox.showwarning('连接失败', '连接异常,ip或端口不可访问,点击设置按钮重新设置\n')
# print("连接异常,ip或端口不可访问\n")
def main():
initKey()
mainPage()
if __name__ == "__main__":
main()