【问题标题】:Adapt Crypto API (VBA) to use with Access 2010 64 bit调整 Crypto API (VBA) 以与 Access 2010 64 位一起使用
【发布时间】:2017-04-06 11:57:51
【问题描述】:

您好,我有一个 VBA 模块,可以在 32 位 Office 环境 (Access 2010) 中正常工作。我需要调整代码以便在 64 位 Office 环境中也能正常运行。

详细我无法理解句柄和数据类型的结构

私有声明函数 CryptGetProvParam Lib "advapi32.dll".... 私有声明函数 CryptDeriveKey Lib "advapi32.dll".... 私有声明函数CryptEncrypt Lib“advapi32.dll”...... 私有声明函数 CryptDestroyKey Lib "advapi32.dll"... 私有声明函数 CryptDecrypt Lib "advapi32.dll".....

我在互联网上找了很多次,但我没有找到任何有关 Crypto API 的参考资料来了解每个函数的详细信息。

提前感谢您的宝贵时间。

更新:我已经定义了代码你运行良好,但我有一个小问题。 该代码在 32 位版本中运行良好,但在 64 位版本中,当我将长度大于 3 个字符的字符串传递给解密函数时,会产生错误的解密字符串。如果我传递 2 或 3 个字符的字符串长度,则解密会生成正确的密钥,但如果我每次传递 4 个或更多字符,则会生成不同的字符串。

以下代码产生正确的结果

加密CSPConnect sEncrypted = EncryptData("aa", MY_PASSWORD) 加密CSPDisconnect

加密CSPConnect sDecrypted = DecryptData(sEncrypted , MY_PASSWORD) 加密CSPDisconnect

以下代码产生不正确的结果

加密CSPConnect sEncrypted = EncryptData("example", MY_PASSWORD) 加密CSPDisconnect

加密CSPConnect sDecrypted = DecryptData(sEncrypted , MY_PASSWORD) 加密CSPDisconnect

    Option Explicit

#If Win64 Then
Private Declare PtrSafe Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" _
                            (ByRef phProv As LongPtr, ByVal pszContainer As String, ByVal pszProvider As String, _
                             ByVal dwProvType As Long, ByVal dwFlags As Long) As Long

Private Declare PtrSafe Function CryptReleaseContext Lib "advapi32.dll" _
                            (ByVal hProv As LongPtr, ByVal dwFlags As Long) As Long

Private Declare PtrSafe Function CryptCreateHash Lib "advapi32.dll" _
                            (ByVal hProv As LongPtr, ByVal algid As Long, ByVal hKey As LongPtr, ByVal dwFlags As Long, _
                             ByRef phHash As LongPtr) As Boolean

Private Declare PtrSafe Function CryptDestroyHash Lib "advapi32.dll" _
                            (ByVal hHash As LongPtr) As Long

Private Declare PtrSafe Function CryptHashData Lib "advapi32.dll" _
                            (ByVal hHash As LongPtr, pbData As Any, ByVal cbData As Long, ByVal dwFlags As Long) As Long

Private Declare PtrSafe Function CryptGetHashParam Lib "advapi32.dll" _
                            (ByVal hHash As LongPtr, ByVal dwParam As Long, pbData As Any, ByRef pcbData As Long, _
                             ByVal dwFlags As Long) As Long

Private Declare PtrSafe Function CryptDeriveKey Lib "advapi32.dll" _
    (ByVal hProv As LongPtr, ByVal algid As Long, ByVal hBaseData As LongPtr, ByVal dwFlags As Long, _
     ByRef phKey As LongPtr) As Long

Private Declare PtrSafe Function CryptDestroyKey Lib "advapi32.dll" _
    (ByVal hKey As LongPtr) As Long

Private Declare PtrSafe Function CryptEncrypt Lib "advapi32.dll" _
    (ByVal hKey As LongPtr, ByVal hHash As LongPtr, ByVal Final As Boolean, ByVal dwFlags As Long, _
     ByVal pbData As String, ByRef pdwDataLen As Long, ByVal dwBufLen As Long) As Long

Private Declare PtrSafe Function CryptDecrypt Lib "advapi32.dll" _
    (ByVal hKey As LongPtr, _
     ByVal hHash As LongPtr, _
     ByVal Final As Boolean, _
     ByVal dwFlags As Long, _
     ByVal pbData As String, _
     ByRef pdwDataLen As Long) As Boolean

Private Declare PtrSafe Function CryptGetProvParam Lib "advapi32.dll" _
    (ByVal hProv As LongPtr, _
     ByVal dwParam As Long, _
     ByRef pbData As Any, _
     ByRef pdwDataLen As Long, _
     ByVal dwFlags As Long) As Long


#Else

    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 CryptReleaseContext Lib "advapi32.dll" _
                                (ByVal hProv As Long, ByVal dwFlags As Long) As Long
    Private Declare Function CryptCreateHash Lib "advapi32.dll" _
                                (ByVal hProv As Long, ByVal Algid As Long, ByVal hKey As Long, ByVal dwFlags As Long, _
                                 ByRef phHash As Long) As Long
    Private Declare Function CryptDestroyHash Lib "advapi32.dll" _
                                (ByVal hHash As Long) As Long
    Private Declare Function CryptHashData Lib "advapi32.dll" _
                                (ByVal hHash As Long, pbData As Any, ByVal cbData As Long, ByVal dwFlags As Long) As Long
    Private Declare Function CryptGetHashParam Lib "advapi32.dll" _
                                (ByVal hHash As Long, ByVal dwParam As Long, pbData As Any, ByRef pcbData As Long, _
                                 ByVal dwFlags As Long) As Long

    Private Declare Function CryptDeriveKey Lib "advapi32.dll" _
        (ByVal hProv As Long, ByVal Algid As Long, ByVal hBaseData As Long, ByVal dwFlags As Long, _
         ByRef phKey As Long) As Long

    Private Declare Function CryptDestroyKey Lib "advapi32.dll" _
        (ByVal hKey As Long) As Long

    Private Declare Function CryptEncrypt Lib "advapi32.dll" _
        (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, _
         ByVal pbData As String, ByRef pdwDataLen As Long, ByVal dwBufLen As Long) As Long

    Private Declare Function CryptDecrypt Lib "advapi32.dll" _
        (ByVal hKey As Long, _
         ByVal hHash As Long, _
         ByVal Final As Long, _
         ByVal dwFlags As Long, _
         ByVal pbData As String, _
         ByRef pdwDataLen As Long) As Long

    Private Declare Function CryptGetProvParam Lib "advapi32.dll" _
        (ByVal hProv As Long, _
         ByVal dwParam As Long, _
         ByRef pbData As Any, _
         ByRef pdwDataLen As Long, _
         ByVal dwFlags As Long) As Long


#End If

Private Const SERVICE_PROVIDER As String = "Microsoft Base Cryptographic Provider v1.0"
Private Const KEY_CONTAINER As String = "Metallica"
Private Const PROV_RSA_FULL As Long = 1
Private Const PP_NAME As Long = 4
Private Const PP_CONTAINER As Long = 6
Private Const CRYPT_NEWKEYSET As Long = 8
Private Const ALG_CLASS_DATA_ENCRYPT As Long = 24576
Private Const ALG_CLASS_HASH As Long = 32768
Private Const ALG_TYPE_ANY As Long = 0
Private Const ALG_TYPE_STREAM As Long = 2048
Private Const ALG_SID_RC4 As Long = 1
Private Const ALG_SID_MD5 As Long = 3
Private Const CALG_MD5 As Long = ((ALG_CLASS_HASH Or ALG_TYPE_ANY) Or ALG_SID_MD5)
Private Const CALG_RC4 As Long = ((ALG_CLASS_DATA_ENCRYPT Or ALG_TYPE_STREAM) Or ALG_SID_RC4)
Private Const ENCRYPT_ALGORITHM As Long = CALG_RC4
Private Const NUMBER_ENCRYPT_PASSWORD As String = "´o¸sçPQ]"

#If VBA7 And Win64 Then
    Private hCryptProv As LongPtr
#Else
    Private hCryptProv As Long
#End If

Public Function EncryptionCSPConnect() As Boolean
    'Function Adapted
    'Get handle to CSP

    If CryptAcquireContext(hCryptProv, KEY_CONTAINER, SERVICE_PROVIDER, PROV_RSA_FULL, CRYPT_NEWKEYSET) = 0 Then
        If CryptAcquireContext(hCryptProv, KEY_CONTAINER, SERVICE_PROVIDER, PROV_RSA_FULL, 0) = 0 Then
            HandleError "Error during CryptAcquireContext for a new key container." & vbCrLf & _
                        "A container with this name probably already exists."
            EncryptionCSPConnect = False
            Exit Function
        End If
    End If

    EncryptionCSPConnect = True
End Function

Public Sub EncryptionCSPDisconnect()
    'Release provider handle.
   'Function Adapted

    If hCryptProv <> 0 Then
        CryptReleaseContext hCryptProv, 0
    End If
End Sub

Public Function EncryptData(ByVal data As String, ByVal Password As String) As String
    Dim sEncrypted As String
    Dim lEncryptionCount As Long
    Dim sTempPassword As String

    'It is possible that the normal encryption will give you a string
    'containing cr or lf characters which make it difficult to write to files
    'Do a loop changing the password and keep encrypting until the result is ok
    'To be able to decrypt we need to also store the number of loops in the result

    'Try first encryption
    lEncryptionCount = 0
    sTempPassword = Password & lEncryptionCount
    sEncrypted = EncryptDecrypt(data, sTempPassword, True)

    'Loop if this contained a bad character
    Do While (InStr(1, sEncrypted, vbCr) > 0) _
          Or (InStr(1, sEncrypted, vbLf) > 0) _
          Or (InStr(1, sEncrypted, Chr$(0)) > 0) _
          Or (InStr(1, sEncrypted, vbTab) > 0)

        'Try the next password
        lEncryptionCount = lEncryptionCount + 1
        sTempPassword = Password & lEncryptionCount
        sEncrypted = EncryptDecrypt(data, sTempPassword, True)

        'Don't go on for ever, 1 billion attempts should be plenty
        If lEncryptionCount = 99999999 Then
            Err.Raise vbObjectError + 999, "EncryptData", "This data cannot be successfully encrypted"
            EncryptData = ""
            Exit Function
        End If
    Loop

    'Build encrypted string, starting with number of encryption iterations
    EncryptData = EncryptNumber(lEncryptionCount) & sEncrypted
End Function

Public Function DecryptData(ByVal data As String, ByVal Password As String) As String
    Dim lEncryptionCount As Long
    Dim sDecrypted As String
    Dim sTempPassword As String

    'When encrypting we may have gone through a number of iterations
    'How many did we go through?
    lEncryptionCount = DecryptNumber(Mid$(data, 1, 8))

    'start with the last password and work back
    sTempPassword = Password & lEncryptionCount
    sDecrypted = EncryptDecrypt(Mid$(data, 9), sTempPassword, False)

    DecryptData = sDecrypted
End Function

Public Function GetCSPDetails() As String
    Dim lLength As Long
    Dim yContainer() As Byte

    If hCryptProv = 0 Then
        GetCSPDetails = "Not connected to CSP"
        Exit Function
    End If

    'For developer info, show what the CSP & container name is
    lLength = 1000
    ReDim yContainer(lLength)
    If CryptGetProvParam(hCryptProv, PP_NAME, yContainer(0), lLength, 0) <> 0 Then
        GetCSPDetails = "Cryptographic Service Provider name: " & ByteToStr(yContainer, lLength)
    End If
    lLength = 1000
    ReDim yContainer(lLength)
    If CryptGetProvParam(hCryptProv, PP_CONTAINER, yContainer(0), lLength, 0) <> 0 Then
        GetCSPDetails = GetCSPDetails & vbCrLf & "Key Container name: " & ByteToStr(yContainer, lLength)
    End If
End Function

Private Function EncryptDecrypt(ByVal data As String, ByVal Password As String, ByVal encrypt As Boolean) As String

    #If Win64 Then
       Dim hHash As LongPtr
       Dim hKey  As LongPtr
       Dim hHashNull As LongPtr
       Dim hKeyNull As LongPtr

       hHashNull = 0&
       hKeyNull = 0&

    #Else
       Dim hHash As Long
        Dim hKey As Long
        Dim hHashNull As Long
       Dim hKeyNull As Long
    #End If


    Dim lLength As Long
    Dim sTemp As String
    Dim GetValue As Boolean

    If hCryptProv = 0 Then
        HandleError "Not connected to CSP"
        Exit Function
    End If

    '--------------------------------------------------------------------
    'The data will be encrypted with a session key derived from the
    'password.
    'The session key will be recreated when the data is decrypted
    'only if the password used to create the key is available.
    '--------------------------------------------------------------------

    'Create a hash object.
    GetValue = CryptCreateHash(hCryptProv, CALG_MD5, hKeyNull, 0, hHash)

    If GetValue = False Then
        HandleError "Error during CryptCreateHash!"
    End If

    'Hash the password.
    If CryptHashData(hHash, Password, Len(Password), 0) = 0 Then
        HandleError "Error during CryptHashData."
    End If

    'Derive a session key from the hash object.
    If CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM, hHash, 0, hKey) = 0 Then
        HandleError "Error during CryptDeriveKey!"
    End If

    'Do the work
    sTemp = data
    lLength = Len(data)
    If encrypt Then
        'Encrypt data.
        If CryptEncrypt(hKey, hHashNull, True, 0, sTemp, lLength, lLength) = 0 Then
            HandleError "Error during CryptEncrypt."
        End If
    Else
        'Encrypt data.
        GetValue = CryptDecrypt(hKey, hHashNull, True, 0, sTemp, lLength)
        If GetValue = 0 Then
            HandleError "Error during CryptDecrypt."
        End If
    End If

    'This is what we return.
    EncryptDecrypt = Mid$(sTemp, 1, lLength)

    'Destroy session key.
    If hKey <> 0 Then
        CryptDestroyKey hKey
    End If

    'Destroy hash object.
    If hHash <> 0 Then
        CryptDestroyHash hHash
    End If
End Function

Private Sub HandleError(ByVal error As String)
    'You could write the error to the screen or to a file
    Debug.Print error
End Sub

Private Function ByteToStr(ByRef ByteArray() As Byte, ByVal lLength As Long) As String
    Dim i As Long
    For i = LBound(ByteArray) To (LBound(ByteArray) + lLength)
        ByteToStr = ByteToStr & Chr$(ByteArray(i))
    Next i
End Function

Private Function EncryptNumber(ByVal lNumber As Long) As String
    Dim i As Long
    Dim sNumber As String

    sNumber = Format$(lNumber, "00000000")

    For i = 1 To 8
        EncryptNumber = EncryptNumber & Chr$(Asc(Mid$(NUMBER_ENCRYPT_PASSWORD, i, 1)) + Val(Mid$(sNumber, i, 1)))
    Next i
End Function

Private Function DecryptNumber(ByVal sNumber As String) As Long
    Dim i As Long

    For i = 1 To 8
        DecryptNumber = (10 * DecryptNumber) + (Asc(Mid$(sNumber, i, 1)) - Asc(Mid$(NUMBER_ENCRYPT_PASSWORD, i, 1)))
    Next i
End Function

【问题讨论】:

    标签: vba cryptography


    【解决方案1】:

    已解决:问题出在函数上

    私有声明 PtrSafe 函数 CryptHashData Lib "advapi32.dll" _ (ByVal hHash As LongPtr, pbData As Any, ByVal cbData As Long, ByVal dwFlags As Long) 只要

    完全错误,因为被写入接受 BYTE 类型而不是 STRING 数据。

    确切是

    对于 64 位:

    Private Declare PTRSAFE 函数 CryptHashData Lib "advapi32.dll" _ (ByVal hHash As Longptr, _ ByVal pbData 作为字符串,_ ByVal dwDataLen 只要,_ ByVal dwFlags 只要)只要

    对于 32 位:

    私有声明函数 CryptHashData Lib "advapi32.dll" _ (ByVal hHash As Long, _ ByVal pbData 作为字符串,_ ByVal dwDataLen 只要,_ ByVal dwFlags 只要)只要

    以下是绝对列表。谢谢大家。

        Option Explicit
    
    #If Win64 Then
    Private Declare PtrSafe Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" _
                                (ByRef phProv As LongPtr, ByVal pszContainer As String, ByVal pszProvider As String, _
                                 ByVal dwProvType As Long, ByVal dwFlags As Long) As Long
    
    Private Declare PtrSafe Function CryptReleaseContext Lib "advapi32.dll" _
                                (ByVal hProv As LongPtr, ByVal dwFlags As Long) As Long
    
    Private Declare PtrSafe Function CryptCreateHash Lib "advapi32.dll" _
                                (ByVal hProv As LongPtr, ByVal algid As Long, ByVal hKey As LongPtr, ByVal dwFlags As Long, _
                                 ByRef phHash As LongPtr) As Boolean
    
    Private Declare PtrSafe Function CryptDestroyHash Lib "advapi32.dll" _
                                (ByVal hHash As LongPtr) As Long
    
    Private Declare PtrSafe  Function CryptHashData Lib "advapi32.dll" _
            (ByVal hHash As Long, _
             ByVal pbData As String, _
             ByVal dwDataLen As Long, _
             ByVal dwFlags As Long) As Long
    
    
    Private Declare PtrSafe Function CryptGetHashParam Lib "advapi32.dll" _
                                (ByVal hHash As LongPtr, ByVal dwParam As Long, pbData As Any, ByRef pcbData As Long, _
                                 ByVal dwFlags As Long) As Long
    
    Private Declare PtrSafe Function CryptDeriveKey Lib "advapi32.dll" _
        (ByVal hProv As LongPtr, ByVal algid As Long, ByVal hBaseData As LongPtr, ByVal dwFlags As Long, _
         ByRef phKey As LongPtr) As Long
    
    Private Declare PtrSafe Function CryptDestroyKey Lib "advapi32.dll" _
        (ByVal hKey As LongPtr) As Long
    
    Private Declare PtrSafe Function CryptEncrypt Lib "advapi32.dll" _
        (ByVal hKey As LongPtr, ByVal hHash As LongPtr, ByVal Final As Boolean, ByVal dwFlags As Long, _
         ByVal pbData As String, ByRef pdwDataLen As Long, ByVal dwBufLen As Long) As Long
    
    Private Declare PtrSafe Function CryptDecrypt Lib "advapi32.dll" _
        (ByVal hKey As LongPtr, _
         ByVal hHash As LongPtr, _
         ByVal Final As Boolean, _
         ByVal dwFlags As Long, _
         ByVal pbData As String, _
         ByRef pdwDataLen As Long) As Boolean
    
    Private Declare PtrSafe Function CryptGetProvParam Lib "advapi32.dll" _
        (ByVal hProv As LongPtr, _
         ByVal dwParam As Long, _
         ByRef pbData As Any, _
         ByRef pdwDataLen As Long, _
         ByVal dwFlags As Long) As Long
    
    
    #Else
    
        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 CryptReleaseContext Lib "advapi32.dll" _
                                    (ByVal hProv As Long, ByVal dwFlags As Long) As Long
        Private Declare Function CryptCreateHash Lib "advapi32.dll" _
                                    (ByVal hProv As Long, ByVal Algid As Long, ByVal hKey As Long, ByVal dwFlags As Long, _
                                     ByRef phHash As Long) As Long
        Private Declare Function CryptDestroyHash Lib "advapi32.dll" _
                                    (ByVal hHash As Long) As Long
    
       Private Declare PtrSafe  Function CryptHashData Lib "advapi32.dll" _
            (ByVal hHash As Long, _
             ByVal pbData As String, _
             ByVal dwDataLen As Long, _
             ByVal dwFlags As Long) As Long
    
        Private Declare Function CryptGetHashParam Lib "advapi32.dll" _
                                    (ByVal hHash As Long, ByVal dwParam As Long, pbData As Any, ByRef pcbData As Long, _
                                     ByVal dwFlags As Long) As Long
    
        Private Declare Function CryptDeriveKey Lib "advapi32.dll" _
            (ByVal hProv As Long, ByVal Algid As Long, ByVal hBaseData As Long, ByVal dwFlags As Long, _
             ByRef phKey As Long) As Long
    
        Private Declare Function CryptDestroyKey Lib "advapi32.dll" _
            (ByVal hKey As Long) As Long
    
        Private Declare Function CryptEncrypt Lib "advapi32.dll" _
            (ByVal hKey As Long, ByVal hHash As Long, ByVal Final As Long, ByVal dwFlags As Long, _
             ByVal pbData As String, ByRef pdwDataLen As Long, ByVal dwBufLen As Long) As Long
    
        Private Declare Function CryptDecrypt Lib "advapi32.dll" _
            (ByVal hKey As Long, _
             ByVal hHash As Long, _
             ByVal Final As Long, _
             ByVal dwFlags As Long, _
             ByVal pbData As String, _
             ByRef pdwDataLen As Long) As Long
    
        Private Declare Function CryptGetProvParam Lib "advapi32.dll" _
            (ByVal hProv As Long, _
             ByVal dwParam As Long, _
             ByRef pbData As Any, _
             ByRef pdwDataLen As Long, _
             ByVal dwFlags As Long) As Long
    
    
    #End If
    
    Private Const SERVICE_PROVIDER As String = "Microsoft Base Cryptographic Provider v1.0"
    Private Const KEY_CONTAINER As String = "Metallica"
    Private Const PROV_RSA_FULL As Long = 1
    Private Const PP_NAME As Long = 4
    Private Const PP_CONTAINER As Long = 6
    Private Const CRYPT_NEWKEYSET As Long = 8
    Private Const ALG_CLASS_DATA_ENCRYPT As Long = 24576
    Private Const ALG_CLASS_HASH As Long = 32768
    Private Const ALG_TYPE_ANY As Long = 0
    Private Const ALG_TYPE_STREAM As Long = 2048
    Private Const ALG_SID_RC4 As Long = 1
    Private Const ALG_SID_MD5 As Long = 3
    Private Const CALG_MD5 As Long = ((ALG_CLASS_HASH Or ALG_TYPE_ANY) Or ALG_SID_MD5)
    Private Const CALG_RC4 As Long = ((ALG_CLASS_DATA_ENCRYPT Or ALG_TYPE_STREAM) Or ALG_SID_RC4)
    Private Const ENCRYPT_ALGORITHM As Long = CALG_RC4
    Private Const NUMBER_ENCRYPT_PASSWORD As String = "´o¸sçPQ]"
    
    #If VBA7 And Win64 Then
        Private hCryptProv As LongPtr
    #Else
        Private hCryptProv As Long
    #End If
    
    Public Function EncryptionCSPConnect() As Boolean
        'Function Adapted
        'Get handle to CSP
    
        If CryptAcquireContext(hCryptProv, KEY_CONTAINER, SERVICE_PROVIDER, PROV_RSA_FULL, CRYPT_NEWKEYSET) = 0 Then
            If CryptAcquireContext(hCryptProv, KEY_CONTAINER, SERVICE_PROVIDER, PROV_RSA_FULL, 0) = 0 Then
                HandleError "Error during CryptAcquireContext for a new key container." & vbCrLf & _
                            "A container with this name probably already exists."
                EncryptionCSPConnect = False
                Exit Function
            End If
        End If
    
        EncryptionCSPConnect = True
    End Function
    
    Public Sub EncryptionCSPDisconnect()
        'Release provider handle.
       'Function Adapted
    
        If hCryptProv <> 0 Then
            CryptReleaseContext hCryptProv, 0
        End If
    End Sub
    
    Public Function EncryptData(ByVal data As String, ByVal Password As String) As String
        Dim sEncrypted As String
        Dim lEncryptionCount As Long
        Dim sTempPassword As String
    
        'It is possible that the normal encryption will give you a string
        'containing cr or lf characters which make it difficult to write to files
        'Do a loop changing the password and keep encrypting until the result is ok
        'To be able to decrypt we need to also store the number of loops in the result
    
        'Try first encryption
        lEncryptionCount = 0
        sTempPassword = Password & lEncryptionCount
        sEncrypted = EncryptDecrypt(data, sTempPassword, True)
    
        'Loop if this contained a bad character
        Do While (InStr(1, sEncrypted, vbCr) > 0) _
              Or (InStr(1, sEncrypted, vbLf) > 0) _
              Or (InStr(1, sEncrypted, Chr$(0)) > 0) _
              Or (InStr(1, sEncrypted, vbTab) > 0)
    
            'Try the next password
            lEncryptionCount = lEncryptionCount + 1
            sTempPassword = Password & lEncryptionCount
            sEncrypted = EncryptDecrypt(data, sTempPassword, True)
    
            'Don't go on for ever, 1 billion attempts should be plenty
            If lEncryptionCount = 99999999 Then
                Err.Raise vbObjectError + 999, "EncryptData", "This data cannot be successfully encrypted"
                EncryptData = ""
                Exit Function
            End If
        Loop
    
        'Build encrypted string, starting with number of encryption iterations
        EncryptData = EncryptNumber(lEncryptionCount) & sEncrypted
    End Function
    
    Public Function DecryptData(ByVal data As String, ByVal Password As String) As String
        Dim lEncryptionCount As Long
        Dim sDecrypted As String
        Dim sTempPassword As String
    
        'When encrypting we may have gone through a number of iterations
        'How many did we go through?
        lEncryptionCount = DecryptNumber(Mid$(data, 1, 8))
    
        'start with the last password and work back
        sTempPassword = Password & lEncryptionCount
        sDecrypted = EncryptDecrypt(Mid$(data, 9), sTempPassword, False)
    
        DecryptData = sDecrypted
    End Function
    
    Public Function GetCSPDetails() As String
        Dim lLength As Long
        Dim yContainer() As Byte
    
        If hCryptProv = 0 Then
            GetCSPDetails = "Not connected to CSP"
            Exit Function
        End If
    
        'For developer info, show what the CSP & container name is
        lLength = 1000
        ReDim yContainer(lLength)
        If CryptGetProvParam(hCryptProv, PP_NAME, yContainer(0), lLength, 0) <> 0 Then
            GetCSPDetails = "Cryptographic Service Provider name: " & ByteToStr(yContainer, lLength)
        End If
        lLength = 1000
        ReDim yContainer(lLength)
        If CryptGetProvParam(hCryptProv, PP_CONTAINER, yContainer(0), lLength, 0) <> 0 Then
            GetCSPDetails = GetCSPDetails & vbCrLf & "Key Container name: " & ByteToStr(yContainer, lLength)
        End If
    End Function
    
    Private Function EncryptDecrypt(ByVal data As String, ByVal Password As String, ByVal encrypt As Boolean) As String
    
        #If Win64 Then
           Dim hHash As LongPtr
           Dim hKey  As LongPtr
           Dim hHashNull As LongPtr
           Dim hKeyNull As LongPtr
    
           hHashNull = 0&
           hKeyNull = 0&
    
        #Else
           Dim hHash As Long
            Dim hKey As Long
            Dim hHashNull As Long
           Dim hKeyNull As Long
        #End If
    
    
        Dim lLength As Long
        Dim sTemp As String
        Dim GetValue As Boolean
    
        If hCryptProv = 0 Then
            HandleError "Not connected to CSP"
            Exit Function
        End If
    
        '--------------------------------------------------------------------
        'The data will be encrypted with a session key derived from the
        'password.
        'The session key will be recreated when the data is decrypted
        'only if the password used to create the key is available.
        '--------------------------------------------------------------------
    
        'Create a hash object.
        GetValue = CryptCreateHash(hCryptProv, CALG_MD5, hKeyNull, 0, hHash)
    
        If GetValue = False Then
            HandleError "Error during CryptCreateHash!"
        End If
    
        'Hash the password.
        If CryptHashData(hHash, Password, Len(Password), 0) = 0 Then
            HandleError "Error during CryptHashData."
        End If
    
        'Derive a session key from the hash object.
        If CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM, hHash, 0, hKey) = 0 Then
            HandleError "Error during CryptDeriveKey!"
        End If
    
        'Do the work
        sTemp = data
        lLength = Len(data)
        If encrypt Then
            'Encrypt data.
            If CryptEncrypt(hKey, hHashNull, True, 0, sTemp, lLength, lLength) = 0 Then
                HandleError "Error during CryptEncrypt."
            End If
        Else
            'Encrypt data.
            GetValue = CryptDecrypt(hKey, hHashNull, True, 0, sTemp, lLength)
            If GetValue = 0 Then
                HandleError "Error during CryptDecrypt."
            End If
        End If
    
        'This is what we return.
        EncryptDecrypt = Mid$(sTemp, 1, lLength)
    
        'Destroy session key.
        If hKey <> 0 Then
            CryptDestroyKey hKey
        End If
    
        'Destroy hash object.
        If hHash <> 0 Then
            CryptDestroyHash hHash
        End If
    End Function
    
    Private Sub HandleError(ByVal error As String)
        'You could write the error to the screen or to a file
        Debug.Print error
    End Sub
    
    Private Function ByteToStr(ByRef ByteArray() As Byte, ByVal lLength As Long) As String
        Dim i As Long
        For i = LBound(ByteArray) To (LBound(ByteArray) + lLength)
            ByteToStr = ByteToStr & Chr$(ByteArray(i))
        Next i
    End Function
    
    Private Function EncryptNumber(ByVal lNumber As Long) As String
        Dim i As Long
        Dim sNumber As String
    
        sNumber = Format$(lNumber, "00000000")
    
        For i = 1 To 8
            EncryptNumber = EncryptNumber & Chr$(Asc(Mid$(NUMBER_ENCRYPT_PASSWORD, i, 1)) + Val(Mid$(sNumber, i, 1)))
        Next i
    End Function
    
    Private Function DecryptNumber(ByVal sNumber As String) As Long
        Dim i As Long
    
        For i = 1 To 8
            DecryptNumber = (10 * DecryptNumber) + (Asc(Mid$(sNumber, i, 1)) - Asc(Mid$(NUMBER_ENCRYPT_PASSWORD, i, 1)))
        Next i
    End Function
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 2022-07-12
      相关资源
      最近更新 更多