使用 Visual C# 计算和比较哈希值

本分步文章介绍如何获取哈希值以及如何比较两个哈希值,以检查它们是否使用 Visual C# 相同。 它还提供了一个代码示例来演示如何执行此任务。

原始产品版本: Visual C#
原始 KB 数: 307020

总结

本文介绍以下Microsoft .NET Framework 类库命名空间:

  • System.Security.Cryptography
  • System.Text

通过 System.Security.Cryptography .NET Framework 中的类,可以轻松计算源数据的哈希值。

计算哈希值

使用命名空间中包含的 System.Security.Cryptography 加密资源轻松生成和比较哈希值。 由于所有哈希函数都采用类型 Byte[]输入,因此可能需要在对源进行哈希处理之前将源转换为字节数组。 若要为字符串值创建哈希,请执行以下步骤:

  1. 打开 Visual Studio .NET 或 Visual Studio。

  2. 在 Visual C# .NET 或 Visual C# 中创建新的控制台应用程序会创建一个公共类以及一个空 Main() 方法。

    注意

    在 Visual C# 中。 NET, 默认情况下会创建Class1.cs 。 在 Visual C# 中, 默认情况下会创建Program.cs

  3. using使用代码后面的SystemSystem.Security.Cryptography这些命名空间中的指令和System.Text命名空间,这样就不需要限定这些命名空间的声明。 这些语句必须在任何其他声明之前使用。

    using System;
    using System.Security.Cryptography;
    using System.Text;
    
  4. 声明一个字符串变量来保存源数据,以及两个字节数组(大小未定义),用于保存源字节和生成的哈希值。

    string sSourceData;
    byte[] tmpSource;
    byte[] tmpHash;
    
  5. GetBytes()使用类的方法System.Text.ASCIIEncoding将源字符串转换为字节数组(需要作为哈希函数的输入)。

    sSourceData = "MySourceData";
    //Create a byte array from source data.
    tmpSource = ASCIIEncoding.ASCII.GetBytes(sSourceData);
    
  6. 通过调用 ComputeHash 类的 MD5CryptoServiceProvider 实例计算源数据的 MD5 哈希。

    注意

    若要计算另一个哈希值,需要创建类的另一个实例。

    //Compute hash based on source data.
    tmpHash = new MD5CryptoServiceProvider().ComputeHash(tmpSource);
    
  7. tmpHash字节数组现在保存源数据的计算哈希值(128 位值=16 字节)。 将类似这样的值显示为十六进制字符串通常很有用,以下代码可实现以下操作:

    Console.WriteLine(ByteArrayToString(tmpHash));
    static string ByteArrayToString(byte[] arrInput)
    {
        int i;
        StringBuilder sOutput = new StringBuilder(arrInput.Length);
        for (i=0;i < arrInput.Length; i++)
        {
            sOutput.Append(arrInput[i].ToString("X2"));
        }
        return sOutput.ToString();
    }
    
  8. 保存并运行代码以查看源值生成的十六进制字符串。

比较两个哈希值

从源数据创建哈希的目的是:

  • 提供一种方法来查看数据是否随时间变化。
  • 比较两个值而不使用实际值。

在任一情况下,都需要比较两个计算哈希。 如果它们都存储为十六进制字符串(如上一部分的最后一步),则很容易。 但是,它们可能采用字节数组的形式。 以下代码从上一部分创建的代码继续显示如何比较两个字节数组。

  1. 在创建十六进制字符串的正下方,基于新的源数据创建新的哈希值。

    sSourceData = "NotMySourceData";
    tmpSource = ASCIIEncoding.ASCII.GetBytes(sSourceData);
    byte[] tmpNewHash;
    tmpNewHash = new MD5CryptoServiceProvider().ComputeHash(tmpSource);
    
  2. 比较两个字节数组的最直接方法是循环访问数组,将每个单个元素与第二个值的对应元素进行比较。 如果任何元素不同,或者两个数组的大小不相同,则两个值不相等。

    bool bEqual = false;
    if (tmpNewHash.Length == tmpHash.Length)
    {
        int i=0;
        while ((i < tmpNewHash.Length) && (tmpNewHash[i] == tmpHash[i]))
        {
            i += 1;
        }
        if (i == tmpNewHash.Length)
        {
            bEqual = true;
        }
    }
    
    if (bEqual)
        Console.WriteLine("The two hash values are the same");
    else
        Console.WriteLine("The two hash values are not the same");
    Console.ReadLine();
    
  3. 保存并运行项目以查看从第一个哈希值创建的十六进制字符串。 了解新哈希是否等于原始哈希。

完整代码清单

using System;
using System.Security.Cryptography;
using System.Text;

namespace ComputeAHash_csharp
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Class1
    {
        static void Main(string[] args)
        {
            string sSourceData;
            byte[] tmpSource;
            byte[] tmpHash;
            sSourceData = "MySourceData";
            //Create a byte array from source data
            tmpSource = ASCIIEncoding.ASCII.GetBytes(sSourceData);

            //Compute hash based on source data
            tmpHash = new MD5CryptoServiceProvider().ComputeHash(tmpSource);
            Console.WriteLine(ByteArrayToString(tmpHash));

            sSourceData = "NotMySourceData";
            tmpSource = ASCIIEncoding.ASCII.GetBytes(sSourceData);

            byte[] tmpNewHash;

            tmpNewHash = new MD5CryptoServiceProvider().ComputeHash(tmpSource);

            bool bEqual = false;
            if (tmpNewHash.Length == tmpHash.Length)
            {
                int i=0;
                while ((i < tmpNewHash.Length) && (tmpNewHash[i] == tmpHash[i]))
                {
                    i += 1;
                }
                if (i == tmpNewHash.Length)
                {
                    bEqual = true;
                }
            }

            if (bEqual)
                Console.WriteLine("The two hash values are the same");
            else
                Console.WriteLine("The two hash values are not the same");
            Console.ReadLine();
        }

        static string ByteArrayToString(byte[] arrInput)
        {
            int i;
            StringBuilder sOutput = new StringBuilder(arrInput.Length);
            for (i=0;i < arrInput.Length; i++)
            {
                sOutput.Append(arrInput[i].ToString("X2"));
            }
            return sOutput.ToString();
        }
    }
}

参考

有关如何使用 .NET Framework 的加密功能的详细信息,请参阅 .NET