CryptGenRandom spitting out 00000000... (1 Viewer)

DavidJMancini

Registered User.
Local time
Today, 01:04
Joined
Feb 3, 2017
Messages
12
So a while back I implemented my own VBA Cryptographically Secure Pseudo-Random Number Generator (CSPRNG) by using a call to MS API for Microsoft Strong Cryptographic Provider. It spits out random bytes 0-255 (00000000-11111111) in a cryptographically secure fashion. The call is accomplished through several DLL function declarations (calling "advapi32.dll") in the VBA module.

The problem here is that my call to CryptAcquireContext() is NOT giving me a cryptographic context.... but only on some computers. It worked just fine on the machine I built it on... but not on other people's machines. It's NOT a Reference issue; the DLL exists, and none of the calls in the module rely on a VBE Reference. I've tried Microsoft Enhanced Cryptographic Provider... no good. All zeros.

I've attached a sample database with demo form.
 

Attachments

  • CSPRNG.accdb
    880 KB · Views: 79

DavidJMancini

Registered User.
Local time
Today, 01:04
Joined
Feb 3, 2017
Messages
12
I needed to initialize a key container, like so:

Code:
Private Const CRYPT_NEWKEYSET = 8

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

Then the other call (using CRYPT_VERIFYCONTEXT) works.

The full (fixed) module:

Code:
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 Long, 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

Pay special notice to the line(s):

Code:
If Err.LastDllError = -2146893802 Then

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

End If
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 03:04
Joined
Feb 28, 2001
Messages
27,172
David's post is important. The standard for Crypto routines involves establishing a context variable because doing so creates a "behind-the-scenes" data structure in which the Crypto code will store intermediate values. What I don't understand is how that worked on ANY machine without a context setup.
 

Users who are viewing this thread

Top Bottom