如何验证数字签名的XML文件?

时间:2017-03-16 13:21:53

标签: c# xml hash digital-signature

您好我是Digital Signing的新手。我正在验证数字签名的XML文件,我已使用以下代码验证了它。但我想知道它是如何验证XML是否正确或被篡改。经过一些文章我发现了 1.为XML创建哈希。(不包括签名部分) 2.使用公钥解密签名(您将获得哈希值) 3.比较两个哈希值。 (如果两个哈希匹配则XML不被篡改)。 我的理解是对的?。

这是我的XML的签名部分

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
      <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
      <Reference URI="">
        <Transforms>
          <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <DigestValue>u+1NVN5c3gbaxmIrkO9SzVQDklA=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>QtQJjevrggzsFZj7PqD3p7GaWkzJAfyacjbMgMXgszCuO+Pxe2rrkScqvgGt2DJqgVlTbC/m9gnodCu7BcXSmW459mSJtyGH+ekWwj6g9ej8I7IYWCRqbI5uus3r3+vr/8ECd5CP/khu/LcCMyPuNIxA8h2EywCeQgbXBvLiWcdexBazdKQQpFxlKw0i+oTs8Ou6jViOdX1ZmTRtdKCQXzAElvpyNimQSmO9OECEs/TytjzIG98mpldfdofoq/2JC+xQhs6IF+Ctw/zlJdkgj1U18U/00Cw4puT4oScTELNSihSS+i9gAL+YjZLlIeunACbnZ4B1CVL/uS9kLlutXQ==</SignatureValue>
    <KeyInfo>
      <KeyValue>
        <RSAKeyValue>
          <Modulus>kHORMZQYOifL5UdIhKe54SfvJKyzLL5Aaw9MgpzeQPgBMmD9KMRnkeU+5RYMiUW8GT3q4eW77UihyxSX3MTAHzuqXoc6GjkBO1Tr41isud721SG7iMspw829YZKAHAPDAl0BV5gpLZagH8KXrDp4dVU+XDOOLZZZWZnbpKSFKvLaJO34KphZ/9W3L/l1BOwEs7132svmtwGgPO2Y16C90sDRWp78ZCYYhb7fAez7683+fijZCDGuVTvS0lBKhmH0ETiNfBAiELUUwHvQ5GHOFSp5PA8+hV9F7zxno1a0/OBpRsHfLydm3THyMUS7DlPE46zPiO9rRIUe90aQ64ulYQ==</Modulus>
          <Exponent>AQAB</Exponent>
        </RSAKeyValue>
      </KeyValue>
    </KeyInfo>
  </Signature>

以及我如何验证XML:

private void btnVerifySign_Click(object sender, EventArgs e)
        {
string  LModulus = node.SelectSingleNode("//Signature/KeyInfo/KeyValue/RSAKeyValue/Modulus").InnerText.ToString();
                string LExponent = node.SelectSingleNode("//Signature/KeyInfo/KeyValue/RSAKeyValue/Exponent").InnerText.ToString();
using (var rsa = new RSACryptoServiceProvider())
                {
var rsaParam = new RSAParameters()
                    {
Modulus = Convert.FromBase64String(LModulus),
                        Exponent = Convert.FromBase64String(LExponent)
                    };
rsa.ImportParameters(rsaParam);
bool result = VerifyXml(newxml1, rsa);
}

public static Boolean VerifyXml(XmlDocument Doc, RSA Key)
        {
            // Check arguments. 
            if (Doc == null)
                throw new ArgumentException("Doc");
            if (Key == null)
                throw new ArgumentException("Key");

            // Create a new SignedXml object and pass it 
            // the XML document class.
            SignedXml signedXml = new SignedXml(Doc);

            // Find the "Signature" node and create a new 
            // XmlNodeList object.
            XmlNodeList nodeList = Doc.GetElementsByTagName("Signature");

            // Throw an exception if no signature was found. 
            if (nodeList.Count <= 0)
            {
                // throw new CryptographicException("Verification failed: No Signature was found in the document.");
                MessageBox.Show("Verification failed: No Signature was found in the document.");
            }

            // This example only supports one signature for 
            // the entire XML document.  Throw an exception  
            // if more than one signature was found. 
            if (nodeList.Count > 1)
            {
                MessageBox.Show("Verification failed: More that one signature was found for the document.");
                // throw new CryptographicException("Verification failed: More that one signature was found for the document.");
            }

            // Load the first <signature> node.  
            signedXml.LoadXml((XmlElement)nodeList[0]);

            // Check the signature and return the result. 
            return signedXml.CheckSignature(Key);
        }

这里,如果我修改xml并通过VerifyXml方法验证它,它返回false,如果我不修改xml VerifyXml方法返回true。我想知道它是如何验证XML的?我试过在nodeList [0]中比较篡改和未篡改的XML的值,我得到了相同的值但signedXml.CheckSignature(Key)返回true / false。对于不同的xml,摘要值应该是不同的吗?在这里,我为修改和未修改的xml获得相同的摘要值。并且基于CheckSignature(Key)返回true / false的确切内容。当为xml?创建哈希值时。谢谢。

1 个答案:

答案 0 :(得分:1)

实际上签名的是<SignedInfo>元素,而不是数据对象。数据对象的哈希值包含在<Reference>元素的<SignedInfo>元素中。因此,数据对象也是间接签名的。在验证签名时,将数据对象的哈希值与<Reference>元素中的带符号的数据摘要进行比较。然后使用公钥检查<SignedInfo>元素上的签名。

有关详情,请阅读RFC 3275。在那里,您可以找到有关为签名xml生成和验证所执行步骤的信息。