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

C#转Python的RSA PKCS1加密实现求助:服务器返回拒绝

C#转Python的RSA PKCS1加密实现求助:服务器返回拒绝

我正在尝试把一段C#代码转成Python,场景是服务器会下发公钥(模数modulus、指数exponent),我需要用PKCS1填充方式加密数据后发给服务器,但Python这边的加密结果总是不被服务器认可,一直返回拒绝。

原C#实现代码

using (TcpClient client = new TcpClient())
{
    await client.ConnectAsync(ip, port);
    using (NetworkStream stream = client.GetStream())
    {
        await App.SendCmdToServer(stream, "auth", this.Ver.ToString().Split('.', StringSplitOptions.None));
        
        byte[] modulus = new byte[256];
        int num2 = await stream.ReadAsync(modulus, 0, modulus.Length);
        byte[] exponent = new byte[3];
        int num3 = await stream.ReadAsync(exponent, 0, exponent.Length);
        
        this.ServerRsa = RSA.Create();
        this.ServerRsa.ImportParameters(new RSAParameters()
        {
          Modulus = modulus,
          Exponent = exponent
        });

        using (MemoryStream data = new MemoryStream())
        {
          using (BinaryWriter writer = new BinaryWriter((Stream) data))
          {
            writer.Write(string1);
            writer.Write(string2);
            await App.SendDataToServer(stream, this.ServerRsa.Encrypt(data.ToArray(), RSAEncryptionPadding.Pkcs1));
          }
        }
    }
}

我试过的Python代码

使用rsa库:

server_rsa = rsa.newkeys(2048)[0]
server_rsa.n = int.from_bytes(modulus, byteorder='big')
server_rsa.e = int.from_bytes(exponent, byteorder='big')
data = (string1 + string2).encode()
encrypted_data = rsa.encrypt(data, server_rsa)

使用pycryptodome库:

pubkey = construct((int.from_bytes(modulus, 'big'), int.from_bytes(exponent, 'big')))
cipher = PKCS1_v1_5.new(pubkey)
encrypted_data = cipher.encrypt(data)

有没有大佬知道是不是Python和C#的RSA实现有什么特殊的不兼容点?


可能的问题排查及解决方法

我来帮你梳理几个最容易踩的坑,大概率是这些地方出了问题:

  • 字符串序列化逻辑不一致(核心问题!)
    你在C#里用BinaryWriter.Write(string)写入字符串,这个方法的逻辑是:先写一个4字节小端整数表示字符串UTF-8编码后的字节长度,再写入UTF-8的字节数组。但你Python里直接把两个字符串拼接后编码,完全没模拟这个前缀长度的逻辑,导致加密的原始数据和C#版本完全不一样,服务器解密后自然识别不了。

    正确的Python写法应该模拟C#的序列化逻辑:

    import struct
    from io import BytesIO
    
    def csharp_binary_write_string(stream, s):
        # 先转UTF-8
        utf8_bytes = s.encode('utf-8')
        # 写入4字节小端整数表示字节长度
        stream.write(struct.pack('<i', len(utf8_bytes)))
        # 写入字符串字节
        stream.write(utf8_bytes)
    
    # 构造要加密的原始数据
    data_stream = BytesIO()
    csharp_binary_write_string(data_stream, string1)
    csharp_binary_write_string(data_stream, string2)
    raw_data = data_stream.getvalue()
    

    之后用这个raw_data去做加密,而不是直接拼接字符串编码。

  • 公钥导入的细节问题
    用pycryptodome的时候,你代码里的construct应该是RSA.construct,要确保导入正确的模块:

    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_v1_5
    
    # 构造公钥
    pubkey = RSA.construct((int.from_bytes(modulus, byteorder='big'), int.from_bytes(exponent, byteorder='big')))
    cipher = PKCS1_v1_5.new(pubkey)
    # 用上面构造的raw_data加密
    encrypted_data = cipher.encrypt(raw_data)
    

    另外可以验证下读取的指数是否正确:通常RSA公钥的指数是65537(也就是0x010001),你可以打印int.from_bytes(exponent, 'big')看看是不是这个值,确认公钥有没有完整读取。

  • TCP流读取的完整性问题
    C#里的ReadAsync可能不会一次性读满指定的字节数(比如网络延迟导致分包),你在Python里读取modulus和exponent的时候,要确保读满指定长度(256字节modulus、3字节exponent),不能只调用一次read()就完事。比如可以写个辅助函数:

    def read_exact(stream, length):
        buffer = b''
        while len(buffer) < length:
            chunk = stream.read(length - len(buffer))
            if not chunk:
                raise Exception("连接断开,未读取到足够数据")
            buffer += chunk
        return buffer
    
    # 读取公钥
    modulus = read_exact(stream, 256)
    exponent = read_exact(stream, 3)
    

备注:内容来源于stack exchange,提问作者Tux

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:05:28