Use CryptGenRandom(
)
unless you absolutely need entropy, in which
case see Recipe 11.8 and Recipe 11.20 through Recipe 11.23.
Microsoft allows you to get cryptographically strong pseudo-random
numbers using the CryptoAPI function CryptGenRandom(
)
. Unfortunately, there is no provision for any way to get
entropy. The system does collect entropy behind the scenes, which it
uses to improve the quality of the cryptographically strong
pseudo-random numbers it gets.
Therefore, if this interface is being used to bind to the API we
describe in Recipe 11.2, we can only implement spc_rand(
)
and spc_keygen( )
, both of which will
be exactly the same. If you want to try to get actual entropy on
Windows, the only solution as of this writing is to use EGADS, which
we discuss in Recipe 11.8. Alternatively, you can collect it
yourself, as discussed in Recipe 11.20 through Recipe 11.23.
To use CryptGenRand( )
, you must first acquire an
HCRYPTPROV
context. To do this, use the function
CryptAcquireContext(
)
, which we discuss in some detail in Recipe
5.25. With an HCRYPTPROV
context in hand, you can
call CryptGenRandom(
)
, which will return TRUE
if
it is successful; otherwise, it will return FALSE
,
but it should never fail. CryptGenRandom( )
has
the following signature:
BOOL CryptGenRandom(HCRYPTPROV *hProv, DWORD dwLen, BYTE *pbBuffer);
This function has the following arguments:
hProv
Handle to a cryptographic service provider obtained via
CryptAcquireContext( )
.
dwLen
Number of bytes of random data required. The output buffer must be at least this large.
pbBuffer
Buffer into which the random data will be written.
Here we show how to use this function by binding it to the API from Recipe 11.2:
#include <windows.h> #include <wincrypt.h> static HCRYPTPROV hProvider; void spc_rand_init(void) { if (!CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) ExitProcess((UINT)-1); /* Feel free to properly signal an error instead. */ } unsigned char *spc_rand(unsigned char *pbBuffer, size_t cbBuffer) { if (!hProvider) spc_rand_init( ); if (!CryptGenRandom(hProvider, cbBuffer, pbBuffer)) ExitProcess((UINT)-1); /* Feel free to properly signal an error instead. */ return pbBuffer; } unsigned char *spc_keygen(unsigned char *pbBuffer, size_t cbBuffer) { if (!hProvider) spc_rand_init( ); if (!CryptGenRandom(hProvider, cbBuffer, pbBuffer)) ExitProcess((UINT)-1); return pbBuffer; }