如何使用 VBA 获取文件的 MD5 十六进制哈希?

Posted

技术标签:

【中文标题】如何使用 VBA 获取文件的 MD5 十六进制哈希?【英文标题】:How to get the MD5 hex hash for a file using VBA? 【发布时间】:2011-02-19 01:22:28 【问题描述】:

我需要一个适用于文件的版本。

像这样简单的 Python 代码:

import hashlib

def md5_for_file(fileLocation, block_size=2**20):
    f = open(fileLocation)
    md5 = hashlib.md5()
    while True:
        data = f.read(block_size)
        if not data:
            break
        md5.update(data)
    f.close()
    return md5.hexdigest()

但在 VBA 中。

【问题讨论】:

【参考方案1】:

一个较老的问题,可以使用更好的答案。这些函数专门用于散列文件,而不是散列密码。作为奖励,我包含了一个 SHA1 函数。如果去掉类型声明,这些函数也可以在 VBScript 中工作,只是需要更改 GetFileBytes 函数以使用 FileSystemObject(或可能是 ADO Stream),因为 VBScript 中不存在 Free File。

Private Sub TestMD5()
    Debug.Print FileToMD5Hex("C:\test.txt")
    Debug.Print FileToSHA1Hex("C:\test.txt")
End Sub

Public Function FileToMD5Hex(sFileName As String) As String
    Dim enc
    Dim bytes
    Dim outstr As String
    Dim pos As Integer
    Set enc = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
    'Convert the string to a byte array and hash it
    bytes = GetFileBytes(sFileName)
    bytes = enc.ComputeHash_2((bytes))
    'Convert the byte array to a hex string
    For pos = 1 To LenB(bytes)
        outstr = outstr & LCase(Right("0" & Hex(AscB(MidB(bytes, pos, 1))), 2))
    Next
    FileToMD5Hex = outstr
    Set enc = Nothing
End Function

Public Function FileToSHA1Hex(sFileName As String) As String
    Dim enc
    Dim bytes
    Dim outstr As String
    Dim pos As Integer
    Set enc = CreateObject("System.Security.Cryptography.SHA1CryptoServiceProvider")
    'Convert the string to a byte array and hash it
    bytes = GetFileBytes(sFileName)
    bytes = enc.ComputeHash_2((bytes))
    'Convert the byte array to a hex string
    For pos = 1 To LenB(bytes)
        outstr = outstr & LCase(Right("0" & Hex(AscB(MidB(bytes, pos, 1))), 2))
    Next
    FileToSHA1Hex = outstr 'Returns a 40 byte/character hex string
    Set enc = Nothing
End Function

Private Function GetFileBytes(ByVal path As String) As Byte()
    Dim lngFileNum As Long
    Dim bytRtnVal() As Byte
    lngFileNum = FreeFile
    If LenB(Dir(path)) Then ''// Does file exist?
        Open path For Binary Access Read As lngFileNum
        ReDim bytRtnVal(LOF(lngFileNum) - 1&) As Byte
        Get lngFileNum, , bytRtnVal
        Close lngFileNum
    Else
        Err.Raise 53
    End If
    GetFileBytes = bytRtnVal
    Erase bytRtnVal
End Function

【讨论】:

快速问题:UTF8Encoding 的变量“asc”没有在任何地方使用,这有什么用吗?此外,要使其与 VBScript 一起使用,您可能必须使用 ADODB.Stream 对象而不是 FreeFile 方法打开文件......无论如何,很好的分享! 我认为“asc”的东西一定是我使用这段代码散列密码时的产物。我现在已经删除了。是的,VBScript 中不存在免费文件。我确实找到了一个我认为可以使用文件系统对象的函数:***.com/questions/6060529/… 很好的解决方案,有几个尼特可供选择...Dim bytes() As Byte 提供了一点好处;并通过引用将其传递给重新配置的Private Sub GetFileBytes(sFileName As String, arrBytes() As Byte) 意味着您回避了冗余内存分配 - 对于资源使用和性能而言,这是一个真正的增益。房间里的大象是,对于非常大的文件,ReDim bytRtnVal(LOF(lngFileNum) - 1&) As Byte 会引发错误。但我不能发布更好的东西,因为我不知道 System.Security.Cryptography 函数中有任何“分块”或流式 API。 更新:用户 Florent B. 在this *** answer 中发布了一个答案,其中数据以块的形式传递给 MD5 哈希服务【参考方案2】:

应该这样做:

        Dim fileBytes() As Byte = File.ReadAllBytes(path:=fullPath)
        Dim Md5 As New MD5CryptoServiceProvider()
        Dim byteHash() As Byte = Md5.ComputeHash(fileBytes)
        Return Convert.ToBase64String(byteHash)

【讨论】:

嗯?首先,这是 VB.NET 而不是 VBA,其次,您省略了一些非常重要的导入命令。 糟糕,我将 VBA 误读为 VB.NET。 VBA 会更难一些,因为它没有使上述代码如此简单的所有 .NET 框架支持。至于导入,Visual Studio 可能会自动为您推荐这些,但为了完整起见,它们是 System.IO 和 System.Security.Cryptography。

以上是关于如何使用 VBA 获取文件的 MD5 十六进制哈希?的主要内容,如果未能解决你的问题,请参考以下文章

C++:检查字符串是不是是有效的 MD5 十六进制哈希

在 mysql 中有效存储 md5 哈希的最佳实践

如何用vba获取文件的MD5 Hash值?

获取python中带有子目录的目录中的所有文件md5哈希

如何获取当前 .exe 的哈希值?

使用 MD5 哈希作为索引