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
|
#!/usr/bin/python
# NSA P2P聊天客户端
# -*- coding: utf-8 -*-
import sys
import socket
import base64
import random
import string
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
from threading import Thread
import getpass
class CryptoClient(object):
def __init__(self):
print("欢迎使用CryptoChat,一个安全的P2P聊天客户端")
print("你想要加密吗?好的,小伙子,开始吧!!!")
self.IP = input("请输入你想要聊天的IP地址:")
self.PORT = int(input("输入通信端口:"))
print()
print("现在输入不同加密方法的密钥,确保它们不同。")
print("请注意,为了安全起见,它们不会被显示。")
print()
self.EncryptKeyXOR = getpass.getpass("输入XOR加密的密钥:")
self.EncryptKeyAES = hashlib.md5(getpass.getpass("输入AES的安全密码:").encode()).hexdigest()
print()
input("当两个客户端都准备好时按回车。")
### AES填充处理
BS = 16
self.pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
self.unpad = lambda s: s[:-ord(s[len(s) - 1:])]
### 启动聊天服务器和客户端
try:
Thread(target=self.RecvMSG, args=()).start()
except socket.error as e:
print(self.IP + " 还没准备好!当 " + self.IP + " 准备好时按回车。")
input()
Thread(target=self.RecvMSG, args=()).start()
self.SendMSG()
def EncryptAES(self, raw):
raw = self.pad(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.EncryptKeyAES.encode(), AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw.encode())).decode()
def DecryptAES(self, enc):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.EncryptKeyAES.encode(), AES.MODE_CBC, iv)
return self.unpad(cipher.decrypt(enc[16:])).decode()
def XOR(self, securekey, data, mode):
if mode == 1:
securekey = securekey[::-1]
temp = ''
for char in securekey:
for x in data:
temp += chr(ord(x) ^ ord(char))
data = temp
temp = ''
return data
def EncryptMSG(self, data):
data = self.XOR(self.EncryptKeyXOR, data, 0)
data = self.EncryptAES(data)
return data
def DecryptMSG(self, data):
data = self.DecryptAES(data)
data = self.XOR(self.EncryptKeyXOR, data, 1)
return data
def SendMSG(self):
clientsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
print()
print("你现在正在与 '" + self.IP + "' 对话")
while True:
message = input("")
if message.startswith("/send"): # 发送文件命令
self.SendFILE(message.split(" ")[1])
continue
if message == "/leave":
message = self.EncryptMSG("\x03")
clientsock.sendto(message.encode(), (self.IP, self.PORT))
sys.exit(0)
if message.startswith("/msg"):
self.IP = message.split(" ")[1]
print("[CLIENT] 你现在正在与 '" + self.IP + "' 对话")
continue
else:
message = self.EncryptMSG("\x01" + message)
clientsock.sendto(message.encode(), (self.IP, self.PORT))
def SendFILE(self, file_):
if file_.startswith(".") or file_.startswith("/"): # 添加的安全措施
print("[CLIENT] 出于安全和保护原因,以 '.' 或 '/' 开头的文件名不会被发送。中止。")
else:
clientsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
data = "\x02" + file_ + "\xFF"
with open(file_, "rb") as f:
data += f.read()
data = self.EncryptMSG(data)
clientsock.sendto(data.encode(), (self.IP, self.PORT))
print("[CLIENT] 文件已发送!")
def RandStr(self, length):
return ''.join(random.choice(string.ascii_letters) for _ in range(length))
def RecvMSG(self):
serversocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
serversocket.bind(('', self.PORT))
while True:
data, addr = serversocket.recvfrom(1073741824) # 缓冲区大小为1Gb(用于大文件/图像)
data = self.DecryptMSG(data.decode())
if data.startswith("\x02"):
filename = ''
data = list(data)
del data[0]
for i in data:
if i == "\xFF":
break
else:
filename += i
del data[0] # 删除协议字符
del data[:len(filename)] # 删除文件结束字符
if filename.startswith(".") or filename.startswith("/"): # 尝试利用!
print("[!!!警报!!!] " + addr[0] + " 试图覆盖你的 " + filename)
else:
print("[CLIENT] " + addr[0] + " 发送了 " + filename)
print("[CLIENT] 正在下载...") # 下载那个东西
data = ''.join(data)
with open(filename, "wb") as f:
f.write(data.encode())
print("[CLIENT] 已保存。")
elif data.startswith("\x01"): # 所有消息以"\x01"开头以防止文件垃圾邮件
data = list(data)
del data[0]
data = ''.join(data)
print("[" + addr[0] + "] > | " + data)
elif data.startswith("\x03"):
print("[CLIENT] " + addr[0] + " 已离开。")
sys.exit(0)
if __name__ == "__main__":
CryptoClient()
|