簡體   English   中英

可以使用緩沖讀取來計算MD5(或其他)哈希嗎?

[英]Possible to calculate MD5 (or other) hash with buffered reads?

我需要計算很大文件(千兆字節)的校驗和。 可以使用以下方法完成此操作:

    private byte[] calcHash(string file)
    {
        System.Security.Cryptography.HashAlgorithm ha = System.Security.Cryptography.MD5.Create();
        FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
        byte[] hash = ha.ComputeHash(fs);
        fs.Close();
        return hash;
    }

但是,文件通常是事先以緩沖方式寫入的(例如一次寫入32mb)。 我如此確信,我看到了一個哈希函數的替代,該哈希函數使我能夠在編寫的同時計算MD5(或其他)哈希,即:計算一個緩沖區的哈希,然后將得到的哈希輸入到下一個迭代中。

像這樣的東西:(pseudocode-ish)

byte [] hash = new byte [] { 0,0,0,0,0,0,0,0 };
while(!eof)
{
   buffer = readFromSourceFile();
   writefile(buffer);
   hash = calchash(buffer, hash);
}

哈希現在與在整個文件上運行calcHash函數所實現的功能類似。

現在,在.Net 3.5 Framework中找不到類似的替代項,我在做夢嗎? 它從來沒有存在過,還是我在搜索時很爛? 一次進行寫入和校驗和計算的原因是由於文件大而有意義。

我喜歡上面的答案,但是為了完整起見,並且是一個更通用的解決方案,請參閱CryptoStream類。 如果您已經在處理流,則可以很容易地將流包裝在CryptoStream ,並將HashAlgorithm作為ICryptoTransform參數傳遞。

var file = new FileStream("foo.txt", FileMode.Open, FileAccess.Write);
var md5 = MD5.Create();
var cs = new CryptoStream(file, md5, CryptoStreamMode.Write);
while (notDoneYet)
{
    buffer = Get32MB();
    cs.Write(buffer, 0, buffer.Length);
}
System.Console.WriteLine(BitConverter.ToString(md5.Hash));

您可能必須在獲取哈希之前關閉流(因此HashAlgorithm知道已完成)。

您可以使用TransformBlockTransformFinalBlock方法來分塊處理數據。

// Init
MD5 md5 = MD5.Create();
int offset = 0;

// For each block:
offset += md5.TransformBlock(block, 0, block.Length, block, 0);

// For last block:
md5.TransformFinalBlock(block, 0, block.Length);

// Get the has code
byte[] hash = md5.Hash;

注意:它可以(至少與MD5提供程序一起使用)將所有塊發送到TransformBlock ,然后將空塊發送到TransformFinalBlock以完成該過程。

似乎可以使用TransformBlock / TransformFinalBlock ,如本示例所示:對大型文件進行哈希處理時顯示進度更新

哈希算法有望處理這種情況,通常使用以下3個函數實現:

hash_init() -調用以分配資源並開始哈希。
hash_update() -在到達新數據時調用它。
hash_final() -完成計算並釋放資源。

請參閱http://www.openssl.org/docs/crypto/md5.htmlhttp://www.openssl.org/docs/crypto/sha.html ,以獲取有關C語言的良好標准示例; 我確定您的平台也有類似的庫。

我只需要做類似的事情,但想異步讀取文件。 它使用TransformBlock和TransformFinalBlock,並給我與Azure一致的答案,所以我認為這是正確的!

private static async Task<string> CalculateMD5Async(string fullFileName)
{
  var block = ArrayPool<byte>.Shared.Rent(8192);
  try
  {
     using (var md5 = MD5.Create())
     {
         using (var stream = new FileStream(fullFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8192, true))
         {
            int length;
            while ((length = await stream.ReadAsync(block, 0, block.Length).ConfigureAwait(false)) > 0)
            {
               md5.TransformBlock(block, 0, length, null, 0);
            }
            md5.TransformFinalBlock(block, 0, 0);
         }
         var hash = md5.Hash;
         return Convert.ToBase64String(hash);
      }
   }
   finally
   {
      ArrayPool<byte>.Shared.Return(block);
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM