You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:18:43