在 C# 中生成运行哈希(或校验和)

本文关键字:校验和 哈希 运行 | 更新日期: 2023-09-27 18:36:53

前言:

我正在执行具有验证提交阶段的数据导入。这个想法是:第一阶段允许从各种来源获取数据,然后在数据库上运行各种插入/更新/验证操作。提交将回滚,但会生成"验证哈希/校验和"。提交阶段是相同的,但是,如果"验证哈希/校验和"相同,则将提交操作。(数据库将在适当的隔离级别下运行。

限制:

  • 输入读取和操作仅正向读取一次
  • 不想预先创建流(例如,写入 MemoryStream 是不可取的),因为可能有很多数据。(它可以在我们的服务器/负载上运行,但假装内存有限。
  • 不想"创建我自己的"。(我知道可用的代码,如Damien的CRC-32,我可以使用/修改,但更喜欢"标准"的东西。

以及我(认为我)正在寻找的:

一种基于输入+操作生成哈希(例如SHA1或MD5?)或校验和(例如CRC32,但希望更多)的方法。(输入/操作本身可以散列为更适合校验和生成的值,但能够"写入蒸汽"会很好。

所以,问题是:

如何在 C# 中生成运行哈希(或校验和)?

此外,虽然可以为正在运行的操作修改 CRC32 实现,但运行 SHAx 或 MD5 哈希呢?

我是否缺少某种方便的流方法,而不是可以用作适配器?

(欢迎批评,但也请酌情回答上述问题。另外,我宁愿不处理线程。;-)

在 C# 中生成运行哈希(或校验和)

你可以多次调用 HashAlgorithm.TransformBlock,然后调用 TransformFinalBlock 会给你所有区块的结果。

将您的输入分块(通过从 steam 中读取 x 数量的字节)并用每个块调用TransformBlock

编辑(来自 msdn 示例):

public static void PrintHashMultiBlock(byte[] input, int size)
{
    SHA256Managed sha = new SHA256Managed();
    int offset = 0;
    while (input.Length - offset >= size)
        offset += sha.TransformBlock(input, offset, size, input, offset);
    sha.TransformFinalBlock(input, offset, input.Length - offset);
    Console.WriteLine("MultiBlock {0:00}: {1}", size, BytesToStr(sha.Hash));
}

抱歉,我没有任何现成的示例,尽管对您来说,您基本上是用自己的块替换input,那么size将是该块中的字节数。 您必须自己跟踪偏移量。

哈希

有一个构建和一个完成阶段。您可以在构建阶段输入任意数量的数据。数据可以根据需要拆分。最后,完成哈希操作并获取哈希。

您可以使用可写的加密流来写入数据。这是最简单的方法。

您可以使用 MD5CryptoServiceProvider 的 ComputeHash 方法生成 MD5 哈希。 它采用流作为输入。

创建内存或文件流,将哈希输入写入其中,然后在完成后调用 ComputeHash 方法。

var myStream = new MemoryStream();
// Blah blah, write to the stream...
myStream.Position = 0;
using (var csp = new MD5CryptoServiceProvider()) {
    var myHash = csp.ComputeHash(myStream);
}

编辑:避免建立大量流的一种可能性是在循环中一遍又一遍地调用它并对结果进行 XOR 运算:

// Assuming we had this somewhere:
Byte[] myRunningHash = new Byte[16];
// Later on, from above:
for (var i = 0; i < 16; i++) // I believe MD5 are 16-byte arrays.  Edit accordingly.
    myRunningHash[i] = myRunningHash[i] ^ [myHash[i];

编辑#2:最后,基于@usr下面的答案,你可能可以使用HashCore和HashFinal:

using (var csp = new MD5CryptoServiceProvider()) {
    // My example here uses a foreach loop, but an 
    // event-driven stream-like approach is 
    // probably more what you are doing here.
    foreach (byte[] someData in myDataThings)
        csp.HashCore(someData, 0, someData.Length);
    var myHash = csp.HashFinal();
}
这是

规范的方式:

using System;
using System.Security.Cryptography;
using System.Text;
public void CreateHash(string sSourceData)
{
    byte[] sourceBytes;
    byte[] hashBytes;
    //create Bytearray from source data
    sourceBytes = ASCIIEncoding.ASCII.GetBytes(sSourceData);
    // calculate 16 Byte Hashcode
    hashBytes = new MD5CryptoServiceProvider().ComputeHash(sourceBytes);
    string sOutput = ByteArrayToHexString(hashBytes);
 }
static string ByteArrayToHexString(byte[] arrInput)
{
    int i;
    StringBuilder sOutput = new StringBuilder(arrInput.Length);
    for (i = 0; i < arrInput.Length - 1; i++)
    {
        sOutput.Append(arrInput[i].ToString("X2"));
    }
    return sOutput.ToString();
}