[翻译]加密聊天室:第二部分
(前段时间忙于毕业,接手了这篇翻译一直就搁在那,今天逛论坛发现组内小姐姐已经将第一部分翻译出来,阅读之后觉得这个工程量不大加之作者的构思很是清晰,可以锻炼一下自己的Python代码能力,并且其中的关于DH的操作考虑的还是非常周到的,故翻译出来供大家阅读学习)
原文https://0x00sec.org/t/encrypted-chat-part-ii/5958
欢迎回来
在了解加密聊天服务器背后的概念之后,我们已经做好准备来近距离的查看代码来理解服务器和客户端是怎样操作的
第二部分:代码
下面是本次加密聊天项目的文件组成:
File Description Category ---------------------------------------------------------------- client.py Chat Client Networking server.py Chat Server Networking, Control dhke.py Diffie-Hellman Key Exchange Crypto cipher.py AES Encryption and Decryption Crypto cli.py Command-Line Interface Interface
服务端和客户端公用许多的代码,特别是关于消息加密解密的代码。然而,由于是服务端进行大部分的处理,我们将会从服务端的代码开始。
这里我只会讨论关键的代码,而省略一些琐碎的代码。完整的代码可以在这里找到。
服务器代码- 密钥交换
# Inside Server Class
def __init__(self, host='127.0.0.1', port=DEFAULT_PORT):
...
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.dh_params = M2DH.gen_params(DH_SIZE, 2)
...
首先我们创建一个服务端用来交互的套接字:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
接着,使用m2crypto里的DH模块我们生成一个用来做DH秘钥交换的参数:
self.dh_params = M2DH.gen_params(DH_SIZE, 2)
请记住,我们需要创建两个公共值:素数模p和素数基g。当我们指定所需素数的大小(以位为单位)(建议公钥素数至少为2048位)以及我们想要使用哪个生成器时,此函数返回包含p和g的类。它使用OpenSSL库,“是用于传输层安全性(TLS)和安全套接字层(SSL)协议,商业级的的强大全功能工具包”以及“通用加密库”。许多其他程序使用此库,例如OpenVPN。
现在我们可以等待新客户端连接,当有连接尝试时使用Diffie-Hellman密钥交换并监听其传入的加密消息。
while True:
connection, address = self.socket.accept()
client = Client(self, connection, address)
...
self.clients.append(client)
...
threading.Thread(target=self.listen, args=(client, )).start()
我们使用套接字接受下一个传入连接(此功能阻塞)并将其初始化为新客户端。 让我们来看看这样做时会发生什么:
# Inside Client Class (this is the client object the server uses)
def __init__(self, server, connection, address):
...
self.key = self.dh(server.dh_params)
客户端类接收服务器(客户端所属的服务器),套接字连接和格式(ip_address,port)的地址。然后调用dh()来生成共享密钥。
# Inside Client Class
def dh(self, dh_params):
"""
Perform Diffie-Hellman Key Exchange with a client.
:param dh_params: p and g generated by DH
:return shared_key: shared encryption key for AES
"""
# p: shared prime
p = DH.b2i(dh_params.p)
# g: primitive root modulo
g = DH.b2i(dh_params.g)
# a: randomized private key
a = DH.gen_private_key()
# Generate public key from p, g, and a
public_key = DH.gen_public_key(g, a, p)
# Create a DH message to send to client as bytes
dh_message = bytes(DH(p, g, public_key))
self.connection.sendall(dh_message)
# Receive public key from client as bytes
try:
response = self.connection.recv(LEN_PK)
except ConnectionError:
print("Key Exchange with {} failed".format(self.address[0]))
return None
client_key = DH.b2i(response)
# Calculate shared key with newly received client key
shared_key = DH.get_shared_key(client_key, a, p)
return shared_key
首先,使用位于dhke.py中的DH.b2i方法将p和g参数从字节转换为整数。然后它生成一个随机私钥a(也是一个整数)。此交换的服务器公钥是通过将g增加到a的幂并使用DH.gen_public_key()将结果取模p来计算。
def gen_public_key(g, private, p):
# g^private % p
return pow(g, private, p)
现在,它可以使用值p,g和public_key来构造要发送到客户端的公共消息。
注意:上传附件及图片大小不得大于30M。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
