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

手动验证SAML响应中的RSA签名遇断言失败问题求助

手动验证SAML RSA签名失败排查求助

我发现.NET的<SignedXml>组件存在问题——同一个SAML响应在Java环境中可以正常验证,但在.NET里无法通过。于是我尝试手动编写RSA签名验证代码来校验SAML响应的签名,同时用外部工具计算了<SignedInfo>元素的预期摘要用于对比。已经确认代码中的大小端转换和签名解密逻辑符合预期,但最终Debug.Assert断言还是失败了,求帮忙排查问题。

我的代码如下:

var sigString = "Xxfh0hq34DGIQibeBrNcYuU/XD0aX...IviQm/5jZK6pD9wReldSPoo=";
var sigBytes = Convert.FromBase64String(sigString).Reverse().Append<byte>(0x0).ToArray();
var s = new BigInteger(sigBytes);

var modulusString = "lg4dkGLwfAApoNtWoX...oxvjjaGfH9PzoE=";
var modulusBytes = Convert.FromBase64String(modulusString).Reverse().Append<byte>(0x0).ToArray();
var n = new BigInteger(modulusBytes);

var exponentString = "AQAB";
var exponentBytes =  Convert.FromBase64String(exponentString).Reverse().Append<byte>(0x0).ToArray();
var e = new BigInteger(exponentBytes);

var r = BigInteger.ModPow(s, e, n);

var expectedB64 = "XeHIN99Mkt5A/HswHotEndGJ6ahw/0l8jbjy92Fjsaw=";
var expected = new BigInteger(Convert.FromBase64String(expectedB64).Reverse().Append<byte>(0x0).ToArray());

var expectedHex = expected.ToString("X");
var resultHex = r.ToString("X");

//Removing pkcs1.5 padding
var actualHex = resultString.Substring(resultString.Length - expectedString.Length);


Debug.Assert(resultHex == actualHex); //Fail

关键问题点排查:

  1. 变量名拼写错误:代码中计算actualHex时使用了resultString和expectedString,但前面定义的变量是resultHex和expectedHex,这会直接导致取值错误,是断言失败的直接原因。
  2. PKCS#1.5 padding解析逻辑错误:手动截取末尾固定长度的方式不严谨,PKCS#1.5签名的padding有固定格式:开头是0x00 0x01,接着是连续的0xFF,然后是0x00分隔符,最后才是摘要内容。正确的做法是从解密后的字节数组中找到0x00分隔符,取后面的内容,而不是按长度截取。
  3. BigInteger字节序处理错误:.NET的BigInteger(byte[] value)构造函数默认按大端序解析,且会把最高位为1的字节数组解析为负数。你这里对所有字节数组做了Reverse()反转,还额外添加了0x0字节,会导致模数、指数、签名值的BigInteger实例数值完全错误。正确的做法是使用BigInteger(byte[] value, bool isUnsigned)重载,直接传入原始字节数组(RSA的模数、指数、签名都是大端存储的)。
  4. 额外添加0x0字节的问题:只有当原始字节数组最高位是0x80及以上时,才需要添加0x0字节避免BigInteger被解析为负数,但盲目添加会改变数值,导致计算错误。

修正后的示例代码:

var sigString = "Xxfh0hq34DGIQibeBrNcYuU/XD0aX...IviQm/5jZK6pD9wReldSPoo=";
var sigBytes = Convert.FromBase64String(sigString);
// 使用无符号解析,直接传入大端字节数组
var s = new BigInteger(sigBytes, isUnsigned: true);

var modulusString = "lg4dkGLwfAApoNtWoX...oxvjjaGfH9PzoE=";
var modulusBytes = Convert.FromBase64String(modulusString);
var n = new BigInteger(modulusBytes, isUnsigned: true);

var exponentString = "AQAB";
var exponentBytes = Convert.FromBase64String(exponentString);
var e = new BigInteger(exponentBytes, isUnsigned: true);

// 计算模幂,转换为大端无符号字节数组
var rBytes = s.ModPow(e, n).ToByteArray(isUnsigned: true, isBigEndian: true);

// 正确解析PKCS#1.5 padding
int separatorIndex = Array.IndexOf(rBytes, (byte)0x00);
if (separatorIndex == -1 || separatorIndex < 2 || rBytes[0] != 0x00 || rBytes[1] != 0x01)
{
    throw new InvalidOperationException("无效的PKCS#1.5签名填充");
}
// 截取分隔符后的摘要内容
var actualDigestBytes = rBytes[(separatorIndex + 1)..];

var expectedB64 = "XeHIN99Mkt5A/HswHotEndGJ6ahw/0l8jbjy92Fjsaw=";
var expectedDigestBytes = Convert.FromBase64String(expectedB64);

// 直接对比字节数组,避免Hex字符串转换的潜在问题
Debug.Assert(actualDigestBytes.SequenceEqual(expectedDigestBytes));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:15:56