socket加密通信


编程思路:

  1. 客户端和服务器端建立连接
  2. 客户端产生非对称密钥,将公钥传送给服务器端
  3. 服务器端通过公钥将密钥进行加密并传送给客户端
  4. 客户端接收到密钥并进行解密,双方开始通信

背景资料:

  • AES原理(图解密码技术第三章)
  • RSA原理(图解密码技术第五章)
  • Socket通信原理

代码部分

注释已经非常详细了,这里就不再赘述。


异常类定义

class AuthenticationError(Exception):

    def __init__(self, Errorinfo):
        super().__init__()
        self.errorinfo = Errorinfo
    def __str__(self):
        return self.errorinfo

服务器端代码


服务器类定义:
import socket
import rsa
import pickle
from cryptography.fernet import Fernet
import hashlib
from errorclass import AuthenticationError
import time

# 使用图灵机器人的自动回复功能
from tlrobot import get_reply

class Server:

    # 用来标记同时连接的客户端的数量
    number = 0

    # 默认的最大等待数量为5
    # 默认使用本机的ip地址和8080端口
    def __init__(self, backlog=5, addr=('localhost', 8080)):
        # 默认使用AF_INET协议族,即ipv4地址和端口号的组合以及tcp协议
        self.serverSocket = socket.socket()
        # 绑定监听的ip地址和端口号
        self.serverSocket.bind(addr)
        # 开始等待
        self.serverSocket.listen(backlog)

    # 该函数需要并行处理
    def link_one_client(self):
        # 获取客户端对象和客户端地址
        clientSocket, addr = self.serverSocket.accept()

        # 客户端数量加1
        Server.number = Server.number + 1
        # 标记当前客户端编号
        now_number = Server.number

        # 打印
        print("和客户端{0}建立连接\n目标主机地址为:{1}".format(now_number, addr))
        # 接受客户端传递的公钥
        # 这里可以加一个哈希函数检验公钥的正确性!
        # 运用pickle进行反序列化
        publicKeyPK, pubKeySha256 = pickle.loads(clientSocket.recv(1024))
        if hashlib.sha256(publicKeyPK).hexdigest() != pubKeySha256:
            raise AuthenticationError("密钥被篡改!")
        else:
            publicKey = pickle.loads(publicKeyPK)
            print("已接受公钥")


        # 下面是用公钥加密对称密钥并传递的过程
        # 产生用于对称加密的密钥
        sym_key = Fernet.generate_key()
        # 用pickle进行序列化用来进行网络传输
        # 对密钥进行hash保证其准确性
        en_sym_key = rsa.encrypt(pickle.dumps(sym_key), publicKey)
        en_sym_key_sha256 = hashlib.sha256(en_sym_key).hexdigest()
        print("正在加密传送密钥")
        clientSocket.send(pickle.dumps((en_sym_key,en_sym_key_sha256)))

        # 这里可以添加密钥交换成功的函数


        # 初始化加密对象
        f = Fernet(sym_key)

        # 下面使用对称密钥进行加密对话的过程
        while True:
            time.sleep(0.3)
            # 接收到的加密消息
            en_recvData = clientSocket.recv(1024)
            recvData = f.decrypt(en_recvData).decode()
            print("接受到客户端{0}传来的消息:{1}".format(now_number, recvData))

            # 调用图灵机器人
            sendData = get_reply(recvData)
            # 对消息进行加密
            en_sendData = f.encrypt(sendData.encode())
            clientSocket.send(en_sendData)


服务器端类实例化:
import threading

from serverclass import Server

print("欢迎使用服务端程序!")

server = Server()
while True:
    # 这里使用多线程可以避免服务器阻塞在一个客户端上
    t = threading.Thread(target=server.link_one_client)
    t.start()

客户端代码


客户端类定义:
import socket
import rsa
import pickle
from cryptography.fernet import Fernet
import hashlib
from errorclass import AuthenticationError

class Client:

    def __init__(self):
        # 产生非对称密钥
        self.asyKey = rsa.newkeys(2048)
        # 公钥和私钥
        self.publicKey = self.asyKey[0]
        self.privateKey = self.asyKey[1]


    def link_server(self, addr=('localhost', 8080)):
        # 创建socket通信对象
        # 默认使用AF_INET协议族,即ipv4地址和端口号的组合以及tcp协议
        clientSocket = socket.socket()
        # 默认连接服务器地址为本机ip和8080端口
        clientSocket.connect(addr)

        # 向服务器传递公钥,和该公钥字符串化后的sha256值
        print("正在向服务器传送公钥")
        sendKey = pickle.dumps(self.publicKey)
        sendKeySha256 = hashlib.sha256(sendKey).hexdigest()
        clientSocket.send(pickle.dumps((sendKey, sendKeySha256)))

        # 接受服务器传递的密钥并进行解密
        symKey, symKeySha256 = pickle.loads(clientSocket.recv(1024))
        if hashlib.sha256(symKey).hexdigest() != symKeySha256:
            raise AuthenticationError("密钥被篡改!")
        else:
            self.symKey = pickle.loads(rsa.decrypt(symKey, self.privateKey))
            print("密钥交换完成")

        # 初始化加密对象
        f = Fernet(self.symKey)

        while True:

            sendData = input("输入你要发送的消息:")
            en_sendData = f.encrypt(sendData.encode())
            clientSocket.send(en_sendData)

            en_recvData = clientSocket.recv(1024)
            recvData = f.decrypt(en_recvData).decode()
            print("接受到服务器传来的消息:{0}".format(recvData))


客户端类实例化:
from clientclass import Client

print("欢迎使用客户端程序!")
client = Client()
client.link_server()

调用图灵机器人的代码


import requests
import json

def get_reply(data):
    datas = {
        'reqType': 0,
        "perception": {
            "inputText": {
                "text": data
            },

            "selfInfo": {
                "location": {
                    "city": "武汉",
                    "province": "湖北"
                }
            }
        },

        "userInfo": {
            # 这里填上自己的apiKey
            "apiKey": "*********************",
            # userid可以随便填写
            "userId": "443545"
        }
    }

    datas = json.dumps(datas)
    url = "http://openapi.tuling123.com/openapi/api/v2"
    r = requests.post(url=url, data=datas)
    return json.loads(r.text).get("results")[0].get("values").get("text")

参考资料:


文章作者: qiufeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 qiufeng !
评论
 上一篇
v2ray-configure v2ray-configure
记录一下怕自己忘记了v2配置v2加速cdn加速hostwind 服务器namesilo 域名网站 document.querySelectorAll('.github-emoji') .forEach(
2020-04-07
本篇 
socket加密通信 socket加密通信
编程思路: 客户端和服务器端建立连接 客户端产生非对称密钥,将公钥传送给服务器端 服务器端通过公钥将密钥进行加密并传送给客户端 客户端接收到密钥并进行解密,双方开始通信 背景资料: AES原理(图解密码技术第三章) RSA原理(图解密码
2020-04-07
  目录