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

使用OpenSSL RSA公钥验证签名失败问题排查

问题分析与解决

你的代码核心问题是签名和验证的参数逻辑不匹配,导致验证时的哈希计算和签名时的哈希计算不一致:

错误点详解

  1. 签名阶段的错误用法
    你手动计算了数据的SHA256摘要digest,然后调用RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, ...)。但RSA_sign的第二个参数m的含义是:当指定哈希算法类型(如NID_sha256)时,m是原始数据,函数会自动对m计算对应哈希并完成签名。你传入的是已经计算好的摘要,导致RSA_sign会对这个摘要再计算一次SHA256哈希,最终签名的是“哈希的哈希”,而非原始数据的哈希。

  2. 验证阶段的正确逻辑,但和签名不匹配
    验证时你调用RSA_verify(NID_sha256, data.c_str(), data.length(), ...),这部分逻辑是对的:RSA_verify会自动对原始数据data计算SHA256哈希,然后和签名解密后的哈希对比。但因为签名的是二次哈希,自然无法匹配,导致验证失败。

修复方案

有两种修复方式,选其一即可:

方式一:让RSA_sign自动处理哈希计算(推荐)

删除手动计算SHA256的代码,直接传入原始数据给RSA_sign:

// 移除手动计算哈希的代码
// unsigned char digest[SHA256_DIGEST_LENGTH];
// SHA256(reinterpret_cast<const unsigned char*>(data.c_str()), data.length(), digest);

unsigned int signatureLength = RSA_size(encrypt_rsa_pri_key);
unsigned char* signature = new unsigned char[signatureLength];
// 直接传入原始数据和长度,RSA_sign会自动计算SHA256哈希
int result = RSA_sign(NID_sha256, reinterpret_cast<const unsigned char*>(data.c_str()), data.length(), signature, &signatureLength, encrypt_rsa_pri_key);
std::string retStr(signature, signature + signatureLength);
// 验证逻辑保持不变
result = RSA_verify(NID_sha256, reinterpret_cast<const unsigned char*>(data.c_str()), data.length(), signature, signatureLength, encrypt_rsa_pub_key);
// 记得释放内存
delete[] signature;

方式二:手动计算哈希,直接签名摘要(需处理ASN.1封装)

如果你必须手动计算哈希,需要将摘要封装成RSA签名要求的ASN.1结构,再进行签名:

unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(data.c_str()), data.length(), digest);

// 封装SHA256摘要的ASN.1结构(RSA签名验证会期望这个标准结构)
unsigned char digest_with_asn1[64];
const unsigned char sha256_asn1_prefix[] = {0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
int prefix_len = sizeof(sha256_asn1_prefix);
memcpy(digest_with_asn1, sha256_asn1_prefix, prefix_len);
memcpy(digest_with_asn1 + prefix_len, digest, SHA256_DIGEST_LENGTH);
int digest_total_len = prefix_len + SHA256_DIGEST_LENGTH;

unsigned int signatureLength = RSA_size(encrypt_rsa_pri_key);
unsigned char* signature = new unsigned char[signatureLength];
// 直接对封装后的摘要进行签名
int result = RSA_sign(NID_undef, digest_with_asn1, digest_total_len, signature, &signatureLength, encrypt_rsa_pri_key);
std::string retStr(signature, signature + signatureLength);
// 验证逻辑保持不变
result = RSA_verify(NID_sha256, reinterpret_cast<const unsigned char*>(data.c_str()), data.length(), signature, signatureLength, encrypt_rsa_pub_key);
// 记得释放内存
delete[] signature;

额外注意事项

  • 必须释放signature指向的内存,避免内存泄漏。
  • 你的公钥XOR解密逻辑需确保解密后的内容是完整正确的PEM格式,虽然BN_cmp返回0说明公钥加载正确,仍建议临时输出解密后的公钥内容,确认和注释中的PEM一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 13:37:01