使用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"异常:
数字签名逻辑完全错误
- 数字签名验证不是用公钥解密签名值,而是用公钥验证签名有效性:签名是私钥对原始数据哈希值加密生成的,验证时需要用公钥解析签名得到哈希值,再和原始数据计算的哈希值比对。你把签名值当成加密数据处理,逻辑完全颠倒。
SignatureValue是Base64编码的二进制数据,你直接用编码1256转字节是错误的,必须先做Base64解码。
公钥加载方式错误
KeyInfo字段是DER格式的公钥(开头的3082是DER编码标识),但你用PemReader读取——这个类是用来处理带-----BEGIN PUBLIC KEY-----头的PEM格式公钥的,直接读DER格式会导致密钥参数无效,进而引发解密异常。
分段处理逻辑错误
- 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
相关产品推荐
相关产品推荐

