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

如何用Crypto++验证Python生成的RSA签名及问题排查

RSA跨语言签名验证失败排查与修复

问题背景

我用Python实现服务端、C实现客户端的RSA签名验证流程:Python服务端持RSA私钥,C客户端持配对公钥。客户端发送字符串到服务端,服务端用私钥生成ASCII格式签名返回,客户端需验证签名的合法性(来自配对密钥、基于目标字符串生成)。但现有代码始终返回false,Crypto++调试难度大,确定只需调整参数即可修复,求问题点。


原始代码与问题点

原始Python服务端代码

import rsa
from base64 import b64encode

str = "message"

pub, priv = rsa.newkeys(2048)

# 注:此处存在笔误,privkey应为priv
keyB64 = rsa.sign(str.encode('utf-8'), privkey, 'SHA-1')    
signature = b64encode(keyB64).decode('ascii')

with open("public_key.txt", "w") as file:
        file.write(pub.save_pkcs1().decode('utf8'))
        file.close()

生成的PKCS#1格式公钥示例

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALqrXqb17/TiXmGGbvbFwRMV+mbCqPtvnD0zlvIKxpJ4NSBVZ2Lz87SU
Ww69uFILy19G6prThJAzHha9pa3fWRKRv5epMXcP6TFZ3er0h0uaxOKxle+OtpnC
xyW+QMzkhuDL1gR1OrgVW6jCV6lmVdca63+m2PfTjQj1Vc64OyWBAgMBAAE=
-----END RSA PUBLIC KEY-----

原始C++客户端验证代码

#include <./Cryptopp/rsa.h>
#include <./Cryptopp/hex.h>
#include <./Cryptopp/pssr.h>

inline bool RsaVerifyString(const std::string &aPublicKeyStrASCII,
                            const std::string &str,
                            const std::string &aSignatureStrASCII)
{

  // decode and load public key (using pipeline)
  CryptoPP::RSA::PublicKey publicKey;
  publicKey.Load(CryptoPP::StringSource(aPublicKeyStrASCII, true).Ref());

  // decode signature
  std::string decodedSignature;
  CryptoPP::StringSource ss(aSignatureStrASCII, true);

  // verify message
  bool result = false;
  CryptoPP::RSASS<CryptoPP::PSSR, CryptoPP::SHA1>::Verifier verifier(publicKey);
  CryptoPP::StringSource ss2(decodedSignature + str, true,
                             new CryptoPP::SignatureVerificationFilter(verifier,
                               new CryptoPP::ArraySink((unsigned char*)&result,
                                                       sizeof(result))));

  return result;
}

//...

std::string message("message");

if(RsaVerifyString(publicKeyASCII, message, signatureASCII))
{
    std::cout << "OK" << std::endl;
}

原始代码核心错误点

  1. Python代码笔误:rsa.sign的第二个参数是privkey,但生成的私钥变量是priv,直接运行会报错。
  2. 签名解码缺失:Python用Base64编码签名,但C++代码未添加Base64Decoder,导致decodedSignature为空。
  3. 验证输入逻辑错误:Crypto++的SignatureVerificationFilter需要单独传入消息和签名,而非拼接两者。正确流程是先输入消息,再通过过滤器验证签名。
  4. 公钥加载方式错误:Python生成的是PKCS#1格式公钥,Crypto++直接调用Load无法正确解析,需用PEM_Load结合StringSource加载。

更新尝试:迁移到PyCryptoDome后的问题

更新后的Python服务端代码(PyCryptoDome)

from Crypto import Random
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

PRIV_PATH = '../priv.pem'
PUB_PATH= '../pub.pem'


def gen_key_pair():
    random_generator = Random.new().read
    key = RSA.generate(2048, random_generator)
    print(key.exportKey(), key.publickey().exportKey())
    with open(PRIV_PATH, 'wb') as file:
        file.write(key.exportKey())
    with open(PUB_PATH, 'wb') as file:
        file.write(key.publickey().exportKey())
    return key.exportKey(), key.publickey().exportKey()


def sign_message(message):
    key = RSA.importKey(open(PRIV_PATH, 'rb').read())
    h = SHA.new(message)
    signer = PKCS1_v1_5.new(key)
    signature = signer.sign(h)
    return signature


def verify_sign(message, signature):
    key = RSA.importKey(open(PUB_PATH, 'rb').read())
    h = SHA.new(message)
    verifier = PKCS1_v1_5.new(key)
    if verifier.verify(h, signature):
       print("The signature is authentic.")
    else:
       print("The signature is not authentic.")
       
# TEST CRYPTO
gen_key_pair()
message = 'Hello pycrypto!'.encode('utf-8')
signature = sign_message(message).hex()
print('signature='+signature)
verify_sign(message, bytes.fromhex(signature))

预计修改后的C++客户端代码(未整理)

inline bool RsaVerifyString(const std::string &aPublicKeyStrASCII,
                            const std::string &str,
                            const std::string &aSignatureStrASCII)
{

  // decode and load public key (using pipeline)
  CryptoPP::RSA::PublicKey publicKey;
  publicKey.Load(CryptoPP::StringSource(aPublicKeyStrASCII, true).Ref());

  // decode signature
  std::string decodedSignature;
  CryptoPP::StringSource ss(aSignatureStrASCII, true);

  // verify message
  bool result = false;
  CryptoPP::RSASS<CryptoPP::PKCS1v15, CryptoPP::SHA256>::Verifier verifier(publicKey);
  CryptoPP::StringSource ss2(decodedSignature + str, true,
                             new CryptoPP::SignatureVerificationFilter(verifier,
                               new CryptoPP::ArraySink((unsigned char*)&result,
                                                       sizeof(result))));

  return result;
}

更新后代码的潜在问题

  1. 哈希算法不匹配:Python用SHA-1(Crypto.Hash.SHA对应SHA-1),但C++代码中用了SHA256,两者必须一致。
  2. 签名编码方式不匹配:Python将签名转为Hex字符串,但C++代码未做Hex解码,直接处理ASCII字符串。
  3. 仍存在原始代码的验证逻辑错误:拼接签名和消息的方式依然错误,公钥加载方式也未修正。

修复后的C++客户端代码示例

#include <./Cryptopp/rsa.h>
#include <./Cryptopp/hex.h>
#include <./Cryptopp/base64.h>
#include <./Cryptopp/pssr.h>
#include <./Cryptopp/pem.h>

inline bool RsaVerifyString(const std::string &aPublicKeyStrASCII,
                            const std::string &str,
                            const std::string &aSignatureStrASCII)
{
    // 加载PKCS#1格式公钥
    CryptoPP::RSA::PublicKey publicKey;
    CryptoPP::StringSource pubKeySource(aPublicKeyStrASCII, true);
    CryptoPP::PEM_Load(pubKeySource, publicKey);

    // 解码Base64格式签名(如果用Hex则替换为HexDecoder)
    std::string decodedSignature;
    CryptoPP::StringSource ss(aSignatureStrASCII, true,
        new CryptoPP::Base64Decoder(
            new CryptoPP::StringSink(decodedSignature)
        )
    );

    // 初始化验证器:对应Python rsa库的PSS填充+SHA1,或PyCryptoDome的PKCS1_v1_5+SHA1
    // 如果用PyCryptoDome的PKCS1_v1_5,替换为RSASS<PKCS1v15, SHA1>::Verifier
    CryptoPP::RSASS<CryptoPP::PSSR, CryptoPP::SHA1>::Verifier verifier(publicKey);

    bool result = false;
    // 正确的验证流程:先输入消息,再通过过滤器验证签名
    CryptoPP::StringSource ss2(str, true,
        new CryptoPP::SignatureVerificationFilter(
            verifier,
            new CryptoPP::ArraySink(reinterpret_cast<unsigned char*>(&result), sizeof(result)),
            CryptoPP::SignatureVerificationFilter::PUT_RESULT | CryptoPP::SignatureVerificationFilter::SIGNATURE_AT_END
        )
    );
    // 写入签名到过滤器
    ss2.Put(reinterpret_cast<const unsigned char*>(decodedSignature.data()), decodedSignature.size());
    ss2.MessageEnd();

    return result;
}

内容的提问来源于stack exchange,提问作者user325962

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:30:45