11

C#でXMLドキュメントをハッシュするための最良の方法は何ですか?XMLドキュメントをハッシュして、生成されたときから手動で変更されたかどうかを確認したいと思います。私はこれをセキュリティのために使用していません。誰かがXMLを変更し、それに合わせてハッシュを変更しても問題ありません。

たとえば、ルートの子ノードをハッシュし、そのハッシュをルートの属性として保存します。

<RootNode Hash="abc123">
    <!-- Content to hash here -->
</RootNode>
4

4 に答える 4

10

.NETには、 XMLデジタル署名仕様を実装するクラスがあります。署名は、元のXMLドキュメント内に追加することも(つまり、「エンベロープ署名」)、個別に保存/転送することもできます。

セキュリティが必要ないので少しやり過ぎかもしれませんが、すでに実装されており、言語やプラットフォームに依存しない標準であるという利点があります。

于 2009-10-05T21:28:35.147 に答える
5

暗号化名前空間を使用できます。

System.Security.Cryptography.MACTripleDES hash = new System.Security.Cryptography.MACTripleDES(Encoding.Default.GetBytes("mykey"));
string hashString = Convert.ToBase64String(hash.ComputeHash(Encoding.Default.GetBytes(myXMLString)));

キーを使用してハッシュ暗号技術者を作成してから、xmlの文字列reqpresentationを使用してハッシュを作成する必要があります。

于 2009-10-05T17:14:49.933 に答える
2

System.Securityに.NET参照を追加し、XmlDsigC14NTransformを使用します。ここに例があります...

/* http://www.w3.org/TR/xml-c14n

    Of course is cannot detect these are the same...

       <color>black</color>    vs.   <color>rgb(0,0,0)</color>

    ...because that's dependent on app logic's interpretation of XML data.

    But otherwise it gets the following right...
    •Normalization of whitespace in start and end tags
    •Lexicographic ordering of namespace and attribute
    •Empty element conversion to start-end tag pair 
    •Retain all whitespace between tags

    And more.
 */
public static string XmlHash(XmlDocument myDoc)
{
    var t = new System.Security.Cryptography.Xml.XmlDsigC14NTransform();
    t.LoadInput(myDoc);
    var s = (Stream)t.GetOutput(typeof(Stream));
    var sha1 = SHA1.Create();

    var hash = sha1.ComputeHash(s);
    var base64String = Convert.ToBase64String(hash);
    s.Close();
    return base64String;
}
于 2013-12-06T22:00:27.827 に答える
0

最近、作業中の部分的なXMLドキュメントのハッシュ「チェックサム」を実装する必要がありました(XElementを使用しています)。初歩的なパフォーマンステストでは、ルックアップテーブルを使用して16進文字列ハッシュを作成した場合、使用しない場合と比較して、マシンの実行時間が最大3倍高速化することが示されました。

これが私の実装です:

using System.Xml.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Linq;

/// <summary>
/// Provides a way to easily compute SHA256 hash strings for XML objects.
/// </summary>
public static class XMLHashUtils
{
    /// <summary>
    /// Precompute a hexadecimal lookup table for runtime performance gain, at the cost of memory and startup performance loss.
    /// SOURCE: https://stackoverflow.com/a/18574846
    /// </summary>
    static readonly string[] hexLookupTable = Enumerable.Range(0, 256).Select(integer => integer.ToString("x2")).ToArray();

    static readonly SHA256Managed sha256 = new SHA256Managed();

    /// <summary>
    /// Computes a SHA256 hash string from an XElement and its children.
    /// </summary>
    public static string Hash(XElement xml)
    {
        string xmlString = xml.ToString(SaveOptions.DisableFormatting); // Outputs XML as single line
        return Hash(xmlString);
    }

    /// <summary>
    /// Computes a SHA256 hash string from a string.
    /// </summary>
    static string Hash(string stringValue)
    {
        byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(stringValue));
        return BytesToHexString(hashBytes);
    }

    /// <summary>
    /// Converts a byte array to a hexadecimal string using a lookup table.
    /// </summary>
    static string BytesToHexString(byte[] bytes)
    {
        int length = bytes.Length;
        StringBuilder sb = new StringBuilder(length * 2); // Capacity fits hash string length
        for (var i = 0; i < length; i++)
        {
            sb.Append(hexLookupTable[bytes[i]]); // Using lookup table for faster runtime conversion
        }
        return sb.ToString();
    }
}

そして、ここにいくつかのユニットテストがあります(NUnitフレームワークを使用):

using NUnit.Framework;
using System.Linq;
using System.Xml.Linq;

public class XMLHashUtilsTest
{
    /// <summary>
    /// Outputs XML: <root><child attribute="value" /></root>
    /// where <child /> node repeats according to childCount
    /// </summary>
    XElement CreateXML(int childCount)
    {
        return new XElement("root", Enumerable.Repeat(new XElement("child", new XAttribute("attribute", "value")), childCount));
    }

    [Test]
    public void HashIsDeterministic([Values(0,1,10)] int childCount)
    {
        var xml = CreateXML(childCount);
        Assert.AreEqual(XMLHashUtils.Hash(xml), XMLHashUtils.Hash(xml));
    }

    [Test]
    public void HashChanges_WhenChildrenAreDifferent([Values(0,1,10)] int childCount)
    {
        var xml1 = CreateXML(childCount);
        var xml2 = CreateXML(childCount + 1);
        Assert.AreNotEqual(XMLHashUtils.Hash(xml1), XMLHashUtils.Hash(xml2));
    }

    [Test]
    public void HashChanges_WhenRootNameIsDifferent([Values("A","B","C")]string nameSuffix)
    {
        var xml1 = CreateXML(1);
        var xml2 = CreateXML(1);
        xml2.Name = xml2.Name + nameSuffix;
        Assert.AreNotEqual(XMLHashUtils.Hash(xml1), XMLHashUtils.Hash(xml2));
    }

    [Test]
    public void HashChanges_WhenRootAttributesAreDifferent([Values("A","B","C")]string attributeName)
    {
        var xml1 = CreateXML(1);
        var xml2 = CreateXML(1);
        xml2.Add(new XAttribute(attributeName, "value"));
        Assert.AreNotEqual(XMLHashUtils.Hash(xml1), XMLHashUtils.Hash(xml2));
    }
}
于 2018-09-13T17:17:37.603 に答える