【MD5模块和UTF8转换模块】【VBA常用模块】仅适用VB7 64位,已验证

用例,VBA的环境是GB2312的,直接MD5中文字符出来的会与实际通用的UTF8字符数据不一致,所以要先转UTF8再MD5


Sub test()
    Dim f As New MD5
    Dim s As String
    s = "中文字"
    Debug.Print "ANSI:" & f.DigestStrToHexStr(s)
    Dim a() As Byte, b() As Byte
    a = s
    Debug.Print "GB2312:" & f.DigestByteToHexStr(a)
    Debug.Print "GB2312-UTF8:" & f.DigestByteToHexStr(Unicode_To_UTF8(a)) '这里的数据和网上在线MD5验证网站一致。
    b = StrConv(s, vbFromUnicode)
    Debug.Print "ANSI-UTF8:" & f.DigestByteToHexStr(Unicode_To_UTF8(b))
End Sub


复制以下内容,新建模块,粘贴,命名模块名称为ConvUTF8

Option Explicit
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, lpUsedDefaultChar As Long) As Long
Private Declare PtrSafe Function GetLastError Lib "kernel32" () As Long

Public Function UTF8_To_Unicode(ByRef UTF8() As Byte) As Byte()
    Dim i As Long, j As Long, k As Long, l As Long
    Dim Buffer() As Byte
    Dim Length As Long
    Dim Temp As Long
    'Dim bits As Long, Bytes As Long
    Length = UBound(UTF8) - LBound(UTF8) + 1
    If Length > 0 Then ReDim Buffer(0 To Length * 2 - 1) Else Buffer = vbNullString
    For i = LBound(UTF8) To UBound(UTF8)
        Select Case UTF8(i)
        Case &H0& To &H7F&:  k = 0: Temp = UTF8(i) And &H7F&
        Case &HC0& To &HDF&: k = 1: Temp = UTF8(i) And &H1F&
        Case &HE0& To &HEF&: k = 2: Temp = UTF8(i) And &HF&
        Case &HF0& To &HF7&: k = 3: Temp = UTF8(i) And &H7&
        Case &HF8& To &HFB&: k = 4: Temp = UTF8(i) And &H3&
        Case &HFC& To &HFD&: k = 5: Temp = UTF8(i) And &H1&
        Case Else: Call Err.Raise("")
        End Select
        For l = 1 To k
            Temp = Temp * &H40& Or UTF8(i + l) And &H3F&
        Next
        'bits = (8 - (k + 2)) + 6 * k
        'Bytes = (bits + 7) \ 8
        'For l = 0 To Bytes - 1
            'Buffer(j + l) = Temp And &HFF
            'Temp = Temp \ &H100
        'Next
        'j = j + Bytes
        Buffer(j + 0) = Temp And &HFF&
        Buffer(j + 1) = Temp \ &H100& And &HFF&
        j = j + 2
        i = i + k
    Next
    If j Then ReDim Preserve Buffer(0 To j - 1)
    UTF8_To_Unicode = Buffer
End Function

Public Function Unicode_To_UTF8(ByRef Unicode() As Byte) As Byte()
    Dim i As Long, j As Long, k As Long
    Dim Buffer() As Byte
    Dim Length As Long
    Dim Temp As Long
    Length = (UBound(Unicode) - LBound(Unicode) + 1) \ 2
    If Length > 0 Then ReDim Buffer(0 To Length * 3 - 1) Else Buffer = vbNullString
    For i = LBound(Unicode) To UBound(Unicode) Step 2
        Temp = Unicode(i) Or Unicode(i + 1) * &H100&
        k = 1
        If Temp >= &H800& Then
            Buffer(j + 2) = Temp And &H3F& Or &H80&
            Buffer(j + 0) = Buffer(j + 0) Or &HE0&
            Temp = Temp \ &H40&
            k = k + 1
        End If
        If Temp >= &H80& Then
            Buffer(j + 1) = Temp And &H3F& Or &H80&
            Buffer(j + 0) = Buffer(j + 0) Or &HC0&
            Temp = Temp \ &H40&
            k = k + 1
        End If
        
        Buffer(j + 0) = Buffer(j + 0) Or Temp
        j = j + k
    Next
    If j Then ReDim Preserve Buffer(0 To j - 1)
    Unicode_To_UTF8 = Buffer
End Function


复制以下内容,新建类模块,粘贴,命名类模块名称为MD5

Option Explicit

Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
'Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dest As Any, ByVal numBytes As Long)

'/* Constants for MD5Transform routine. */
Private Const S11 As Long = 7
Private Const S12 As Long = 12
Private Const S13 As Long = 17
Private Const S14 As Long = 22
Private Const S21 As Long = 5
Private Const S22 As Long = 9
Private Const S23 As Long = 14
Private Const S24 As Long = 20
Private Const S31 As Long = 4
Private Const S32 As Long = 11
Private Const S33 As Long = 16
Private Const S34 As Long = 23
Private Const S41 As Long = 6
Private Const S42 As Long = 10
Private Const S43 As Long = 15
Private Const S44 As Long = 21

Private LongBits(0 To 31) As Long

Private x(0 To 15) As Long
Private State(0 To 3) As Long
Private Count As Long

'/* ROTATE_LEFT rotates x left n bits.*/
Private Function ROTATE_LEFT(ByVal x As Long, ByVal n As Long) As Long
    Dim After_n As Long, Before_n As Long
    After_n = x And (LongBits(&H1F Xor n) - 1)
    Before_n = (x And &H7FFFFFFF) \ LongBits(32 - n)
    ROTATE_LEFT = After_n * LongBits(n) Or Before_n
    If x And LongBits(&H1F Xor n) Then ROTATE_LEFT = ROTATE_LEFT Or &H80000000
    If x And &H80000000 Then ROTATE_LEFT = ROTATE_LEFT Or LongBits(n - 1)
End Function

'/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
'Rotation is separate from addition to prevent recomputation.*/
Private Sub FF(ByRef a As Long, _
               ByVal b As Long, _
               ByVal c As Long, _
               ByVal d As Long, _
               ByVal x As Long, _
               ByVal s As Long, _
               ByVal ac As Long)
    a = LongOverflowAdd4(a, b And c Or Not b And d, x, ac)
    a = ROTATE_LEFT(a, s)
    a = LongOverflowAdd(a, b)
End Sub

Private Sub GG(ByRef a As Long, _
               ByVal b As Long, _
               ByVal c As Long, _
               ByVal d As Long, _
               ByVal x As Long, _
               ByVal s As Long, _
               ByVal ac As Long)
    a = LongOverflowAdd4(a, b And d Or c And Not d, x, ac)
    a = ROTATE_LEFT(a, s)
    a = LongOverflowAdd(a, b)
End Sub

Private Sub HH(ByRef a As Long, _
               ByVal b As Long, _
               ByVal c As Long, _
               ByVal d As Long, _
               ByVal x As Long, _
               ByVal s As Long, _
               ByVal ac As Long)
    a = LongOverflowAdd4(a, b Xor c Xor d, x, ac)
    a = ROTATE_LEFT(a, s)
    a = LongOverflowAdd(a, b)
End Sub

Private Sub II(ByRef a As Long, _
               ByVal b As Long, _
               ByVal c As Long, _
               ByVal d As Long, _
               ByVal x As Long, _
               ByVal s As Long, _
               ByVal ac As Long)
    a = LongOverflowAdd4(a, c Xor b Or Not d, x, ac)
    a = ROTATE_LEFT(a, s)
    a = LongOverflowAdd(a, b)
End Sub



'/* Construct a MD5 object with a input buffer. */
Public Function DigestByteToHexStr(SourceByte() As Byte) As String
    Call ReSet
    Call Update(SourceByte, UBound(SourceByte) + 1)
    Call Final
    DigestByteToHexStr = LongToString(State(0)) & LongToString(State(1)) & LongToString(State(2)) & LongToString(State(3))
End Function

'/* Construct a MD5 object with a string. */
Public Function DigestStrToHexStr(ByRef SourceString As String) As String
    DigestStrToHexStr = DigestByteToHexStr(StrConv(SourceString, vbFromUnicode))
End Function

'/* Construct a MD5 object with a file. */
Public Function DigestFileToHexStr(ByRef FilePath As String) As String
    If Len(Dir$(FilePath)) Then
        Dim F1 As Long, FileBuffer(0 To 65535) As Byte, i As Long, j As Long
        F1 = FreeFile
        Open FilePath For Binary Access Read As #F1
        Call ReSet
    
        For i = 1 To LOF(F1) \ 65536
            Form1.Cls
            Form1.Print i
            DoEvents
            Get #F1, , FileBuffer
            Call Update(FileBuffer, UBound(FileBuffer) + 1)
        Next
        i = LOF(F1) And &HFFFF&
        If i Then
            Get #F1, , FileBuffer
            Call Update(FileBuffer, i)
        End If
    
        Count = LOF(F1)
        Close #F1
        Call Final
        DigestFileToHexStr = LongToString(State(0)) & LongToString(State(1)) & LongToString(State(2)) & LongToString(State(3))
    End If
End Function

'/* Reset the calculate state */
Private Sub ReSet()
    '/* reset number of bits. */
    Count = 0
    '/* Load magic initialization constants. */
    State(0) = &H67452301
    State(1) = &HEFCDAB89
    State(2) = &H98BADCFE
    State(3) = &H10325476
End Sub

'/* MD5 block update operation. Continues an MD5 message-digest
'operation, processing another message block, and updating thecontext.*/
Private Sub Update(InputArr() As Byte, ByVal Length As Long)
    Dim i As Long, Index As Long, PartLen As Long
    '/* Compute number of bytes mod 64 */
    Index = Count And &H3F
    '/* update number of bits */
    Count = Count + Length
    PartLen = 64 - Index
    Dim Address As LongPtr
    Address = VarPtr(x(0))
    '/* transform as many times as possible. */
    If Length >= PartLen Then
        Call CopyMemory(ByVal Address + Index, InputArr(0), PartLen)
        Call Transform '(Buffer)
        For i = PartLen To Length - 64 Step 64
            Call CopyMemory(ByVal Address + Index, InputArr(i), 64)
            Call Transform '(Buffer)
        Next
        Index = 0
    'Else
        'i = 0
    End If
    '/* Buffer remaining input */
    If Length - i > 0 Then Call CopyMemory(ByVal Address + Index, InputArr(i), Length - i)
End Sub


'/* MD5 finalization. Ends an MD5 message-_digest operation, writing the
'the message _digest and zeroizing the context.*/
Private Sub Final()
    'byte bits[8];
    'uint32 oldState[4];
    'uint32 oldCount[2];
    Dim Padding(0 To 63) As Byte
    Dim Index As Long, PadLen As Long
    Dim TempCount As Long
    TempCount = Count
    '/* Save current state and count. */
    'memcpy(oldState, _state, 16);
    'memcpy(oldCount, _count, 8);

    '/* Save number of bits */
    'encode(_count, bits, 8);
    'Call ZeroMemory(Padding(1), 7)
    Padding(0) = &H80
    '/* Pad out to 56 mod 64. */
    Index = Count And &H3F
    PadLen = IIf(Index < 56, 56 - Index, 120 - Index)
    Call Update(Padding, PadLen)

    '/* Append length (before padding) */
    Call CopyMemory(Padding(0), TempCount * 0.0008@, 8)
    Call Update(Padding, 8)

    '/* Store state in digest */
    'encode(_state, _digest, 16);

    '/* Restore current state and count. */
    'memcpy(_state, oldState, 16);
    'memcpy(_count, oldCount, 8);
End Sub

'/* MD5 basic transformation. Transforms _state based on block. */
Private Sub Transform() 'Block() As Byte)

    Dim a As Long, b As Long, c As Long, d As Long
    a = State(0)
    b = State(1)
    c = State(2)
    d = State(3)
    'Dim x(0 To 15) As Long
    'Call Decode(Block, x, 64)
    'Call CopyMemory(x(0), Block(0), 64)
    '/* Round 1 */
    Call FF(a, b, c, d, x(0), S11, &HD76AA478)  ' /* 1 */
    Call FF(d, a, b, c, x(1), S12, &HE8C7B756)  ' /* 2 */
    Call FF(c, d, a, b, x(2), S13, &H242070DB)  ' /* 3 */
    Call FF(b, c, d, a, x(3), S14, &HC1BDCEEE)  ' /* 4 */
    Call FF(a, b, c, d, x(4), S11, &HF57C0FAF)  ' /* 5 */
    Call FF(d, a, b, c, x(5), S12, &H4787C62A)  ' /* 6 */
    Call FF(c, d, a, b, x(6), S13, &HA8304613)  ' /* 7 */
    Call FF(b, c, d, a, x(7), S14, &HFD469501)  ' /* 8 */
    Call FF(a, b, c, d, x(8), S11, &H698098D8)  ' /* 9 */
    Call FF(d, a, b, c, x(9), S12, &H8B44F7AF)  ' /* 10 */
    Call FF(c, d, a, b, x(10), S13, &HFFFF5BB1) ' /* 11 */
    Call FF(b, c, d, a, x(11), S14, &H895CD7BE) ' /* 12 */
    Call FF(a, b, c, d, x(12), S11, &H6B901122) ' /* 13 */
    Call FF(d, a, b, c, x(13), S12, &HFD987193) ' /* 14 */
    Call FF(c, d, a, b, x(14), S13, &HA679438E) ' /* 15 */
    Call FF(b, c, d, a, x(15), S14, &H49B40821) ' /* 16 */

    '/* Round 2 */
    Call GG(a, b, c, d, x(1), S21, &HF61E2562)  ' /* 17 */
    Call GG(d, a, b, c, x(6), S22, &HC040B340)  ' /* 18 */
    Call GG(c, d, a, b, x(11), S23, &H265E5A51) ' /* 19 */
    Call GG(b, c, d, a, x(0), S24, &HE9B6C7AA)  ' /* 20 */
    Call GG(a, b, c, d, x(5), S21, &HD62F105D)  ' /* 21 */
    Call GG(d, a, b, c, x(10), S22, &H2441453)  ' /* 22 */
    Call GG(c, d, a, b, x(15), S23, &HD8A1E681) ' /* 23 */
    Call GG(b, c, d, a, x(4), S24, &HE7D3FBC8)  ' /* 24 */
    Call GG(a, b, c, d, x(9), S21, &H21E1CDE6)  ' /* 25 */
    Call GG(d, a, b, c, x(14), S22, &HC33707D6) ' /* 26 */
    Call GG(c, d, a, b, x(3), S23, &HF4D50D87)  ' /* 27 */
    Call GG(b, c, d, a, x(8), S24, &H455A14ED)  ' /* 28 */
    Call GG(a, b, c, d, x(13), S21, &HA9E3E905) ' /* 29 */
    Call GG(d, a, b, c, x(2), S22, &HFCEFA3F8)  ' /* 30 */
    Call GG(c, d, a, b, x(7), S23, &H676F02D9)  ' /* 31 */
    Call GG(b, c, d, a, x(12), S24, &H8D2A4C8A) ' /* 32 */

    '/* Round 3 */
    Call HH(a, b, c, d, x(5), S31, &HFFFA3942)  ' /* 33 */
    Call HH(d, a, b, c, x(8), S32, &H8771F681)  ' /* 34 */
    Call HH(c, d, a, b, x(11), S33, &H6D9D6122) ' /* 35 */
    Call HH(b, c, d, a, x(14), S34, &HFDE5380C) ' /* 36 */
    Call HH(a, b, c, d, x(1), S31, &HA4BEEA44)  ' /* 37 */
    Call HH(d, a, b, c, x(4), S32, &H4BDECFA9)  ' /* 38 */
    Call HH(c, d, a, b, x(7), S33, &HF6BB4B60)  ' /* 39 */
    Call HH(b, c, d, a, x(10), S34, &HBEBFBC70) ' /* 40 */
    Call HH(a, b, c, d, x(13), S31, &H289B7EC6) ' /* 41 */
    Call HH(d, a, b, c, x(0), S32, &HEAA127FA)  ' /* 42 */
    Call HH(c, d, a, b, x(3), S33, &HD4EF3085)  ' /* 43 */
    Call HH(b, c, d, a, x(6), S34, &H4881D05)   ' /* 44 */
    Call HH(a, b, c, d, x(9), S31, &HD9D4D039)  ' /* 45 */
    Call HH(d, a, b, c, x(12), S32, &HE6DB99E5) ' /* 46 */
    Call HH(c, d, a, b, x(15), S33, &H1FA27CF8) ' /* 47 */
    Call HH(b, c, d, a, x(2), S34, &HC4AC5665)  ' /* 48 */

    '/* Round 4 */
    Call II(a, b, c, d, x(0), S41, &HF4292244)  ' /* 49 */
    Call II(d, a, b, c, x(7), S42, &H432AFF97)  ' /* 50 */
    Call II(c, d, a, b, x(14), S43, &HAB9423A7) ' /* 51 */
    Call II(b, c, d, a, x(5), S44, &HFC93A039)  ' /* 52 */
    Call II(a, b, c, d, x(12), S41, &H655B59C3) ' /* 53 */
    Call II(d, a, b, c, x(3), S42, &H8F0CCC92)  ' /* 54 */
    Call II(c, d, a, b, x(10), S43, &HFFEFF47D) ' /* 55 */
    Call II(b, c, d, a, x(1), S44, &H85845DD1)  ' /* 56 */
    Call II(a, b, c, d, x(8), S41, &H6FA87E4F)  ' /* 57 */
    Call II(d, a, b, c, x(15), S42, &HFE2CE6E0) ' /* 58 */
    Call II(c, d, a, b, x(6), S43, &HA3014314)  ' /* 59 */
    Call II(b, c, d, a, x(13), S44, &H4E0811A1) ' /* 60 */
    Call II(a, b, c, d, x(4), S41, &HF7537E82)  ' /* 61 */
    Call II(d, a, b, c, x(11), S42, &HBD3AF235) ' /* 62 */
    Call II(c, d, a, b, x(2), S43, &H2AD7D2BB)  ' /* 63 */
    Call II(b, c, d, a, x(9), S44, &HEB86D391)  ' /* 64 */

    State(0) = LongOverflowAdd(State(0), a)
    State(1) = LongOverflowAdd(State(1), b)
    State(2) = LongOverflowAdd(State(2), c)
    State(3) = LongOverflowAdd(State(3), d)
End Sub

'/* Encodes input (ulong) into output (byte). Assumes length is a multiple of 4.*/
'Private Sub Encode(InputArr() As Long, OutputArr() As Byte, Length As Long)
    'Call CopyMemory(OutputArr(0), InputArr(0), 64)
'End Sub

'/* Decodes input (byte) into output (ulong). Assumes length is a multiple of 4.*/
'Private Sub Decode(InputArr() As Byte, OutputArr() As Long, Length As Long)
    'Call CopyMemory(OutputArr(0), InputArr(0), 64)
'End Sub

'Private Function LongOverflowAdd(ByVal a As Double, ByVal b As Double) As Long
'    Dim t As Double
'    t = a + b
'    If t < &H80000000 Then t = t + 4294967296#
'    If t > &H7FFFFFFF Then t = t - 4294967296#
'    LongOverflowAdd = t
'End Function

Private Function LongOverflowAdd(ByVal a As Long, ByVal b As Long) As Long
    If (a Xor b) And &H80000000 Then
        LongOverflowAdd = a + b
    Else
        LongOverflowAdd = (a Xor &H80000000) + b Xor &H80000000
    End If
End Function



'Private Function LongOverflowAdd4(ByVal a As Double, ByVal b As Double, ByVal c As Double, ByVal d As Double) As Long
'    Dim t As Double
'    t = a + b + c + d
'    If t < &H80000000 Then t = t + 4294967296#
'    If t < &H80000000 Then t = t + 4294967296#
'    If t > &H7FFFFFFF Then t = t - 4294967296#
'    If t > &H7FFFFFFF Then t = t - 4294967296#
'    LongOverflowAdd4 = t
'End Function
Private Function LongOverflowAdd4(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long) As Long
    'LongOverflowAdd4 = LongOverflowAdd(LongOverflowAdd(a, b), LongOverflowAdd(c, d))

    If (a Xor b) And &H80000000 Then
        a = a + b
    Else
        a = (a Xor &H80000000) + b Xor &H80000000
    End If
    If (c Xor d) And &H80000000 Then
        c = c + d
    Else
        c = (c Xor &H80000000) + d Xor &H80000000
    End If
    If (a Xor c) And &H80000000 Then
        LongOverflowAdd4 = a + c
    Else
        LongOverflowAdd4 = (a Xor &H80000000) + c Xor &H80000000
    End If

End Function

Private Function LongToString(ByVal Value As Long) As String
    Dim Arr(0 To 3) As Byte, t As Byte
    Call CopyMemory(Arr(0), Value, 4)
    t = Arr(0)
    Arr(0) = Arr(3)
    Arr(3) = t
    t = Arr(1)
    Arr(1) = Arr(2)
    Arr(2) = t
    Call CopyMemory(Value, Arr(0), 4)
    LongToString = Hex$(Value)
    If Len(LongToString) < 8 Then LongToString = String$(8 - Len(LongToString), "0") & LongToString
End Function


Private Sub Class_Initialize()
    Dim i As Long
    LongBits(0) = 1
    For i = 1 To 30
        LongBits(i) = LongBits(i - 1) * 2
    Next
    LongBits(31) = &H80000000
End Sub


发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.0

@2021 yunfeng.net.cn 版权所有
浙ICP备16007973号-1