應用程式 VBA/VBA 中的檔案雜湊
- 本節包含用於生成檔案雜湊的程式碼,即對整個檔案的雜湊。
- 提供了多種演算法,並提供用於 base64 或十六進位制的輸出選項。下面的 VBA 程式碼生成 MD5、SHA1、SHA2-256、SHA2-384 和 SHA2-512 雜湊的摘要。
- 此程式碼適用於單個檔案,但在相鄰頁面上提供的程式碼,VBA 中的資料夾雜湊,可用於遞迴雜湊列表,同樣可以選擇雜湊和輸出選項。
- 字串雜湊例程在另一節中給出。
- 通常這些雜湊不使用種子值,但為了說明該方法,程式碼包含一個這樣的示例(FileToSHA512SALT())。請注意,它的輸出與SHA512Managed類的輸出不同。如果對其他加鹽(帶種子的)輸入感興趣,則在相應的過程中存在註釋。
- 這些列出的演算法可以對長度不超過 200MB(兆位元組)的任何單個檔案進行雜湊,超過此長度,GetFileBytes() 中將生成記憶體不足錯誤。具體測試發現,雜湊對於 200MB 的壓縮檔案效果很好,但對於 500MB 的壓縮檔案則失敗;確切的斷點尚不清楚。對於大於 200MB 的檔案,存在其他工具。
- 大檔案雜湊,例如超過 200MB,最好使用其他工具完成。這裡提到了四個這樣的例子
- Microsoft 的 FCIV 實用工具,是免費下載。它是一個命令列應用程式,能夠對單個檔案和整個資料夾樹進行雜湊。它可以輕鬆處理大型檔案,但只適用於 MD5 和 SHA1 雜湊。它將 base64 和十六進位制輸出都發送到螢幕,但只將 b64 輸出格式傳送到檔案。準備好的檔案可以與任何新執行進行驗證,但結果只能顯示在螢幕上。它有點難以使用,即使有他們的說明,所以頁面從 VBA 執行 FCIV 實用工具和檔案校驗和完整性驗證程式 (FCIV) 示例可能會被新手發現有用。到目前為止,微軟還沒有將編碼擴充套件到包括現代演算法。
- Windows 8.1 及更高版本中的 PowerShell,可以使用所有 MD5、SHA1、SHA256、SHA384 和 SHA512 演算法建立大型單個檔案雜湊。它只在螢幕上生成輸出,儘管輸出也可以被管道傳輸到剪貼簿以供貼上。沒有用於對資料夾進行雜湊或將輸出輸出到 xml 檔案的簡單選項。為了完整起見,檔案校驗和完整性驗證程式 (FCIV) 示例中給出了一個使用示例。在 Windows 10 中,也可以使用certutil -hashfile <要雜湊的檔案的完整路徑> MD5,在命令提示符下獲取雜湊值,儘管大小限制尚不清楚。(將 md5 更改為 sha1、sha256 或 sha512 等)。
- 可以處理大型檔案的外部應用程式是MD5 和 SHA 校驗和實用程式。它是一個獨立的應用程式,基本版本可以免費下載。它為單個檔案生成 MD5、SHA1、SHA2/256 和 SHA2/512 雜湊。輸出為十六進位制,並在簡潔的使用者介面上一起顯示。還有一個更復雜的商業版本。
- FSUM 快速檔案完整性檢查器是另一個用於命令列使用的免費外部應用程式。它在許多方面類似於 FCIV,但包含最新的演算法(MD2、MD4、MD5、SHA-1、SHA-2(256、384、512)、RIPEMD-160、PANAMA、TIGER、ADLER32 和 CRC32)。除了大型檔案十六進位制雜湊外,它還可以執行平面或遞迴資料夾雜湊。輸入的程式碼與 FCIV 的程式碼不完全相同,但提供了一個文字檔案,其中包含使用示例。網頁FSUM 快速檔案完整性檢查器提供了下載和其他詳細資訊,雖然文字檔案沒有提到結果可以輕鬆地透過管道傳輸到剪貼簿,方法是 |clip。雖然圖形介面存在於其他地方,但命令列應用程式被發現是最穩定的。
- 在嘗試雜湊時,需要考慮檔案的許可權。雜湊必須訪問檔案才能獲取它們包含的位元組。雖然這並不涉及實際執行檔案,但某些資料夾和檔案型別可能會在執行時被發現被鎖定。事實上,這種型別的訪問是字串雜湊和檔案雜湊之間的主要區別。每當訪問檔案時,通常需要錯誤處理。這裡假設使用者會新增自己的錯誤處理,或者會在雜湊嘗試之前繞過有問題的檔案。使用者應該知道,程式碼無法處理空文字檔案;例如,沒有儲存任何文字的記事本檔案。GetFileBytes 例程將出錯。如果遇到空檔案,或者遇到超過 200MB 的檔案,將產生一條訊息並退出。
- 使用者檔案和資料夾幾乎沒有限制。除了空檔案問題外,那些想要訪問自己建立的資料夾中的使用者檔案的人通常不會遇到任何問題,並且感興趣的人應該知道,在本系列的另一節中有一個遞迴資料夾雜湊模組可能與之相關。 VBA 中的資料夾雜湊還包含有關如何避免音樂、影片和其他 Microsoft 庫的虛擬資料夾問題的說明。
- 雜湊只關心檔案的內容,而不是它的名稱或其他檔案詳細資訊。這意味著可以找到任何名稱下檔案的副本,方法是比較它們的雜湊值。在具有故意混淆的檔名的安全系統中,這意味著可以對非常長的檔案列表進行雜湊,直到找到所需的雜湊值,而不是依賴於不太安全的檔名來查詢它。或者,檔名有時只是檔案的雜湊值,以便雜湊可以揭示任何錯誤或非法更改。在這種情況下,駭客可能會更改檔案,然後使用相應的雜湊對檔案進行命名,但他不知道所需的雜湊演算法或要使用的私有字串,因此當所有者執行他自己的雜湊驗證時,更改將始終被檢測到。
重要。發現雜湊例程在 Windows 10、64 位 Office 設定中出錯。但是,隨後的檢查揭示瞭解決方案。Windows 平臺必須已安裝Net Framework 3.5(包括 .Net 2 和 .Net 3),這個舊版本,而不僅僅是開啟或關閉 Windows 功能中啟用的Net Framework 4.8 高階服務。當它在那裡被選中時,例程工作得很好。
- 2020 年 9 月 11 日添加了將結果傳輸到剪貼簿的預設程式碼
- 2019 年 7 月 25 日將檔案選擇對話方塊設定為開啟時列出所有檔案型別
- 2019 年 6 月 17 日添加了檔案選擇對話方塊和檔案大小限制
在該集合中的其他地方提供了用於對字串進行雜湊和批次檔案雜湊的程式碼。下面的面板包含與字串相同的程式碼,但經過了輕微的修改,用於對單個完整檔案進行雜湊。使用者透過選擇對話方塊提供檔案的完整路徑作為起始引數。引數選項允許選擇十六進位制或 base-64 輸出。包括用於 MD5、SHA1、SHA2-256、SHA2-384 和 SHA2-512 雜湊的函式。
對於頻繁使用,選擇對話方塊最方便,雖然程式碼包含一個已註釋的行,供那些打算將檔案地址鍵入過程的人使用;只需註釋掉不需要的行即可。
在每種情況下,編碼人員可以在 bytes() 陣列中找到未修改的雜湊值,此時它們處於 8 位位元組,即表示 ASCII 程式碼的數字,它適用於完整的 8 位 256 字元集。在每種情況下,填充 bytes() 陣列後的程式碼決定要交付的 ASCII 字元集版本。對於十六進位制字元集,0-9 和 A 到 F,總位集被分成四位位元組數量的兩倍,然後返回以供使用。對於 base-64 集,主要使用小寫字母、大寫字母和整數,為輸出建立 6 位字元。這兩個集合在這裡最有用,因為它們包含常用的字元。128 和 256 ASCII 集包含太多奇特字元和非列印字元,因此沒有用。對於每個雜湊版本,其位計數都是一個常數,因此其輸出長度將根據所選型別而變化。
一般而言,訊息框不允許複製其文字。如果需要複製,請將訊息框替換為輸入框,並將輸出雜湊設定為框的預設值。然後可以輕鬆地將其複製。或者,使用立即視窗中 *Debug.Print* 方法的輸出。已包含一個過程來用結果覆蓋剪貼簿:如果不需要此功能,請在頂層過程中註釋掉該行。
Option Explicit
Public sFPath As String, sH As String
Private Sub TestFileHashes()
'run this to obtain file hashes in a choice of algorithms
'select any one algorithm call below
'Limited to unrestricted files less than 200MB and not zero
'Set a reference to mscorlib 4.0 64-bit, and Microsoft Scripting Runtime
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim b64 As Boolean, bOK As Boolean, bOK2 as Boolean
Dim sSecret As String, nSize As Long, reply
'USER SETTINGS
'======================================================
'======================================================
'set output format here
b64 = True 'true for output base-64, false for hex
'======================================================
'set chosen file here
'either set path to target file in hard-typed line
'or choose a file using the file dialog procedure
'sFPath = "C:\Users\Your Folder\Documents\test.txt" 'eg.
sFPath = SelectFile2("SELECT A FILE TO HASH...") 'uses file dialog
'check the file
If sFPath = "" Then 'exit sub for no file selection
MsgBox "No selection made - closing"
Exit Sub
End If
bOK = GetFileSize(sFPath, nSize)
If nSize = 0 Or nSize > 200000000 Then 'exit sub for zero size
MsgBox "File has zero contents or greater than 200MB - closing"
Exit Sub
End If
'======================================================
'set secret key here if using HMAC class of algorithms
sSecret = "Set secret key for FileToSHA512Salt selection"
'======================================================
'choose algorithm
'enable any one line to obtain that hash result
'sH = FileToMD5(sFPath, b64)
'sH = FileToSHA1(sFPath, b64)
'sH = FileToSHA256(sFPath, b64)
'sH = FileToSHA384(sFPath, b64)
'sH = FileToSHA512Salt(sFPath, sSecret, b64)
sH = FileToSHA512(sFPath, b64)
'======================================================
'======================================================
'Results Output - open the immediate window as required
Debug.Print sFPath & vbNewLine & sH & vbNewLine & Len(sH) & " characters in length"
MsgBox sFPath & vbNewLine & sH & vbNewLine & Len(sH) & " characters in length"
'reply = InputBox("The selected text can be copied with Ctrl-C", "Output is in the box...", sH)
'decomment these two lines to overwrite the clipboard with the results
bOK2 = CopyToClip(sH)
If bOK2 = True Then MsgBox ("The result is on the clipboard.")
'decomment this line to append the hash to a file (after setting its path)
'AppendHashToFile
'decomment this block to place the hash in first cell of sheet1
' With ThisWorkbook.Worksheets("Sheet1").Cells(1, 1)
' .Font.Name = "Consolas"
' .Select: Selection.NumberFormat = "@" 'make cell text
' .Value = sH
' End With
End Sub
Private Sub AppendHashToFile()
Dim sFPath2 As String, fso As FileSystemObject, ts As TextStream
Dim sContents As String, sNewContents As String
sFPath2 = "C:\Users\Your Folder\Documents\test.txt" 'eg.
Set fso = New FileSystemObject
If Not Dir(sFPath2) = vbNullString Then
'docs.microsoft.com/office/vba/language/reference/user-interface-help/opentextfile-method
'devblogs.microsoft.com/scripting/how-can-i-add-a-line-to-the-top-of-a-text-file/
Set ts = fso.OpenTextFile(sFPath2, ForReading)
sContents = ts.ReadAll: ts.Close
End If
sNewContents = sH & vbTab & sFPath & vbTab & Now & vbNewLine & sContents
sNewContents = Left(sNewContents, Len(sNewContents) - 2)
Set ts = fso.OpenTextFile(sFPath2, ForWriting, True)
ts.WriteLine sNewContents: ts.Close
End Sub
Public Function FileToMD5(sFullPath As String, Optional bB64 As Boolean = False) As String
'parameter full path with name of file returned in the function as an MD5 hash
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim enc, bytes, outstr As String, pos As Integer
Set enc = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
'Convert the string to a byte array and hash it
bytes = GetFileBytes(sFullPath)
bytes = enc.ComputeHash_2((bytes))
If bB64 = True Then
FileToMD5 = ConvToBase64String(bytes)
Else
FileToMD5 = ConvToHexString(bytes)
End If
Set enc = Nothing
End Function
Public Function FileToSHA1(sFullPath As String, Optional bB64 As Boolean = False) As String
'parameter full path with name of file returned in the function as an SHA1 hash
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim enc, bytes, outstr As String, pos As Integer
Set enc = CreateObject("System.Security.Cryptography.SHA1CryptoServiceProvider")
'Convert the string to a byte array and hash it
bytes = GetFileBytes(sFullPath) 'returned as a byte array
bytes = enc.ComputeHash_2((bytes))
If bB64 = True Then
FileToSHA1 = ConvToBase64String(bytes)
Else
FileToSHA1 = ConvToHexString(bytes)
End If
Set enc = Nothing
End Function
Function FileToSHA512Salt(ByVal sPath As String, ByVal sSecretKey As String, _
Optional ByVal bB64 As Boolean = False) As String
'Returns a sha512 FILE HASH in function name, modified by parameter sSecretKey.
'This hash differs from that of FileToSHA512 using the SHA512Managed class.
'HMAC class inputs are hashed twice;first input and key are mixed before hashing,
'then the key is mixed with the result and hashed again.
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim asc As Object, enc As Object
Dim SecretKey() As Byte
Dim bytes() As Byte
'create a text and crypto objects
Set asc = CreateObject("System.Text.UTF8Encoding")
'Any of HMACSHAMD5,HMACSHA1,HMACSHA256,HMACSHA384,or HMACSHA512 can be used
'for corresponding hashes, albeit not matching those of Managed classes.
Set enc = CreateObject("System.Security.Cryptography.HMACSHA512")
'make a byte array of the text to hash
bytes = GetFileBytes(sPath)
'make a byte array of the private key
SecretKey = asc.Getbytes_4(sSecretKey)
'add the key property
enc.Key = SecretKey
'make a byte array of the hash
bytes = enc.ComputeHash_2((bytes))
'convert the byte array to string
If bB64 = True Then
FileToSHA512Salt = ConvToBase64String(bytes)
Else
FileToSHA512Salt = ConvToHexString(bytes)
End If
'release object variables
Set asc = Nothing
Set enc = Nothing
End Function
Public Function FileToSHA256(sFullPath As String, Optional bB64 As Boolean = False) As String
'parameter full path with name of file returned in the function as an SHA2-256 hash
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim enc, bytes, outstr As String, pos As Integer
Set enc = CreateObject("System.Security.Cryptography.SHA256Managed")
'Convert the string to a byte array and hash it
bytes = GetFileBytes(sFullPath) 'returned as a byte array
bytes = enc.ComputeHash_2((bytes))
If bB64 = True Then
FileToSHA256 = ConvToBase64String(bytes)
Else
FileToSHA256 = ConvToHexString(bytes)
End If
Set enc = Nothing
End Function
Public Function FileToSHA384(sFullPath As String, Optional bB64 As Boolean = False) As String
'parameter full path with name of file returned in the function as an SHA2-384 hash
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim enc, bytes, outstr As String, pos As Integer
Set enc = CreateObject("System.Security.Cryptography.SHA384Managed")
'Convert the string to a byte array and hash it
bytes = GetFileBytes(sFullPath) 'returned as a byte array
bytes = enc.ComputeHash_2((bytes))
If bB64 = True Then
FileToSHA384 = ConvToBase64String(bytes)
Else
FileToSHA384 = ConvToHexString(bytes)
End If
Set enc = Nothing
End Function
Public Function FileToSHA512(sFullPath As String, Optional bB64 As Boolean = False) As String
'parameter full path with name of file returned in the function as an SHA2-512 hash
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim enc, bytes, outstr As String, pos As Integer
Set enc = CreateObject("System.Security.Cryptography.SHA512Managed")
'Convert the string to a byte array and hash it
bytes = GetFileBytes(sFullPath) 'returned as a byte array
bytes = enc.ComputeHash_2((bytes))
If bB64 = True Then
FileToSHA512 = ConvToBase64String(bytes)
Else
FileToSHA512 = ConvToHexString(bytes)
End If
Set enc = Nothing
End Function
Private Function GetFileBytes(ByVal sPath As String) As Byte()
'makes byte array from file
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim lngFileNum As Long, bytRtnVal() As Byte, bTest
lngFileNum = FreeFile
If LenB(Dir(sPath)) Then ''// Does file exist?
Open sPath For Binary Access Read As lngFileNum
'a zero length file content will give error 9 here
ReDim bytRtnVal(0 To LOF(lngFileNum) - 1&) As Byte
Get lngFileNum, , bytRtnVal
Close lngFileNum
Else
Err.Raise 53 'File not found
End If
GetFileBytes = bytRtnVal
Erase bytRtnVal
End Function
Function ConvToBase64String(vIn As Variant) As Variant
'used to produce a base-64 output
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim oD As Object
Set oD = CreateObject("MSXML2.DOMDocument")
With oD
.LoadXML "<root />"
.DocumentElement.DataType = "bin.base64"
.DocumentElement.nodeTypedValue = vIn
End With
ConvToBase64String = Replace(oD.DocumentElement.Text, vbLf, "")
Set oD = Nothing
End Function
Function ConvToHexString(vIn As Variant) As Variant
'used to produce a hex output
'Set a reference to mscorlib 4.0 64-bit
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim oD As Object
Set oD = CreateObject("MSXML2.DOMDocument")
With oD
.LoadXML "<root />"
.DocumentElement.DataType = "bin.Hex"
.DocumentElement.nodeTypedValue = vIn
End With
ConvToHexString = Replace(oD.DocumentElement.Text, vbLf, "")
Set oD = Nothing
End Function
Function GetFileSize(sFilePath As String, nSize As Long) As Boolean
'use this to test for a zero file size
'takes full path as string in sFilePath
'returns file size in bytes in nSize
'Make a reference to Scripting Runtime
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim fs As FileSystemObject, f As File
Set fs = CreateObject("Scripting.FileSystemObject")
If fs.FileExists(sFilePath) Then
Set f = fs.GetFile(sFilePath)
nSize = f.Size
GetFileSize = True
Exit Function
End If
End Function
Function SelectFile2(Optional sTitle As String = "") As String
'opens a file-select dialog and on selection
'returns its full path string in the function name
'If Cancel or OK without selection, returns empty string
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim fd As FileDialog, sPathOnOpen As String, sOut As String
Set fd = Application.FileDialog(msoFileDialogFilePicker)
'do not include backslash here
sPathOnOpen = Application.DefaultFilePath
'set the file-types list on the dialog and other properties
With fd
.Filters.Clear
'the first filter line below sets the default on open (here all files are listed)
.Filters.Add "All Files", "*.*"
.Filters.Add "Excel workbooks", "*.xlsx;*.xlsm;*.xls;*.xltx;*.xltm;*.xlt;*.xml;*.ods"
.Filters.Add "Word documents", "*.docx;*.docm;*.dotx;*.dotm;*.doc;*.dot;*.odt"
.AllowMultiSelect = False
.InitialFileName = sPathOnOpen
.Title = sTitle
.InitialView = msoFileDialogViewList 'msoFileDialogViewSmallIcons
.Show
If .SelectedItems.Count = 0 Then
'MsgBox "Canceled without selection"
Exit Function
Else
sOut = .SelectedItems(1)
'MsgBox sOut
End If
End With
SelectFile2 = sOut
End Function
Function CopyToClip(sIn As String) As Boolean
'passes the parameter string to the clipboard
'set reference to Microsoft Forms 2.0 Object Library (by browsing for FM20.DLL).
'If ref not listed, inserting user form will list it.
'Clipboard cleared when launch application closes.
'Make sure that Net Framework 3.5 (includes .Net 2 and .Net 3) is installed and enabled
'and not only the Net Framework 4.8 Advanced Services
Dim DataOut As DataObject
Set DataOut = New DataObject
'first pass textbox text to dataobject
DataOut.SetText sIn
'then pass dataobject text to clipboard
DataOut.PutInClipboard
'release object variable
Set DataOut = Nothing
CopyToClip = True
End Function
- VBA 中的字串雜湊 : 此係列中的一個配套頁面,適用於只想對字串進行雜湊處理的使用者。
- VBA 中的資料夾雜湊 : 另一個配套頁面,它建立遞迴資料夾雜湊列表和日誌。使用最新的雜湊演算法,但僅限於大小不超過約 200 MB 的檔案。
- 從 VBA 執行 FCIV 實用程式: 如何使用 Microsoft fciv.exe 命令列實用程式從 VBA 建立 MD5 和 SHA1 檔案雜湊。雖然使用起來比較笨拙,但 MS 實用程式允許對整個資料夾樹進行雜湊處理和驗證。
- 檔案校驗和完整性驗證器 (FCIV) 示例: 有關如何使用 FCIV 實用程式的更多詳細資訊,適用於沒有太多使用命令列提示符經驗的使用者。
- MD5 和 SHA 校驗和實用程式: 一個外部網站的免費應用程式,用於同時顯示單個檔案的 MD5、SHA1、SHA256 和 SHA512 雜湊值(僅十六進位制)。包括檔案瀏覽功能和拖放功能,使操作變得輕鬆。此實用程式還可以用於對大型檔案進行雜湊處理;作者已測試過 500 MB 檔案。
- FSUM 快速檔案完整性檢查器 : FSUM 雜湊器的基本命令列版本下載。
- FSUM GUI : FSUM 實用程式的圖形介面下載網站。這允許檔案瀏覽、拖放以及其他功能,以簡化原本的命令列操作。