Thursday 19 September 2013

Get MD5Hash from FileStream while partially reading

Hello friends,

Recently am worked to CryptoStream using MD5Hash related things and I need to calculate hash of a specified Stream while I was processing its data. I was trying to resolve various solutions and got some samples and customized that and resolve it. Here I will go to describe the difficulty and explanation.
Actually I need to get MD5Hash from filestream while partially reading. Before that we are doing to direct approach.
Along the way I discovered 3 additional methods to calculate hash – all suitable when you can’t rely on seeking in the stream.
Direct Approach for get Hash from container:
                      using (MD5 md5 = System.Security.Cryptography.MD5.Create())
            {
                md5.ComputeHash (inputStraeam);
                String containerHash = BitConverter.ToString(md5.Hash);
                return containerHash;
            }

This is the direct approach to calculate hash from data in stream, but its setback is that after calculating the hash value the stream is read to the end
 If the source stream was seekable (FileStream, MemoryStream…), you can just seek back and process the stream normally, but what if you can’t seek in the processing stream?

The block approach
The block approach you can calculate hash for filestream, using
You can calculate the hash on the go, using TransformBlock and TransformFinalBlock methods of MD5 class.
   using (MD5 md5 = MD5.Create())
        {
          byte[] data = new byte[4096];
          int numRead = 0;
          while ((numRead = inputStream.Read(data, 0, data.length)) > 0)
          {
                           
          md5.TransformBlock(data, 0, numRead, null, 0);

          }
           md5.TransformFinalBlock(data, 0, numRead);

         string fileHash = BitConverter.ToString(md5.Hash);
         fileHash = fileHash.Replace("-", "").ToUpper();
      }

This allows you to calculate the hash of the data at the same time to entire stream.



The block approach with Container position
The block approach with container position you to calculate the hash from set the fileStream position to read and end of stream.
using TransformBlock and TransformFinalBlock methods of MD5 class.
string fileHash = string.Empty;
long totalFileStreamFileStreamSize = fileStreamSize;
byte[] data = new byte[4096];
int readAmount = 0;

 if (fileStreamSize < data.Length)
 {
  readAmount = fileStreamSize;
 }
 else
 {
 readAmount = data.Length;
 }
 using (MD5 md5 = MD5.Create())
 {
 int numRead = 0;

 totalFileStreamFileStreamSize = totalFileStreamFileStreamSize + position;

 while ((numRead = container.Read(data, 0, readAmount)) > 0)
 {

 if ((totalFileStreamFileStreamSize - container.Position) <= readAmount)
 {
 readAmount = (int)(totalFileStreamFileStreamSize - container.Position);
 }
 // Compute MD5 hash
 if (container.Position != totalFileStreamFileStreamSize)
 {
 md5.TransformBlock(data, 0, numRead, null, 0);
 }
 else
 {
 md5.TransformFinalBlock(data, 0, numRead);
 }
 }
 fileHash = BitConverter.ToString(md5.Hash);
 fileHash = fileHash.Replace("-", "").ToUpper();
  }
The CryptoStream Approach
when we want to calculate hash value of output of your algorighm and do not have input in form of a stream, you can use CryptoStreamMode.Write.
using (MD5 md5 = new MD5CryptoServiceProvider())
{
using (CryptoStream writerOutputDocument = new CryptoStream(originalDocument, md5, CryptoStreamMode.Write))
{
while (totalRemaining > 0)
{
int numRead = inputContainer.Read(buffer, 0, readAmount);
if (numRead < 1)
{
throw new Exception("Unexpected end of file readingr.");
}
                                                                    writerOutputDocument.Write(buffer, 0, numRead);

totalRemaining -= numRead;
if (totalRemaining < buffer.Length)
{
 readAmount = (int)totalRemaining;
}
}
}
}

Note – when using CryptoStreamMode.Write, you need to indicate to the hash algorithm that all data is written.


No comments:

Post a Comment