0

我正在尝试使用 AdvApi32 中的 Crypto 函数对用户提供的数据(文件)进行 MD5 哈希处理。一切都很好,除非文件非常大(数百 MB 或更大),在这种情况下,我最终会遇到 OutOfMemory 异常。

我认为解决方案是重复调用CryptHashData使用相同的方法HashObject并一次仅处理(例如)4096 个字节。

这似乎有效,但返回的哈希不正确。

Function HashFile(File As FolderItem) As String
  Declare Function CryptAcquireContextW Lib "AdvApi32" (ByRef provider as Integer, container as Integer, providerName as WString, _
  providerType as Integer, flags as Integer) as Boolean
  Declare Sub CryptDestroyHash Lib "AdvApi32" (hashHandle as Integer )
  Declare Function CryptCreateHash Lib "AdvApi32" (provider as Integer, algorithm as Integer, key as Integer, flags as Integer, _
  ByRef hashHandle as Integer) as Boolean
  Declare Function CryptHashData Lib "AdvApi32" (hashHandle as Integer, data as Ptr, length as Integer, flags as Integer) as Boolean
  Declare Function CryptGetHashParam Lib "AdvApi32" (hashHandle as Integer, type as Integer, value as Ptr, ByRef length as Integer, _
  flags as Integer) as Boolean

  Const HP_HASHVAL = &h0002
  Const HP_HASHSIZE = &h0004
  Const MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"
  Const PROV_RSA_FULL = 1
  Const CRYPT_NEWKEYSET = &h00000008
  Const CALG_MD5 = &h00008003

  Dim provider As Integer
  Dim hashHandle As Integer

  If Not CryptAcquireContextW(provider, 0, MS_DEF_PROV, PROV_RSA_FULL, 0) Then
    If Not CryptAcquireContextW(provider, 0, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) Then
      Raise New RuntimeException
    End If
  End If

  If Not CryptCreateHash(provider, CALG_MD5, 0, 0, hashHandle) Then
    Raise New RuntimeException
  End If

  Dim dataPtr As New MemoryBlock(4096)
  Dim bs As BinaryStream
  bs = bs.Open(File)
  dataPtr.StringValue(0, 4096) = bs.Read(4096)

  Do
    If CryptHashData(hashHandle, dataPtr, dataPtr.Size, 0) Then
      dataPtr = New MemoryBlock(4096)
      dataPtr.StringValue(0, 4095) = bs.Read(4096)
    End If
  Loop Until bs.EOF

  Dim size as Integer = 4
  Dim toss As New MemoryBlock(4)
  If Not CryptGetHashParam(hashHandle, HP_HASHSIZE, toss, size, 0) Then
    Raise New RuntimeException
  End If

  size = toss.UInt32Value(0)

  Dim hashValue As New MemoryBlock(size)
  If Not CryptGetHashParam(hashHandle, HP_HASHVAL, hashValue, size, 0) Then
    Raise New RuntimeException
  End If
  CryptDestroyHash(hashHandle)

  //Convert binary to hex
  Dim hexvalue As Integer
  Dim hexedInt As String
  Dim src As String = hashValue.StringValue(0, hashValue.Size)
  For i As Integer = 1 To LenB(src)
    hexvalue = AscB(MidB(src, i, 1))
    hexedInt = hexedInt + RightB("00" + Hex(hexvalue), 2)
  next

  Return LeftB(hexedInt, LenB(hexedInt))

End Function

我在这里做错了什么?我得到的输出是一致的,但是是错误的。

4

2 回答 2

0

您是否检查过 C++ 上的那个 msdn 示例?与您的问题非常相似的答案。

于 2013-04-27T20:14:03.117 回答
0

我认为问题在于,由于您以 4096 字节块的形式读取数据 - 当数据不是 4096 的倍数时,您最终会包含不需要的尾随 0 或可能的垃圾值。尝试bs.Read(1)而不是bs.Read(4096)在循环中:Loop Until bs.EOF为了测试现在是否正在计算正确的哈希。如果成功调整循环以分别处理剩余 (%4096) 字节。

于 2013-04-27T21:01:31.853 回答