在C#中生成Running Hash(或Checksum)?

时间:2012-06-11 18:08:06

标签: c# hash checksum

序:

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

限制:

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

我(我想)正在寻找:

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

所以,问题是:

如何在C#中生成Running Hash(或Checksum)?

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

我是否缺少某种方便的Stream方法而不能用作适配器?

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

4 个答案:

答案 0 :(得分:9)

您可以多次致电HashAlgorithm.TransformBlock,然后拨打TransformFinalBlock即可获得所有街区的结果。

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

答案 1 :(得分:4)

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

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

答案 2 :(得分: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);
}

编辑:避免构建大量Streams的一种可能性是在循环中反复调用它并对结果进行异或运行:

// 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();
}

答案 3 :(得分: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();
}