Attribute VB_Name = "basMD5pbe1"
Option Explicit
Option Base 0

Public Function Make_MD5_PBE(sPassword As String, abSalt() As Byte, nCount As Integer) As String
' Derives a password-based key using PBKDF1 algorithm and MD5 hash function. Ref: PKCS#5.
' Uses functions MD5_BytesHexHash() and cnvHexStrFromBytes() from
' CryptoSys (TM) API available from <http://www.cryptosys.net/>.
' This code was written in Visual Basic by David Ireland
' Copyright (C) 2003-6 DI Management Services Pty Ltd.
' First published 22 June 2003. Updated 17 May 2006.

    Dim nRet As Long
    Dim strHexDigest As String
    Dim abMsg() As Byte
    Dim abDigest() As Byte
    Dim nLength As Long
    Dim nLenSalt As Integer
    Dim i As Integer
    
    ' Create concatenation of P || S
    ' Convert password string to Byte array
    abMsg = StrConv(sPassword, vbFromUnicode)
    ' Append salt bytes
    nLenSalt = UBound(abSalt) - LBound(abSalt) + 1
    nLength = Len(sPassword) + nLenSalt
    ReDim Preserve abMsg(nLength - 1)
    For i = 0 To nLenSalt - 1
        abMsg(Len(sPassword) + i) = abSalt(i)
    Next
    
    ' Pre-dimension digest block to be 16 bytes (remember arrays are 0-based)
    ReDim abDigest(API_MAX_MD5_BYTES - 1)
    
    i = 1
    'H(1) = MD5(P || S)
    Debug.Print "P || S =", cnvHexStrFromBytes(abMsg)
    nRet = MD5_BytesHash(abDigest(0), abMsg(0), nLength)
    Debug.Print i, cnvHexStrFromBytes(abDigest)
    
    ' Length of input data is now 16
    nLength = API_MAX_MD5_BYTES
    ' and we just repeatedly re-hash the previous digest
    Do While i < nCount
        ' H(i) = MD5(H(i-1))
        i = i + 1
        nRet = MD5_BytesHash(abDigest(0), abDigest(0), nLength)
        ' For debugging purposes, we'll output some intermediate values
        If (i <= 3 Or nCount - i < 3) Then
            Debug.Print i, cnvHexStrFromBytes(abDigest)
        End If
    Loop
    
    ' Convert final result to a hex string
    strHexDigest = cnvHexStrFromBytes(abDigest)
    Make_MD5_PBE = strHexDigest
End Function

Public Function Test_MD5_PBE()
    Dim sHexKey As String
    Dim abSalt(7) As Byte
    
' Set salt = 78 57 8E 5A 5D 63 CB 06
    abSalt(0) = &H78
    abSalt(1) = &H57
    abSalt(2) = &H8E
    abSalt(3) = &H5A
    abSalt(4) = &H5D
    abSalt(5) = &H63
    abSalt(6) = &HCB
    abSalt(7) = &H6
    sHexKey = Make_MD5_PBE("abc", abSalt, 1000)
    Debug.Print "Derived key = " & sHexKey
' EXPECTED RESULTS:-
' 1            0e8baaeb3ced73cbc9bf4964f321824a
' 2            1f0554e6f8810739258c9abc60a782d5
' 3            aba6fedb4ad3efae8180364e617d9d79
' ...
' 1000         8fd6158bfe81add961241d8e4169d411
'Derived key = 8fd6158bfe81add961241d8e4169d411

End Function

Public Function Test_MD5_PBE_1()
    Dim sHexKey As String
    Dim abSalt(7) As Byte

' Change salt = 7D 60 43 5F 02 E9 E0 AE
    abSalt(0) = &H7D
    abSalt(1) = &H60
    abSalt(2) = &H43
    abSalt(3) = &H5F
    abSalt(4) = &H2
    abSalt(5) = &HE9
    abSalt(6) = &HE0
    abSalt(7) = &HAE
    sHexKey = Make_MD5_PBE("abc", abSalt, 2048)
    Debug.Print "Derived key = " & sHexKey
' EXPECTED RESULTS:-
' 1            4116f55b8bbc73af8e48833958f5bbca
' 2            eb7c2107b18f8227a5da327d1e0c97f7
' 3            504a7312c7a45e2ab15d4633e69b8053
' ...
' 2048         cc584d1ee305fb7ef65926f62e88dfe3
'Derived key = cc584d1ee305fb7ef65926f62e88dfe3
    
End Function