none
Generate MD5 and SHA1 hash for file

    Question

  • Hi,

    I'm trying to generate an MD5 and SHA1 hash value for a given file with the following:

     

    Imports System
    Imports System.IO
    Imports System.Security.Cryptography
    Imports System.Text
    
    Public Class ASyncFileHashAlgorithm
      Protected hashAlgorithm As HashAlgorithm
      Protected m_hash As Byte()
      Protected cancel As Boolean = False
      Protected m_bufferSize As Integer = 4096
      Public Delegate Sub FileHashingProgressHandler(ByVal sender As Object, ByVal e As FileHashingProgressArgs)
      Public Event FileHashingProgress As FileHashingProgressHandler
    
      Public Sub New(ByVal hashAlgorithm As HashAlgorithm)
        Me.hashAlgorithm = hashAlgorithm
      End Sub
    
      Public Function ComputeHash(ByVal stream As Stream) As Byte()
        cancel = False
        m_hash = Nothing
        Dim _bufferSize As Integer = m_bufferSize
        ' this makes it impossible to change the buffer size while computing 
        Dim readAheadBuffer As Byte(), buffer As Byte()
        Dim readAheadBytesRead As Integer, bytesRead As Integer
        Dim size As Long, totalBytesRead As Long = 0
    
        size = stream.Length
        readAheadBuffer = New Byte(_bufferSize - 1) {}
        readAheadBytesRead = stream.Read(readAheadBuffer, 0, readAheadBuffer.Length)
    
        totalBytesRead += readAheadBytesRead
    
        Do
          bytesRead = readAheadBytesRead
          buffer = readAheadBuffer
    
          readAheadBuffer = New Byte(_bufferSize - 1) {}
          readAheadBytesRead = stream.Read(readAheadBuffer, 0, readAheadBuffer.Length)
    
          totalBytesRead += readAheadBytesRead
    
          If readAheadBytesRead = 0 Then
            hashAlgorithm.TransformFinalBlock(buffer, 0, bytesRead)
    
          Else
            hashAlgorithm.TransformBlock(buffer, 0, bytesRead, buffer, 0)
          End If
    
          RaiseEvent FileHashingProgress(Me, New FileHashingProgressArgs(totalBytesRead, size))
        Loop While readAheadBytesRead <> 0 AndAlso Not cancel
    
        If cancel Then
          Return InlineAssignHelper(m_hash, Nothing)
        End If
    
        Return InlineAssignHelper(m_hash, hashAlgorithm.Hash)
      End Function
    
      Public Property BufferSize() As Integer
        Get
          Return m_bufferSize
        End Get
        Set(ByVal value As Integer)
          m_bufferSize = value
        End Set
      End Property
    
      Public ReadOnly Property Hash() As Byte()
        Get
          Return m_hash
        End Get
      End Property
    
      'Public Sub Cancel()
      '  cancel = True
      'End Sub
    
      Public Overrides Function ToString() As String
        Dim hex As String = ""
        For Each b As Byte In Hash
          hex += b.ToString("x2")
        Next
    
        Return hex
      End Function
      Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
        target = value
        Return value
      End Function
    End Class
    
    
    Public Class FileHashingProgressArgs
      Inherits EventArgs
      Public Property TotalBytesRead() As Long
        Get
          Return m_TotalBytesRead
        End Get
        Set(ByVal value As Long)
          m_TotalBytesRead = Value
        End Set
      End Property
      Private m_TotalBytesRead As Long
      Public Property Size() As Long
        Get
          Return m_Size
        End Get
        Set(ByVal value As Long)
          m_Size = Value
        End Set
      End Property
      Private m_Size As Long
    
      Public Sub New(ByVal totalBytesRead__1 As Long, ByVal size__2 As Long)
        TotalBytesRead = totalBytesRead__1
        Size = size__2
      End Sub
    End Class
    

     

    I'm using the above like this:

     

     Dim MD5hasher As New ASyncFileHashAlgorithm(MD5.Create())
     Dim SHA1hasher As New ASyncFileHashAlgorithm(SHA1.Create())
    
     Dim stream As IO.Stream = DirectCast(File.Open(strFilePathAndName, FileMode.Open), Stream)
          AddHandler MD5hasher.FileHashingProgress, AddressOf OnFileHashingProgress
    
     Dim t1 = New Thread(AddressOf SHA1hasher.ComputeHash)
          t1.Start(stream)
          While t1.IsAlive
            Application.DoEvents()
          End While
    
          Dim t2 = New Thread(AddressOf MD5hasher.ComputeHash)
          t2.Start(stream)
          While t2.IsAlive
            Application.DoEvents()
          End While
    
    LblMD5.Text = System.BitConverter.ToString(MD5hasher.Hash).Replace("-", "")
    
    LblSHA1.Text = System.BitConverter.ToString(SHA1hasher.Hash).Replace("-", "")
    

    The MD5 is generated correctly but the SHA1 is not. If I switch the order of threads this is reversed (MD5 wrong)

    Is the class not reusing the streamed file to generate during the second thread?

    Thanks,
    madlan

    Thursday, May 26, 2011 6:19 PM

Answers

  • The way your code is, the stream pointer will be positioned at the end of the file after the first hash is computed. If you want to compute the hashes at the same time, you will have to read a block of data and present that to each hasher, then read the next block, and so on. Unless I'm missing something obvious, of course ;)

    --
    Andrew

    • Marked as answer by Liliane Teng Wednesday, June 08, 2011 8:12 AM
    Wednesday, June 01, 2011 7:51 PM

All replies