添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
鼻子大的人字拖  ·  Using the Chicken ...·  1 年前    · 
霸气的核桃  ·  Quickstart: Backup & ...·  1 年前    · 

本次实验要求是基于socket实现Diffie-Hellman密钥交换协议,编程语言不限,本文选用的是Python语言,使用了Python中的socket库,random库以及math库。

程序主要思路如下:

(1)实现客户端与服务端的通信功能,即代码中的Server()函数和Client()函数;

(2)在主函数中实现Diffie-Hellman密钥交换协议;

(3)在通信双方需要交换数据时,调用Server()函数和Client()函数。

Socket:

Socket接口规范可以适用多种通讯协议,主要是TCP/IP。TCP/IP的核心部分由操作系统的内核实现,应用程序通过编程接口来访问TCP/IP,应用程序通讯的方式如下图所示。

Diffie-Hellman密钥交换协议:

假设p是大素数,g是p的本原根,p和g作为公开元素,协议如下:

  • 用户Alice选择随机数XA,计算YA=g XA mod p,保密XA,发送YA给Bob ;
  • 用户Bob选择随机数XB,计算YB=g XB mod p,保密XB,发送YB给Alice;
  • Bob和Alice各自计算 k=YB XA mod p和k=YA XB mod p,从而得到共享密钥k。
  • 这是因为k=YB XA mod p=(g XB ) XA mod p=(g XA ) XB mod p=YA XB mod p。

    代码实现:

    实验语言:Python

    实验环境:Python 3.8.8

    实验软件:Pycharm 2021

    客户端代码:

    import socket
    import math
    import random
    def get_calculation(p, a, X):
        #得到计算数
       Y = (a ** X) % p
       return Y
    def get_generator(p):
        #得到原根
       a = 2
       list = []
       while a < p:
          flag = 1
          while flag != p:
             if (a ** flag) % p == 1:
                break
             flag += 1
          if flag == (p - 1):
             list.append(a)
          a += 1
       return list
    #得到交换计算数后的密钥
    def get_key(X, Y, p):
       key = (Y ** X) % p
       return key
    def Client(x):
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        host = "127.0.0.1"
        port = 8088
        # 连接服务端
        client.connect((host, port))
        send_msg = x
        # 发送数据,编码
        client.send(str(send_msg).encode("utf-8"))
        # 接收服务端返回的数据
        msg = client.recv(1024)
        print("接收到来自服务端的数据:%s" % msg.decode("utf-8"))
        # 关闭客户端
        client.close()
        return msg
    if __name__ == "__main__":
        print("这里是客户端!")
        print("-"*20)
        p = 23 #双方公共数据为23
        # 得到素数的一个原根
        list = get_generator(p)
        # 得到A的私钥
        XA = random.randint(0, p - 1)
        # 得待A的计算数
        YA = get_calculation(p, int(list[-1]), XA)
        #交换计算数
        YB = int(Client(YA))
        # 交换后A的密钥
        key_A = get_key(XA, YB, p)
        print('客户端的生成密钥为:%d' % key_A)
        print("正在发送密钥至服务端比对...")
        judge_op = int(Client(key_A))
        if judge_op == key_A:
            print("比对成功,密钥相同!")

    服务端代码:

    import socket
    import math
    import random
    def get_calculation(p, a, X):
       Y = (a ** X) % p
       return Y
    def get_generator(p):
        #得到原根
       a = 2
       list = []
       while a < p:
          flag = 1
          while flag != p:
             if (a ** flag) % p == 1:
                break
             flag += 1
          if flag == (p - 1):
             list.append(a)
          a += 1
       return list
    #得到交换计算数后的密钥
    def get_key(X, Y, p):
       key = (Y ** X) % p
       return key
    def Server(x):
        # 创建一个socket对象
        socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        host = "127.0.0.1"
        port = 8088
        # 绑定地址
        socket_server.bind((host, port))
        # 设置监听
        socket_server.listen(5)
        client_socket, address = socket_server.accept()
        # 接收客户端的请求
        recvmsg = client_socket.recv(1024)
        # 把接收到的数据进行解码
        strData = recvmsg.decode("utf-8")
        print("接收到来自客户端的数据: %s" % strData)
        msg = x
        # 发送数据,需要进行编码
        client_socket.send(str(msg).encode("utf-8"))
        # 关闭服务器端
        socket_server.close()
        return recvmsg
    if __name__ == "__main__":
        print("这里是服务端!")
        print("-"*20)
        p = 23
        list = get_generator(p)
        #得到B的私钥
        XB = random.randint(0, p-1)
        # 得到B的计算数
        YB = get_calculation(p, int(list[-1]), XB)
        #交换计算数
        YA = int(Server(YB))
        #交换后B的密钥
        key_B = get_key(XB, YA, p)
        print('服务端的生成密钥为:%d' % key_B)
        print("正在发送密钥至客户端比对...")
        judge_op = int(Server(key_B))
        if judge_op == key_B:
            print("比对成功,密钥相同!")

    改进建议:

    (1)客户端和服务端的公共大素数p,ip地址以及端口号可以改进为可输入;

    (2)可以设计GUI界面使程序更加美观,并对客户端与服务端连接状态做提示显示。