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

如何用OpenSSL C++验证PyCryptoDome生成的RSA签名?

OpenSSL验证PyCryptoDome签名失败的问题排查与解决

问题背景

使用PyCryptoDome生成RSA签名,在C中用OpenSSL验证始终失败。公钥已确认有效(用同一私钥在C端签名可验证通过),怀疑问题出在签名格式或编解码流程上。

Python生成签名代码

from Crypto import Random
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
import base64

RSA_BITS = 2048

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

def gen_key_pair():
    random_generator = Random.new().read
    key = RSA.generate(RSA_BITS, random_generator)
    
    priv = key.exportKey()
    pub = str(key.publickey().exportKey())  # 此处存在潜在格式问题
    
    with open(PRIV_PATH, 'wb') as file:
        file.write(priv)
    with open(PUB_PATH, 'w') as file:
        file.write(pub)
    
    print("Public key: "+pub+'\n')

def sign_message(message):
    key = RSA.importKey(open(PRIV_PATH, 'rb').read())
    signer = PKCS1_v1_5.new(key)
    h = SHA256.new(message.encode('ascii'))
    
    print('Signature: '+base64.b64encode(signer.sign(h)).decode('ascii'))

gen_key_pair()
sign_message('hello')

C++验证核心代码(问题集中在Base64解码)

#include <iostream>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <QCoreApplication>

std::string PUBLIC_KEY ="-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1dwgfS3AciOd1yZ2U1HY\n0/sneN6ciARRzKtgHz7EOymoFANuF8MpYWNx8l+SqUfr/Ii2bAOC+94L3hD4Dqw3\nfwDH8vDOjOvCEzgrMdAXZ+Nv8cwRmVlYW8qu5OqXaN7Dv1Scf9vBtCSO59WJ2V4l\nk3VnpjrBqpjJAfW+JNIqsWXBLErOkTtcljBxBADXFVQIBCyTz3QbN+UP7g0eoBQI\n8x8tzmHg7L5vM36Iepn3EIdBBWD942CfqeA0emcFixBtAD7wsg96f9e2Z1tBLskN\nJHRNLgAX50OSuZzMebC9aWV0Z2VhyfCiZIfugODe6X8CXNNTzMqa10eGtXx65kcn\nvwIDAQAB\n-----END PUBLIC KEY-----\n";
std::string SIGNATURE = "a+lpWth2RQG21cODvF0SNtpHuQZKPzCB1geo67EywOPtR2bYVkAcQ99+a8thmzfosXgRVQWjCMDnGJmSwnQUywhMxahZri0WRp/NhEEBrbXV1BxGZcL6uhfGJ4aAds9vWO+fIrE86rUQI9YZlU3griq1DRrzgsRWMviMwflqTskY1F85FpmcCLD1UCMJ9pYHYtRCsHBtNX4PnqR5dzfhkSSmVruOXyV0h4foK/m4+Ad2Xkz8VYZxVjq/64k2vqSuPPBhv3Saizvczq4/wP5IKYUjei/UcMau2g0TUzMXzPOXrVaKsXVDGjUlil6uwYGQ3zQFUIL95rpRYCKsAf8AGQ==";
std::string MESSAGE = "hello";

// 问题函数:Base64解码
void Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) {
  BIO *bio, *b64;

  int decodeLen = calcDecodeLength(b64message);
  *buffer = (unsigned char*)malloc(decodeLen + 1);
  (*buffer)[decodeLen] = '\0';

  bio = BIO_new_mem_buf(b64message, -1);
  b64 = BIO_new(BIO_f_base64());
  bio = BIO_push(b64, bio);

  *length = BIO_read(bio, *buffer, strlen(b64message));
  BIO_free_all(bio);
}

// 省略其他辅助函数与main函数

问题根源

  1. Base64解码不兼容无换行格式:OpenSSL的BIO_f_base64默认要求Base64字符串每行64字符,而Python输出的签名是连续无换行的Base64,导致解码不完整,签名数据长度错误。
  2. Python公钥导出的格式隐患:str(key.publickey().exportKey())会将bytes对象转为带b'前缀和'后缀的字符串,复制时若误包含这些字符会导致公钥加载失败。

修复步骤

1. 修正C++的Base64解码函数

添加BIO_FLAGS_BASE64_NO_NL标志,允许解码无换行的连续Base64字符串:

void Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) {
  BIO *bio, *b64;

  int decodeLen = calcDecodeLength(b64message);
  *buffer = (unsigned char*)malloc(decodeLen + 1);
  (*buffer)[decodeLen] = '\0';

  bio = BIO_new_mem_buf(b64message, -1);
  b64 = BIO_new(BIO_f_base64());
  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); // 关键:关闭换行要求
  bio = BIO_push(b64, bio);

  *length = BIO_read(bio, *buffer, strlen(b64message));
  BIO_free_all(bio);
}

2. 修正Python的公钥导出逻辑

直接将公钥bytes解码为ASCII字符串,避免生成带b'的格式:

pub = key.publickey().exportKey().decode('ascii')  # 替换原str(...)写法

3. 验证签名复制完整性

确保从Python输出复制的签名是完整的,没有截断或多余字符(如空格、换行)。

4. 可选:添加错误日志定位问题

在OpenSSL调用失败的分支添加错误打印,方便排查:

#include <openssl/err.h>

// 在EVP_DigestVerifyInit等失败后添加
ERR_print_errors_fp(stderr);

验证结果

修改后重新生成公钥和签名,复制到C++代码中编译运行,即可成功验证签名,输出"Authentic"。

内容的提问来源于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 17:15:45