5

前言:

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

限制:

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

而我(认为我)在寻找什么:

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

所以,问题是:

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

此外,虽然可以针对 Running 操作修改 CRC32 实现,但运行 SHAx 或 MD5 哈希呢?

我是否缺少某种可以用作适配器的方便的 Stream 方法?

(欢迎批评,但也请在适用的情况下回答上述问题。另外,我不想处理线程。;-)

4

4 回答 4

9

您可以多次调用HashAlgorithm.TransformBlockTransformFinalBlock ,然后调用将为您提供所有块的结果。

将您的输入分块(通过从流中读取 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就是该块中的字节数。您必须自己跟踪偏移量。

于 2012-06-11T18:13:44.000 回答
5

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

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

于 2012-06-11T18:15:17.607 回答
2

您可以使用MD5CryptoServiceProviderComputeHash方法生成 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);
}

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

// 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();
}
于 2012-06-11T18:14:39.170 回答
0

这是规范的方式:

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();
}
于 2012-06-11T18:21:23.007 回答