如何通过Socket发送元组类型RSA签名?解决TypeError报错
解决Socket发送RSA签名(元组类型)的TypeError问题
我一眼就揪出问题根源了:你用pri_key.sign()生成的signature是个元组(格式类似(b'\x01\x02...',)),但Python Socket的send()方法只接受字符串或字节缓冲区类型的参数,直接传元组必然触发报错。下面给你两种实用的解决思路,还有修正后的完整代码:
方法一:提取元组中的字节数据直接发送
RSA.sign()返回的元组里,第一个元素就是实际的签名字节内容,直接提取这个元素发送是最简单直接的方案:
修正后的客户端代码
from Crypto.PublicKey import RSA from Crypto import Random import socket import hashlib random_generator = Random.new().read private_key = RSA.generate(1024, random_generator) # 保留你原来的硬编码密钥写法 pri_key_str = """-----BEGIN RSA PRIVATE KEY----- blah balh~ -----END RSA PRIVATE KEY-----""" pri_key = RSA.importKey(pri_key_str) filename = 'a.txt' blocksize = 65536 def hashvalue(filename): # 计算文件SHA256哈希的十六进制字符串 hash = hashlib.sha256() with open(filename, "rb") as f: for block in iter(lambda: f.read(blocksize), b""): hash.update(block) return hash.hexdigest() file_hash = hashvalue(filename) print(file_hash) # 生成签名并提取元组内的字节数据 signature = pri_key.sign(file_hash, '')[0] print(signature) # 本地验证签名(可选,确认签名有效性) public_key = private_key.publickey() pub_key_str = """-----BEGIN PUBLIC KEY----- blah blah~ -----END PUBLIC KEY-----""" pub_key = RSA.importKey(pub_key_str) if pub_key.verify(file_hash, (signature,)): print("The signature is authentic (local check)") else: print("The signature is not authentic (local check)") # Socket发送逻辑 HOST = '127.0.0.1' PORT = 7777 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((HOST, PORT)) # 哈希值转字节发送(Python3需encode,Python2可直接发送) client.send(file_hash.encode('utf-8')) # 发送签名字节数据 client.send(signature) client.close() # 记得关闭连接
修正后的服务器端代码
from Crypto.PublicKey import RSA import socket pub_key_str = """-----BEGIN PUBLIC KEY----- blah blah~ -----END PUBLIC KEY-----""" pub_key = RSA.importKey(pub_key_str) HOST = '127.0.0.1' PORT = 7777 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((HOST, PORT)) server.listen(10) client, addr = server.accept() # SHA256哈希的十六进制字符串固定64字符,接收64字节足够 hashv = client.recv(64).decode('utf-8') # Python3需解码为字符串 print("receive data ( hash ): ", hashv) # 1024位RSA签名固定128字节,接收128字节 signature = client.recv(128) print("recv signature (type: bytes): ", signature) # 验证时需把签名重新包装为元组,匹配verify方法的参数格式 if pub_key.verify(hashv, (signature,)): print("The signature is authentic") else: print("The signature is not authentic") client.close() server.close()
方法二:用序列化工具打包元组(适合复杂数据场景)
如果后续需要发送更复杂的数据结构(比如多个元组、自定义对象),可以用pickle序列化后发送(注意:pickle存在安全风险,仅在可信的客户端与服务器之间使用):
客户端发送部分修改
import pickle # 序列化签名元组 serialized_signature = pickle.dumps(signature) client.send(serialized_signature)
服务器端接收部分修改
import pickle # 反序列化还原原元组 signature = pickle.loads(client.recv(1024)) # 直接用还原后的元组验证 if pub_key.verify(hashv, signature): print("The signature is authentic")
额外注意事项
- Python2与Python3的字符串/字节处理有差异:Python3必须明确用
encode()将字符串转字节,decode()将字节转字符串;Python2则无需额外处理。 - 确保接收字节长度足够:比如SHA256哈希的十六进制字符串是64字符,
recv(64)即可;1024位RSA签名是128字节,recv(128)就能完整接收。 - 服务器端原代码中
pub_key.verify(hashv,a)的a是未定义变量,需替换为接收的signature(且要包装为元组,除非用pickle序列化)。
内容的提问来源于stack exchange,提问作者ohohoh
相关产品推荐
相关产品推荐

