**
**
要求:设计实现一个通信系统,双方可以通过消息通信,用户可选择一种加密算法和认证算法,对消息进行加密通信和完整性验证。
实现方案:
客户端与服务器端建立连接,发送的消息在客户端程序进行加密,经过服务器转发给其他客户端,由客户端解密后显示。
首先,在客户端1对要发送的明文使用MD5算法得到消息摘要,然后用客户端1的RSA私钥对摘要进行签名。把得到的签名和明文合在一起生成消息,再对消息使用RC4流秘钥进行加密成密文,通过服务器来进行消息传输。
客户端2接收到密文后使用RC4解密算法进行解密,得到由明文合签名组成的消息,此时对明文再使用一次MD5算法生成消息摘要,使用得到的摘要和客户端1的RSA公钥对签名进行验证,如果签名的认证结果为True,则证明消息确实是有客户端1发送的,且消息为被篡改。如果签名认证的结果为False,则此消息的来源可能不真确,消息的可靠信丧失。
其中,客户端1和客户端2都要生成自己的RSA公私钥对,对于私钥自己保存,对于公钥则可以公布。RC4算法是一种对称加密算法,加密和解密用的都是一个秘钥,这个秘钥由需要进行通信的不同的客户端自行保存。由于RC4算法是一种流加密算法不同于对称分组加密算法,所以我设计了一个函数来拆分解密后得到的消息,最终分别得到明文和签名。
import tkinter
import socket,threading
win=tkinter.Tk()#创建主窗口
win.title('服务器')
win.geometry("300x200")
users={}#用户字典
def run(ck,ca):
userName=ck.recv(1024)
users[userName.decode("utf-8")]=ck#解码并存储用户信息
printStr=""+userName.decode("utf-8")+"连接\n" #在显示框中显示是否连接成功
text.insert(tkinter.INSERT,printStr)
while True:
buffer=[]
rData=ck.recv(1024) #接受客户端发送的消息
dataStr=rData.decode("utf-8")
buffer.append(dataStr)
infolist=dataStr.split(":")
#要发送信息的客户端向目标客户端发送消息
#users[infolist[0]].send((userName.decode("utf-8")+": "+infolist[1]).encode("utf"))
users[infolist[0]].send((infolist[1]).encode("utf"))
def start():
ipStr=eip.get()#从输入端中获取ip
portStr=eport.get()
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((ipStr,int(portStr))) #绑定ip和端口号
server.listen(10)
printStr="服务器启动成功\n"
text.insert(tkinter.INSERT,printStr)
while True:
ck,ca=server.accept() #接受所连接的客户端的信息
t=threading.Thread(target=run,args=(ck,ca))#每连接一个客户端就开启一个线程
t.start()
def startSever():
s=threading.Thread(target=start)
s.start()#开启线程
labelIp = tkinter.Label(win, text='ip').grid(row=0, column=0)
labelPort = tkinter.Label(win, text='port').grid(row=1, column=0)
eip = tkinter.Variable()
eport = tkinter.Variable()
entryIp = tkinter.Entry(win, textvariable=eip).grid(row=0, column=1)
entryPort = tkinter.Entry(win, textvariable=eport).grid(row=1, column=1)
button = tkinter.Button(win, text="启动", command=startSever).grid(row=8, column=0)
text = tkinter.Text(win, height=5, width=30)
labeltext = tkinter.Label(win, text='连接消息:').grid(row=3, column=1)
text.grid(row=4, column=1)
win.mainloop()
客户端代码:
import tkinter
import socket
import threading
import MD5
import RC4
import RSA
win=tkinter.Tk()
win.title("客户端1")
win.geometry("300x300+200+20")
ck=None #用来存储客户端的信息
def chaifen(message): #用于拆分明文与签名
plain = " "
signal = " "
for i in range(0,len(message)):
if message[i]=='@':
plain=message[0:i]
signal=message[i+1:len(message)]
return plain,signal
def getInfo(): # 接受消息
while True:
data = ck.recv(1024) # 用于接受服务器发送的信息
key = "569716548"
box = RC4.init_box(key)
mingwen = RC4.ex_decrypt(data, box) # 解密消息
p = chaifen(mingwen) # 返回一个包含明文和签名的元组
print("拆分出的签名:")
print(p[1])
s = p[1]
s = s[2:len(s) - 1]
s = s.encode(encoding="utf-8")
m = MD5.md5(p[0]) # 对明文部分使用md5算法生成摘要
# signal2=KEY.sign(m)
v = RSA.Verify(m, s) # 验证签名
judge(v) # 判断安全性
text.insert(tkinter.INSERT, p[0])
def judge(v):
if v == "SHA-1":
print("消息未被篡改,且由本人发送。")
else:
print("本次通信存在安全隐患!")
def connectServer():
global ck
ipStr=eip.get()
portStr=eport.get()
userStr=euser.get()
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((ipStr,int(portStr)))
client.send(userStr.encode("utf-8"))
ck=client
t=threading.Thread(target=getInfo)
t.start()
def sendMail():
friend=efriend.get()#发给谁
sendStr=esend.get()#发送的消息
#用MD5生成消息摘要
abstract=MD5.md5(sendStr)
#用RSA算法对消息摘要进行签名
signal1=RSA.sign(str(abstract))
#生成消息
message=sendStr+'@'+str(signal1)
#用RC4算法对消息进行加密
key="569716548"
box = RC4.init_box(key)
cipher=RC4.ex_encrypt(message, box)
#发送消息
sendStr=friend+":"+cipher
ck.send(sendStr.encode("utf-8"))
#tkinter界面配置
labelUse = tkinter.Label(win, text="userName").grid(row=0, column=0)
euser = tkinter.Variable()
entryUser = tkinter.Entry(win, textvariable=euser).grid(row=0, column=1)
labelIp = tkinter.Label(win, text="ip").grid(row=1, column=0)
eip = tkinter.Variable()
entryIp = tkinter.Entry(win, textvariable=eip).grid(row=1, column=1)
labelPort = tkinter.Label(win, text="port").grid(row=2, column=0)
eport = tkinter.Variable()
entryPort = tkinter.Entry(win, textvariable=eport).grid(row=2, column=1)
button = tkinter.Button(win, text="启动", command=connectServer).grid(row=3, column=0)
text = tkinter.Text(win, height=5, width=25)
labeltext= tkinter.Label(win, text="显示消息").grid(row=4, column=0)
text.grid(row=4, column=1)
esend = tkinter.Variable()
labelesend = tkinter.Label(win, text="发送的消息").grid(row=5, column=0)
entrySend = tkinter.Entry(win, textvariable=esend).grid(row=5, column=1)
efriend = tkinter.Variable()
labelefriend= tkinter.Label(win, text="发给谁").grid(row=6, column=0)
entryFriend = tkinter.Entry(win, textvariable=efriend).grid(row=6, column=1)
button2 = tkinter.Button(win, text="发送", command=sendMail).grid(row=7, column=0)
win.mainloop()
调用RSA模块进行签名/验签:
import rsa
import base64
# 生成密钥
(pubkey, privkey) = rsa.newkeys(1024)
# 保存密钥
with open('public.pem', 'w+') as f:
f.write(pubkey.save_pkcs1().decode())
with open('private.pem', 'w+') as f:
f.write(privkey.save_pkcs1().decode())
# 私钥签名
def sign(message):
with open('private.pem', 'r') as f:
privkey = rsa.PrivateKey.load_pkcs1(f.read().encode())
signature = rsa.sign(message.encode(), privkey, 'SHA-1')
signature = base64.b64encode(signature)
print("生成的签名:")
print(signature)
return signature
# 公钥验证
def Verify(message, signature):
with open('public.pem', 'r') as f:
pubkey = rsa.PublicKey.load_pkcs1(f.read().encode())
signature = base64.b64decode(signature)
v = rsa.verify(message.encode(), signature, pubkey)
print("验签结果:")
print(v)
return v
RC4算法进行加密:
import base64
def get_message():
print("输入信息:")
s = input()
return s
def get_key():
print("输入秘钥")
key = input()
return key
#初始化s盒
def init_box(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def ex_encrypt(plain, box):#加密
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))
cipher = "".join(res)
s=str(base64.b64encode(cipher.encode('utf-8')), 'utf-8')
# base64的目的也是为了变成可见字符
print("加密(解密)后经过base64编码后的输出:")
print(s)
return s
def ex_decrypt(plain, box):#解密
plain = base64.b64decode(plain)
plain = bytes.decode(plain)
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))
cipher = "".join(res)
# base64的目的也是为了变成可见字符
print("加密(解密)后经过base64编码后的输出:")
print(cipher)
return cipher
def encrypt():
message = get_message()
key = get_key()
box = init_box(key)
ex_encrypt(message, box)
if __name__ == '__main__':
while True:
encrypt()
MD5摘要模块:
from hashlib import md5, sha1, sha224, sha256, sha384, sha512
hash_md5 = md5() # MD5 hash对象
hash_sha1 = sha1() # SHA1 hash对象
hash_sha224 = sha224() # SHA224 hash对象
hash_sha256 = sha256() # SHA256 hash对象
hash_sha384 = sha384() # SHA384 hash对象
hash_sha512 = sha512() # SHA512 hash对象
def md5(str):
print('将要生成摘要的字符串:', str)
# MD5 加密
h_md5 = hash_md5.copy() # 复制一个对象,避免频繁创建对象消耗性能
h_md5.update(str.encode('utf-8')) # 需要将字符串进行编码,编码成二进制数据
md5_str = h_md5.hexdigest() # 获取16进制的摘要
print('MD5生成摘要结果:',md5_str) # 输出结果
return md5_str