3 * Windows rand support for Mono.
5 * Copyright 2016 Microsoft
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10 #include "mono-error.h"
11 #include "mono-error-internals.h"
12 #include "mono-rand.h"
14 #if defined(HOST_WIN32)
16 #include "mono/utils/mono-rand-windows-internals.h"
18 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
19 #ifndef PROV_INTEL_SEC
20 #define PROV_INTEL_SEC 22
22 #ifndef CRYPT_VERIFY_CONTEXT
23 #define CRYPT_VERIFY_CONTEXT 0xF0000000
26 MONO_WIN32_CRYPT_PROVIDER_HANDLE
27 mono_rand_win_open_provider (void)
29 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider = 0;
31 /* There is no need to create a container for just random data,
32 * so we can use CRYPT_VERIFY_CONTEXT (one call) see:
33 * http://blogs.msdn.com/dangriff/archive/2003/11/19/51709.aspx */
35 /* We first try to use the Intel PIII RNG if drivers are present */
36 if (!CryptAcquireContext (&provider, NULL, NULL, PROV_INTEL_SEC, CRYPT_VERIFY_CONTEXT)) {
37 /* not a PIII or no drivers available, use default RSA CSP */
38 if (!CryptAcquireContext (&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFY_CONTEXT)) {
39 /* exception will be thrown in managed code */
48 mono_rand_win_close_provider (MONO_WIN32_CRYPT_PROVIDER_HANDLE provider)
50 CryptReleaseContext (provider, 0);
54 mono_rand_win_gen (MONO_WIN32_CRYPT_PROVIDER_HANDLE provider, guchar *buffer, size_t buffer_size)
56 return CryptGenRandom (provider, (DWORD) buffer_size, buffer);
60 mono_rand_win_seed (MONO_WIN32_CRYPT_PROVIDER_HANDLE provider, guchar *seed, size_t seed_size)
62 /* add seeding material to the RNG */
63 return CryptGenRandom (provider, (DWORD) seed_size, seed);
65 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
70 * Returns: True if random source is global, false if mono_rand_init can be called repeatedly to get randomness instances.
72 * Initializes entire RNG system. Must be called once per process before calling mono_rand_init.
82 * @seed: A string containing seed data
83 * @seed_size: Length of seed string
85 * Returns: On success, a non-NULL handle which can be used to fetch random data from mono_rand_try_get_bytes. On failure, NULL.
87 * Initializes an RNG client.
90 mono_rand_init (guchar *seed, gint seed_size)
92 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider = 0;
94 /* try to open crypto provider. */
95 provider = mono_rand_win_open_provider ();
97 /* seed the CSP with the supplied buffer (if present) */
98 if (provider != 0 && seed != NULL) {
99 /* the call we replace the seed with random - this isn't what is
100 * expected from the class library user */
101 guchar *data = g_malloc (seed_size);
103 memcpy (data, seed, seed_size);
104 /* add seeding material to the RNG */
105 mono_rand_win_seed (provider, data, seed_size);
106 /* zeroize and free */
107 memset (data, 0, seed_size);
112 return (gpointer) provider;
116 * mono_rand_try_get_bytes:
117 * @handle: A pointer to an RNG handle. Handle is set to NULL on failure.
118 * @buffer: A buffer into which to write random data.
119 * @buffer_size: Number of bytes to write into buffer.
120 * @error: Set on error.
122 * Returns: FALSE on failure and sets @error, TRUE on success.
124 * Extracts bytes from an RNG handle.
127 mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gint buffer_size, MonoError *error)
129 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider;
134 provider = (MONO_WIN32_CRYPT_PROVIDER_HANDLE) *handle;
136 /* generate random bytes */
137 if (!mono_rand_win_gen (provider, buffer, buffer_size)) {
138 mono_rand_win_close_provider (provider);
139 /* we may have lost our context with CryptoAPI, but all hope isn't lost yet! */
140 provider = mono_rand_win_open_provider ();
143 /* retry generate of random bytes */
144 if (!mono_rand_win_gen (provider, buffer, buffer_size)) {
145 /* failure, close provider */
146 mono_rand_win_close_provider (provider);
151 /* make sure client gets new opened provider handle or NULL on failure */
152 *handle = (gpointer) provider;
154 /* exception will be thrown in managed code */
155 mono_error_set_execution_engine (error, "Failed to gen random bytes (%d)", GetLastError ());
164 * @handle: An RNG handle.
166 * Releases an RNG handle.
169 mono_rand_close (gpointer handle)
171 mono_rand_win_close_provider ((MONO_WIN32_CRYPT_PROVIDER_HANDLE) handle);
173 #endif /* HOST_WIN32 */