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

C# RSA签名验证失败但Java验证成功,寻求解决方案

RSA签名验证:Java成功但C#失败的解决方法

我遇到了仅通过提供摘要在C#中验证RSA签名失败的问题,对应的Java代码能正常返回true,但C#代码始终返回false。

Java验证代码(成功返回true)

String certificateBase64 = "MIIC6jCCAdKgAwI...";
String signatureValueBase64 = "d0rLeNX+sQCZ3io0ji6j0P2M4bpGYxA+WKS6KkP4GYDxm4qrfhnvrKUOqvDmXNT3kNhv8I6Se6T4TFqJmYPTTQ8O914nDNmqASlknii6EA4ALExVhXfuZ7BeVNZy33AacBF8K/GIYH9DyvtWz9lVFaIX4BV9176CHo2FdSYXfNnrpJWQBIlpEhnsVHThCAabF/AOM/G2vgr5yO2Etbz3VCyZJesBOEmqRl6VlndFXZBgR527zknrH5fnACYrDacVXnFFY1OYGhaRI7tZrOvgkELnXV55aYhShWjAVcrGxaTC6vCHx3Ou4bsbjSCs4PXNMaaPcHUKH99xXODHFnMOjA==";
String hashBase64 = "MDEwDQYJYIZIAWUDBAIBBQAEIGlE+Lr0y76nMOdxNLu1k5g4l3feoWU4MYZm8yo0N5vE";

Base64.Decoder decoder = Base64.getDecoder();

CertificateFactory x509Factory = CertificateFactory.getInstance("X509");
X509Certificate x509Cert;
try (ByteArrayInputStream bais = new ByteArrayInputStream(decoder.decode(certificateBase64))) {
    x509Cert = (X509Certificate) x509Factory.generateCertificate(bais);
}

Signature signature = Signature.getInstance("NONEwithRSA");
signature.initVerify(x509Cert.getPublicKey());
signature.update(decoder.decode(hashBase64));

boolean valid = signature.verify(decoder.decode(signatureValueBase64));
System.out.println(valid);

C#验证代码(原代码返回false)

string certificateBase64 = "MIIC6jCCAdKgAwI...";
string signatureValueBase64 = "d0rLeNX+sQCZ3io0ji6j0P2M4bpGYxA+WKS6KkP4GYDxm4qrfhnvrKUOqvDmXNT3kNhv8I6Se6T4TFqJmYPTTQ8O914nDNmqASlknii6EA4ALExVhXfuZ7BeVNZy33AacBF8K/GIYH9DyvtWz9lVFaIX4BV9176CHo2FdSYXfNnrpJWQBIlpEhnsVHThCAabF/AOM/G2vgr5yO2Etbz3VCyZJesBOEmqRl6VlndFXZBgR527zknrH5fnACYrDacVXnFFY1OYGhaRI7tZrOvgkELnXV55aYhShWjAVcrGxaTC6vCHx3Ou4bsbjSCs4PXNMaaPcHUKH99xXODHFnMOjA==";
string hashBase64 = "MDEwDQYJYIZIAWUDBAIBBQAEIGlE+Lr0y76nMOdxNLu1k5g4l3feoWU4MYZm8yo0N5vE";

byte[] certificateBytes = Convert.FromBase64String(certificateBase64);
byte[] signatureValueBytes = Convert.FromBase64String(signatureValueBase64);
byte[] hashBytes = Convert.FromBase64String(hashBase64);

X509Certificate2 x509Cert = new X509Certificate2(certificateBytes);
RSA publicKey = (RSA)x509Cert.GetRSAPublicKey();

bool isValid = publicKey.VerifyHash(hashBytes, signatureValueBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    
Console.WriteLine(isValid);

问题根源

Java代码使用NONEwithRSA算法,意味着直接对原始哈希字节进行RSA PKCS#1签名,没有添加哈希算法的ASN.1标识前缀。而C#的VerifyHash方法默认会自动为传入的哈希值添加对应算法的ASN.1前缀(例如SHA256的前缀为3031300D060960864801650304020105000420),导致验证时的内容与签名生成时的原始哈希不匹配,最终返回false。

解决方法

要对齐Java的逻辑,需要手动实现无哈希前缀的RSA签名验证,以下是可行的代码:

string certificateBase64 = "MIIC6jCCAdKgAwI...";
string signatureValueBase64 = "d0rLeNX+sQCZ3io0ji6j0P2M4bpGYxA+WKS6KkP4GYDxm4qrfhnvrKUOqvDmXNT3kNhv8I6Se6T4TFqJmYPTTQ8O914nDNmqASlknii6EA4ALExVhXfuZ7BeVNZy33AacBF8K/GIYH9DyvtWz9lVFaIX4BV9176CHo2FdSYXfNnrpJWQBIlpEhnsVHThCAabF/AOM/G2vgr5yO2Etbz3VCyZJesBOEmqRl6VlndFXZBgR527zknrH5fnACYrDacVXnFFY1OYGhaRI7tZrOvgkELnXV55aYhShWjAVcrGxaTC6vCHx3Ou4bsbjSCs4PXNMaaPcHUKH99xXODHFnMOjA==";
string hashBase64 = "MDEwDQYJYIZIAWUDBAIBBQAEIGlE+Lr0y76nMOdxNLu1k5g4l3feoWU4MYZm8yo0N5vE";

byte[] certificateBytes = Convert.FromBase64String(certificateBase64);
byte[] signatureValueBytes = Convert.FromBase64String(signatureValueBase64);
byte[] hashBytes = Convert.FromBase64String(hashBase64);

X509Certificate2 x509Cert = new X509Certificate2(certificateBytes);
using (RSA publicKey = x509Cert.GetRSAPublicKey())
{
    // 用PKCS#1填充解密签名
    byte[] decryptedSignature = publicKey.Decrypt(signatureValueBytes, RSAEncryptionPadding.Pkcs1);
    
    // 从解密结果末尾截取与原始哈希长度一致的字节(PKCS#1填充的额外内容在头部)
    byte[] extractedHash = decryptedSignature.Skip(decryptedSignature.Length - hashBytes.Length).ToArray();
    
    // 比对截取后的哈希与输入哈希是否一致
    bool isValid = extractedHash.SequenceEqual(hashBytes);
    Console.WriteLine(isValid);
}

代码说明

  1. 使用RSA.Decrypt方法配合RSAEncryptionPadding.Pkcs1解密签名,得到包含PKCS#1填充的原始数据。
  2. PKCS#1填充的额外字节位于数据头部,因此从解密结果末尾截取与输入哈希长度相同的字节,得到原始签名的哈希值。
  3. 比对截取后的哈希与输入哈希,判断签名是否有效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:17:35