Generate MD5 and SHA1 hash for file


  • 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
          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)
            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
          Return m_bufferSize
        End Get
        Set(ByVal value As Integer)
          m_bufferSize = value
        End Set
      End Property
      Public ReadOnly Property Hash() As Byte()
          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")
        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
          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
          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)
          While t1.IsAlive
          End While
          Dim t2 = New Thread(AddressOf MD5hasher.ComputeHash)
          While t2.IsAlive
          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?


    Thursday, May 26, 2011 6:19 PM


  • 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 ;)


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

All replies