C# ComputeSignature和手动生成的哈希是不同的

C# ComputeSignature和手动生成的哈希是不同的,c#,xml,cryptography,digital-signature,sha256,C#,Xml,Cryptography,Digital Signature,Sha256,我正在创建带有数字签名的请求xml。下面是我的代码 CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"); var exportedKeyMaterial = cert.PrivateKey.ToXmlString( /* includePrivateParameters = */ tru

我正在创建带有数字签名的请求xml。下面是我的代码

CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");

        var exportedKeyMaterial = cert.PrivateKey.ToXmlString( /* includePrivateParameters = */ true);
        var key = new RSACryptoServiceProvider(new CspParameters(24 /* PROV_RSA_AES */));
        key.PersistKeyInCsp = false;
        key.FromXmlString(exportedKeyMaterial);

        string tokenId = string.Format("X509-{0}", Guid.NewGuid());
        string signatureId = string.Format("SIG-{0}", Guid.NewGuid());
        string tokenRefId = string.Format("STR-{0}", Guid.NewGuid());
        string kiId = string.Format("KI-{0}", Guid.NewGuid());
        string bodyId = string.Format("id-{0}", Guid.NewGuid());

        XmlNamespaceManager ns = new XmlNamespaceManager(xmlDoc.NameTable);
        ns.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        ns.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        ns.AddNamespace("wsa", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
        ns.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        XmlElement body = xmlDoc.DocumentElement.SelectSingleNode(@"//soapenv:Body", ns) as XmlElement;
        if (body == null)
            throw new ApplicationException("No body tag found");

        body.SetAttribute("id", bodyId);

        SignedXml signedXml = new SignedXml(body);
        signedXml.Signature.Id = signatureId;
        signedXml.SigningKey = key;
        signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

        KeyInfo keyInfo = new KeyInfo();
        keyInfo.Id = kiId;

        SecurityTokenReference tokenRef = new SecurityTokenReference();
        tokenRef.ValueType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
        tokenRef.RelativeReference = tokenId;
        tokenRef.Id = tokenRefId;

        // Add Security Token reference
        keyInfo.AddClause(tokenRef);
        signedXml.KeyInfo = keyInfo;

        signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

        XmlDsigExcC14NTransform canMethod = (XmlDsigExcC14NTransform)signedXml.SignedInfo.CanonicalizationMethodObject;
        canMethod.InclusiveNamespacesPrefixList = "soap";

        Reference reference = new Reference();
        reference.Uri = string.Format("#{0}", bodyId);
        reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";

        reference.AddTransform(new Microsoft.Web.Services3.Security.Xml.XmlDsigExcC14NTransform());
        signedXml.AddReference(reference);

        signedXml.ComputeSignature();

XmlElement signedElement = signedXml.GetXml();

 string hash = CalculateDigestOfBody(body);

public string CalculateDigestOfBody(XmlElement xmlDoc)
        {
            SHA256 algo = new SHA256CryptoServiceProvider();
            byte[] byteHash = algo.ComputeHash(Encoding.UTF8.GetBytes(xmlDoc.OuterXml));
            string hashString = Convert.ToBase64String(byteHash);

            return hashString;
        }
这将生成下面的soap头

<Signature Id="SIG-44779d9b-7d39-4c27-877b-a6de1d9365fc" xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
        <InclusiveNamespaces PrefixList="soap" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" />
    </CanonicalizationMethod>
    <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
    <Reference URI="#id-98b3d734-ee46-49bb-aee8-c151d41defe5">
        <Transforms>
            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
        <DigestValue>..</DigestValue>
    </Reference>
</SignedInfo>
<SignatureValue>..</SignatureValue>

..
..

当我比较ComputeSignature和手动计算的哈希/摘要的摘要值时,它们并不相等

根据我的理解,它们应该是相等的,因为两者都是在身体上计算的


我在这里遗漏了什么。

对于那些对答案感兴趣的人:

一旦调用ComputeSignature方法,就不要更改主体或已签名的信息元素。另外,尽量不要手动更改soap:header子项中的任何内容

下面是我做错的代码。评论这是完美的作品

signedElement.Prefix = "ds";
signedElement.FirstChild.Prefix = "ds";
signedElement.FirstChild.FirstChild.Prefix = "ds";
我在ComputeSignature下面添加了这些行。在那之后,我试图手动计算摘要。因此,这两个摘要永远无法匹配


摘要输入中的任何更改都将更改摘要。

您必须使用XmlDocument吗?使用LINQtoXML,命名空间处理非常简单。顺便说一句,您介意将输出重新格式化为多行吗?这真的很难理解为一条长长的线。(如果你愿意,我很乐意为你做这件事,但没有你的允许,我不想做。)@DaisyShipton我已经做了格式化。我可以使用LINQtoXML,但同样,主要关注的是如何使InclusiveNamespaces使用前缀。我不想通过遍历xml以编程的方式实现。我认为应该有一种在CanonicalizationObject中设置它的方法。现在我们可以看到XML了,你问的问题更清楚了——但我不清楚为什么。看起来,
InclusiveNamespaces
只是位于不同的名称空间URI中,我怀疑它是故意位于不同的名称空间URI中的。鉴于这是一个指定其名称空间的框架类型,您能否提供更多的上下文,说明为什么您认为它应该与签名位于同一名称空间中?您谈论的是“歧义错误”-您能给出问题中的确切错误吗?问题是Signature元素用一些URI定义了xmlns。现在,由于这个名称空间是在没有任何前缀的情况下创建的,它将被所有子元素继承,因此InclusiveNamespaces元素也将继承它。但InclusiveNamespaces本身正在创建具有不同URI的XMLN。因此,框架无法识别它应该接受的URI。你所说的“不能识别它应该接受的URI”是什么意思?这意味着InclusiveNamespaces元素位于不同的名称空间URI中。它没有什么不明确的地方——它只是在一个不同的名称空间中。