Python 通过 UDP 在一条消息中发送字符串和字节
在此程序中,我尝试通过 UDP 广播向客户端发送密钥共享。我面临的问题是将字符串和字节编码为一条消息,会产生许多错误。
我想从服务器向客户端发送一个随机 ID 和一个密钥共享,其中包括索引(整数)和共享(16 字节字符串)。我在 id、index 和 share 之间添加了“:”,以便稍后能够在客户端进行管理(通过将消息拆分为多个部分)。
我尝试过将所有内容都转换为字符串,例如: message = (str(id) + ":" + str(index) + ":").encode('utf-16') + str(share, 'utf-16')
。但这会导致客户端的密钥重建出现问题,其中密钥共享应该是字节字符串,它看起来像 b"b'\xff\xfej\xb9\xdb\x8c&\x7f\x06\x87\x98Ig \xfc\x1eJ\xf6\xb5'"
。
然后我尝试将 id 和索引编码为 utf-16 并向客户端发送消息,然后对其进行解码,但这不允许我重建密钥,并且出现错误: ValueError: 编码值必须是整数或 16 字节字符串
。
当我在客户端解码时,数据如下所示:f91f7e52-865d-49bc-bb45-ad80255e9ef9:5:륪赞缦蚬䦘ﱧ䨞뗶
。然而,有些共享在解码后不包含分隔符,因此无法拆分。
有没有一种方法可以让服务器在一条消息中发送所有以下数据(id、index、share),以便在客户端正确区分它们?
服务器所需的输出为(id = string,index = int,share = 16 字节字符串):
id = f91f7e52-865d-49bc-bb45-ad80255e9ef9
index = 5
share = b'\xff\xfej\xb9\xdb\x8c&\x7f\x06\x87\x98Ig\xfc\x1eJ\xf6\xb5'
Server.py
from socket import *
import socket
import time
import uuid
from Crypto.Random import get_random_bytes
from Crypto.Protocol.SecretSharing import Shamir
server = socket.socket(AF_INET, SOCK_DGRAM)
server.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
server.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
id = uuid.uuid4()
# generate 16-byte key
key = get_random_bytes(16)
# prepare k chunks of key
shares = Shamir.split(3, 5, key)
while True:
for index, share in shares:
message = (str(id) + ":" + str(index) + ":").encode('utf-16') + share
# send bytes
server.sendto(message, ('<broadcast>', 37020))
print("message sent!")
time.sleep(1)
Client.py
from socket import *
from Crypto.Protocol.SecretSharing import Shamir
audienceSocket = socket(AF_INET, SOCK_DGRAM)
audienceSocket.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
audienceSocket.bind(('', 37020))
receivedShares = {}
reconstruct = []
while True:
# get data from sender
data, address = audienceSocket.recvfrom(1024)
decoded = data.decode('utf-16')
print("Decoded:", decoded)
id, index = decoded.split(":", 1)
index, share = index.split(":", 1)
share = share.encode('utf-16')
print(id)
print(index)
print(share)
if id not in receivedShares:
receivedShares[id] = set()
receivedShares[id].add((index, share))
print(receivedShares)
for shares in receivedShares:
if len(shares) >= 3:
for share in shares:
reconstruct.append(share)
# reconstrcut the key
key = Shamir.combine(reconstruct)
print("The key is:", key)
In this program I am trying to send key shares though UDP broadcast to the client(s). The issue I'm facing is with encoding of strings and bytes into one message, there are number of errors are produced.
I would like to send from the server to the client a random ID and a key share, which include index (integer) and share (16-bytes string). I have added ":" between id, index and share to be able to manage it at the client later (by splitting the message into parts).
I have tried converting everything into string, such as:message = (str(id) + ":" + str(index) + ":").encode('utf-16') + str(share, 'utf-16')
. But this causing issues in key reconstruction at the client, where the key share should be a byte string and it looks like b"b'\xff\xfej\xb9\xdb\x8c&\x7f\x06\x87\x98Ig\xfc\x1eJ\xf6\xb5'"
.
Then I have tried encoding id and index to utf-16 and sending a message to the client, and then decode it, but this does not let me reconstruct the key and I'm getting an error: ValueError: The encoded value must be an integer or a 16 byte string
.
When I decode at the client, the data looks like this: f91f7e52-865d-49bc-bb45-ad80255e9ef9:5:륪賛缦蜆䦘ﱧ䨞뗶
. However, some shares after decoding do not contain dilimiter and thus not being able to split.
Is there a way the server can send all the following data in one message (id, index, share), so that it can be separated correctly at the client?
The desired output at server would be (id = string, index = int, share = 16-byte string):
id = f91f7e52-865d-49bc-bb45-ad80255e9ef9
index = 5
share = b'\xff\xfej\xb9\xdb\x8c&\x7f\x06\x87\x98Ig\xfc\x1eJ\xf6\xb5'
Server.py
from socket import *
import socket
import time
import uuid
from Crypto.Random import get_random_bytes
from Crypto.Protocol.SecretSharing import Shamir
server = socket.socket(AF_INET, SOCK_DGRAM)
server.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
server.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
id = uuid.uuid4()
# generate 16-byte key
key = get_random_bytes(16)
# prepare k chunks of key
shares = Shamir.split(3, 5, key)
while True:
for index, share in shares:
message = (str(id) + ":" + str(index) + ":").encode('utf-16') + share
# send bytes
server.sendto(message, ('<broadcast>', 37020))
print("message sent!")
time.sleep(1)
Client.py
from socket import *
from Crypto.Protocol.SecretSharing import Shamir
audienceSocket = socket(AF_INET, SOCK_DGRAM)
audienceSocket.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
audienceSocket.bind(('', 37020))
receivedShares = {}
reconstruct = []
while True:
# get data from sender
data, address = audienceSocket.recvfrom(1024)
decoded = data.decode('utf-16')
print("Decoded:", decoded)
id, index = decoded.split(":", 1)
index, share = index.split(":", 1)
share = share.encode('utf-16')
print(id)
print(index)
print(share)
if id not in receivedShares:
receivedShares[id] = set()
receivedShares[id].add((index, share))
print(receivedShares)
for shares in receivedShares:
if len(shares) >= 3:
for share in shares:
reconstruct.append(share)
# reconstrcut the key
key = Shamir.combine(reconstruct)
print("The key is:", key)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
UUID可以被编码为16字节值,例如4字节的整数并且
share
具有16字节的长度。因此,数据可以简单地连接而无需分隔符并按其长度分隔,例如:The UUID can be encoded as 16 bytes value, the integer e.g. as 4 bytes and and
share
has a length of 16 bytes. Therefore the data can be simply concatenated without delimiter and separated by their lengths, e.g.: