用python编写socket加密通信主要有两点,第一步是通过socket库实现socket通信,第二步将通信的内容使用pycrypto库进行RSA加解密操作。
step1:
socket通信原理图
可能不是一个客户端在登录,所以我们这里使用多线程,确保客户端相互不干扰。
下边是一个简单的聊天小程序。
客户端
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
| #-*-encoding:utf-8 -*- import socket,os,threading class RecvMsg(threading.Thread): def __init__(self,threadName,client): threading.Thread.__init__(self) self.name=threadName self.client=client def run(self): while 1: data = client.recv(1024) if data: print data #如果有信息,就打印出来,这个主线程只需要做这个 else: pass client.close() class SendMsg(threading.Thread): def __init__(self,threadName,client): threading.Thread.__init__(self) self.name=threadName self.client=client def run(self): while 1: data=raw_input("") self.client.sendall(data) client=socket.socket(socket.AF_INET, socket.SOCK_STREAM) address=('127.0.0.1',12001) client.connect(address) s=SendMsg("msg1",client) s.start() #调用start方法新建一个子线程,注意,run方法本身是单线程 w=RecvMsg("msg2",client) w.start()
|
服务器端:
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
| #-*-encoding:utf-8 -*- import socket import threading import os import Queue msglist=Queue.Queue(maxsize = 0) clientlist=[] class HandleMsg(threading.Thread): def __init__(self,threadName,conn): threading.Thread.__init__(self) self.name=threadName self.conn=conn self.alive=True def broadcast(self): msg=msglist.get() print msg for i in clientlist: try: i.sendall(msg) except: print self.name+" has disconnected" clientlist.remove(i) else: pass def stop(self): self.alive=False print self.name+" has disconnected" def run(self): while self.alive: try: data=self.conn.recv(1024) except: self.stop() self.conn.close() clientlist.remove(self.conn) else: msglist.put(self.name+" says:"+data) self.broadcast() server=socket.socket(socket.AF_INET, socket.SOCK_STREAM) address=('',12001) server.bind(address) server.listen(30) #这里代表最多响应的连接个数 while 1: conn, addr = server.accept() (host,port)=addr #这里使用host来获取连接的ip #然后每次有人连接进来服务器就打印一个连接进来的消息 print host+" has connected into server" clientlist.append(conn) #这里把每个连接的客户端加入一个列表 #广播的时候就直接遍历发送 HandleMsg(host,conn).start()
|
step2:加密(对1中的功能做部分修改)
秘钥产生过程
在消息处理的类中写一个秘钥产生的函数,在重写run方法的函数中先调用秘钥产生函数,实现客户与服务器间交换秘钥。
1 2 3 4 5 6 7 8
| def crypmodel(self): global random_generator random_generator = Random.new().read rsa = RSA.generate(1024, random_generator) # generating key pair private_pem = rsa.exportKey() public_pem = rsa.publickey().exportKey() return [private_pem,public_pem]
|
客户端向服务器发送消息
服务器向客户端发送消息
客户端向服务器发送消息,需要使用服务器端发来的公钥进行加密,服务器端使用自己的私钥进行解密。
1 2 3 4 5 6 7 8 9 10 11
| #加密 def encrypto(self,txt,public_pemC): rsakey = RSA.importKey(public_pemC) cipher = Cipher_pkcs1_v1_5.new(rsakey) return base64.b64encode(cipher.encrypt(txt)) #解密 def decrypto(self,txt,private_pemS): global random_generator rsakey = RSA.importKey(private_pemS) cipher = Cipher_pkcs1_v1_5.new(rsakey) return cipher.decrypt(base64.b64decode(txt), random_generator)
|
这里我是让服务器端去教学信息网,就是实现了一个客户端发送加密后的用户名密码给服务器端,服务器端接收用户名密码后进行用户登录,然后把查找的内容逐条加密发送给客户端。
–end—之前是客户端与服务器建立连接后,服务器将加密的公钥发给客户端,以后是客户端发送的用户名密码的密文以及解密的明文。
客户端首先接收密文并解密的结果
当然了,通信过程做好还要加上数字签名,但是只是为了完成小学期作业,所以就没有进行到这么繁琐的地步。