2017-02-24 38 views
1

因此,一段時間以來,我通過使用Microsoft強密碼提供程序的MS API調用實現了我自己的MS Access VBA密碼安全僞隨機數生成器(CSPRNG)。它以密碼安全的方式吐出隨機字節0-255(00000000-11111111)。該調用是通過VBA模塊中的幾個DLL函數聲明(調用「advapi32.dll」)完成的。爲什麼CryptAcquireContext在某些計算機上一直返回0(零)?

這裏的問題是,我撥打CryptAcquireContext(...)的電話不是給我一個加密上下文....但只在一些電腦。它在我建立的機器上工作得很好......但不在其他人的機器上。這不是一個VBE參考問題;該DLL存在,並且模塊中的任何調用都不依賴於VBE引用。我嘗試了其他幾家「提供商......」不好。全零。

下面的代碼:

Option Compare Database 
Option Explicit 

Private Const MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider" 
Private Const PROV_RSA_FULL = 1 Private Const CRYPT_VERIFYCONTEXT = 0 



#If VBA7 Then 

    Private Declare PtrSafe 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 Boolean ' 

    Private Declare PtrSafe Function CryptGenRandom Lib "advapi32.dll" _ 
     (ByVal hProv As Long, ByVal dwLen As Long, ByRef pbBuffer As Byte) As Boolean 

    Private Declare PtrSafe Function CryptReleaseContext Lib "advapi32.dll" _ 
     (ByRef hProv As Long, ByVal dwFlagas 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 Boolean ' 

    Private Declare Function CryptGenRandom Lib "advapi32.dll" _ 
     (ByVal hProv As Long, ByVal dwLen As Long, ByRef pbBuffer As Byte) As Boolean 

    Private Declare Function CryptReleaseContext Lib "advapi32.dll" _ 
     (ByRef hProv As Long, ByVal dwFlagas As Long) 

#End If 



Public Function RandomByte() As Byte 

    On Error Resume Next 

    Dim lngContext As Long, bytResult As Byte 

    ' Supposed to dump a value into lngContext... only spitting out zero. 
    Call CryptAcquireContext(lngContext, vbNullString, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) 

    ' Which means THIS ALSO spits out only a zero.... 
    Call CryptGenRandom(lngContext, 1, bytResult) 

    '...and this is crashing for unknown reasons. 
    Call CryptReleaseContext(lngContext, 0) 

    RandomByte = bytResult 

End Function 
+0

你的API聲明不正確。如果你使用'Long'而不是'LongPtr'作爲指針變量,它將在64位執行上下文中失敗。 – Comintern

+0

它在*我的* 64位機器上工作得很好... –

+0

您是否檢查過失敗時的返回值?你現在只是放棄它們。另外,您的Access安裝32位? – Comintern

回答

1

我需要初始化密鑰容器,就像這樣:

Private Const CRYPT_NEWKEYSET = 8 

Call CryptAcquireContext(lngContext, vbNullString, MS_STRONG_PROV, _ 
PROV_RSA_FULL, CRYPT_NEWKEYSET) 

那麼其他的呼叫(使用CRYPT_VERIFYCONTEXT)的作品。

完整模塊:

Option Compare Database 
Option Explicit 

Private Const MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider" 
Private Const PROV_RSA_FULL = 1 
Private Const CRYPT_VERIFYCONTEXT = 0 
Private Const CRYPT_NEWKEYSET = 8 

#If VBA7 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 Boolean ' 

    Private Declare PtrSafe Function CryptGenRandom Lib "advapi32.dll" _ 
    (ByVal hProv As LongPtr, ByVal dwLen As Long, ByRef pbBuffer As Byte) As Boolean 

    Private Declare PtrSafe Function CryptReleaseContext Lib "advapi32.dll" _ 
    (ByRef hProv As LongPtr, ByVal dwFlagas 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 Boolean ' 

    Private Declare Function CryptGenRandom Lib "advapi32.dll" _ 
    (ByVal hProv As Long, ByVal dwLen As Long, ByRef pbBuffer As Byte) As Boolean 

    Private Declare Function CryptReleaseContext Lib "advapi32.dll" _ 
    (ByRef hProv As Long, ByVal dwFlagas As Long) 

#End If 



Public Function RandomByte() As Byte 

    On Error Resume Next 

    Dim lngContext As LongPtr, bytResult As Byte 

    Call CryptAcquireContext(lngContext, vbNullString, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) 

    If Err.LastDllError = -2146893802 Then 

     Call CryptAcquireContext(lngContext, vbNullString, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) 

    End If 

    Call CryptGenRandom(lngContext, 1, bytResult) 

    Call CryptReleaseContext(lngContext, 0) 

    RandomByte = bytResult 

End Function