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

使用BouncyCastle验证XML签名时遇block incorrect异常求助

问题:XML数字签名验证时BouncyCastle抛出"block incorrect"异常

我正在做一个验证XML文档数字签名的项目,文档结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<XMLReport>
   <INNER_CONTENT>----content----</INNER_CONTENT>
   <Signature>
      <SIGNALGO>SHA512</SIGNALGO>
      <KeyInfo>3082010A0282010100D8F165280...........</KeyInfo>
      <SignatureValue>{data}</SignatureValue>
      <HASH>{data}</HASH>
   </Signature>
</XMLReport>

我尝试用KeyInfo字段构造的公钥解密SignatureValue,使用BouncyCastle库时抛出了如下异常:

Org.BouncyCastle.Crypto.InvalidCipherTextException: 'block incorrect'

错误出现在这行代码:

var decryptedBytes = decryptEngine.ProcessBlock(Encoding.GetEncoding(1256).GetBytes(segment), 0, segment.Length);

相关解密方法代码如下:

public static string RsaDecryptWithPublic(string encryptedData, string publicKey) {
  var decryptedResult = string.Empty;
  try {
    Int32 EncryptedLength = 256;
    int len = encryptedData.Length;
    var length = len / EncryptedLength;

    var decryptEngine = new Pkcs1Encoding(new RsaEngine());

    using(var txtreader = new StringReader(publicKey)) {
      var keyParameter = (AsymmetricKeyParameter) new PemReader(txtreader).ReadObject();

      decryptEngine.Init(false, keyParameter);
    }

    var sb = new StringBuilder();

    string resultData = "";

    for (var i = 0; i < length; i++) {
      string segment = encryptedData.Substring(i * EncryptedLength, EncryptedLength);
      try {
        var decryptedBytes = decryptEngine.ProcessBlock(Encoding.GetEncoding(1256).GetBytes(segment), 0, segment.Length);
        resultData = Encoding.GetEncoding(1256).GetString(decryptedBytes);
      } catch (Exception GenEx) {
        string error = GenEx.Message;
      }

      sb.Append(resultData);
    }
    decryptedResult = sb.ToString();
  } catch (Exception ex) {

  }
  return decryptedResult;
}

我的处理方式是不是错了?求帮忙解决。


分析与解决方案

你的代码存在几个核心问题,直接导致了"block incorrect"异常:

  1. 数字签名逻辑完全错误

    • 数字签名验证不是用公钥解密签名值,而是用公钥验证签名有效性:签名是私钥对原始数据哈希值加密生成的,验证时需要用公钥解析签名得到哈希值,再和原始数据计算的哈希值比对。你把签名值当成加密数据处理,逻辑完全颠倒。
    • SignatureValue是Base64编码的二进制数据,你直接用编码1256转字节是错误的,必须先做Base64解码。
  2. 公钥加载方式错误

    • KeyInfo字段是DER格式的公钥(开头的3082是DER编码标识),但你用PemReader读取——这个类是用来处理带-----BEGIN PUBLIC KEY-----头的PEM格式公钥的,直接读DER格式会导致密钥参数无效,进而引发解密异常。
  3. 分段处理逻辑错误

    • RSA的块处理是针对二进制数据的,你按256个字符分段再转字节,完全不符合RSA的块长度规则,必然导致块长度错误。

修正步骤:

1. 正确加载DER格式公钥

将KeyInfo的十六进制字符串转成字节数组,再解析为RSA公钥参数:

// 把KeyInfo的十六进制字符串转字节数组
byte[] keyBytes = Hex.Decode(publicKeyHex);
AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyBytes);

2. 正确处理SignatureValue

SignatureValue是Base64编码的签名数据,先解码为字节数组:

byte[] signatureBytes = Convert.FromBase64String(signatureValue);

3. 使用正确的签名验证逻辑

用SignerUtilities创建对应算法的验证器,结合原始内容做验证,替代错误的解密逻辑:

public static bool VerifyXmlSignature(string innerContent, string signatureValue, string publicKeyHex)
{
    try
    {
        // 解析DER格式公钥
        byte[] keyBytes = Hex.Decode(publicKeyHex);
        AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyBytes);

        // 初始化SHA512withRSA签名验证器
        ISigner signer = SignerUtilities.GetSigner("SHA512withRSA");
        signer.Init(false, publicKey);

        // 传入原始内容字节
        byte[] contentBytes = Encoding.UTF8.GetBytes(innerContent);
        signer.BlockUpdate(contentBytes, 0, contentBytes.Length);

        // 验证签名
        byte[] signatureBytes = Convert.FromBase64String(signatureValue);
        return signer.VerifySignature(signatureBytes);
    }
    catch (Exception)
    {
        return false;
    }
}

4. 丢弃错误的解密方法

直接删除原来的RsaDecryptWithPublic方法,它完全不符合数字签名验证的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 05:05:36