本次实验要求是基于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界面使程序更加美观,并对客户端与服务端连接状态做提示显示。