MD5 Hashing Using the CryptoAPI
MD5 (or almost any other hashing algorithm you could possibly want to work with) is provided for you by the Windows Cryptography API. The code to use this API is as follows:
Option Explicit Private Const ALG_CLASS_HASH As Long = (4 * 2 ^ 13) Private Const ALG_SID_MD5 As Long = 3 Private Const ALG_TYPE_ANY As Long = 0 Private Const CALG_MD5 As Long = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD5)
Private Const CRYPT_VERIFYCONTEXT As Long = &HF0000000
Private Const PROV_RSA_FULL As Long = 1 Private Const HP_HASHSIZE As Long = &H4 Private Const HP_HASHVAL As Long = &H2 Private Declare Function CryptGetHashParam Lib "advapi32.dll" (ByVal hHash As Long, ByVal dwParam As Long, pByte As Any, ByRef pdwDataLen As Long, ByVal dwFlags As Long) As Long Private Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Long, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long Private Declare Function CryptCreateHash Lib "advapi32.dll" (ByVal hProv As Long, ByRef Algid As Long, ByRef hKey As Long, ByVal dwFlags As Long, ByRef phHash As Long) As Long Private Declare Function CryptDestroyHash Lib "advapi32.dll" (ByRef hHash As Long) As Long Private Declare Function CryptHashData Lib "advapi32.dll" (ByRef hHash As Long, ByVal pbData As String, ByVal dwDataLen As Long, ByVal dwFlags As Long) As Long Private Declare Function CryptReleaseContext Lib "advapi32.dll" (ByRef hProv As Long, ByRef dwFlags As Long) As Long Public Function MD5DigestToHex(ByVal s As String) As String Dim hContext As Long Dim hHash As Long Dim dwDataLen As Long Dim b() As Byte '-- Acquire our crypto context and create a hash object CryptAcquireContext hContext, vbNullChar, vbNullChar, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT CryptCreateHash hContext, ByVal CALG_MD5, ByVal 0&, 0&, hHash '-- Add our data to the hash CryptHashData ByVal hHash, s, Len(s), 0 '-- Get the length of the data in the hash (should always be 16 bytes - 32 hex chars) CryptGetHashParam hHash, HP_HASHSIZE, dwDataLen, 4, 0 '-- Set up data buffer for the hashed data ReDim b(dwDataLen - 1) '-- Get the hashed data CryptGetHashParam hHash, HP_HASHVAL, b(0), dwDataLen, 0 Dim str As String, i As Long '-- Convert to hex For i = 0 To UBound(b) str = str & HexChar(b(i)) Next i MD5DigestToHex = LCase$(str) '-- Clean up CryptDestroyHash hHash CryptReleaseContext hContext, ByVal 0& End Function Private Function HexChar(ByVal b As Byte) As String Dim s As String s = Hex(b) If Len(s) = 1 Then s = "0" & s HexChar = s End Function
The code first acquires a context in which to do our CryptoAPI work, and then creates a hash object so that we can hash some data. We then hash the input string using CryptHashData, and finally get the size of the hashed data (which should always be 16 bytes, for this example because we're using MD5) and then the actual data. The data is in binary format so we then have to convert it to hex (well we don't really, but it's usually more convenient like that). The only thing left to do then is return the value and clean up. You can also change the algorithm that it uses to hash the data by using a different "CALG_xxxx" constant when creating the hash with CryptCreateHash. A list of the supported algorithms can be found here.