2 * mono-rand-windows.c: Windows rand support for Mono.
4 * Copyright 2016 Microsoft
5 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 #include "mono-error.h"
10 #include "mono-error-internals.h"
11 #include "mono-rand.h"
13 #if defined(HOST_WIN32)
15 #include "mono/utils/mono-rand-windows-internals.h"
17 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
18 #ifndef PROV_INTEL_SEC
19 #define PROV_INTEL_SEC 22
21 #ifndef CRYPT_VERIFY_CONTEXT
22 #define CRYPT_VERIFY_CONTEXT 0xF0000000
25 MONO_WIN32_CRYPT_PROVIDER_HANDLE
26 mono_rand_win_open_provider (void)
28 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider = 0;
30 /* There is no need to create a container for just random data,
31 * so we can use CRYPT_VERIFY_CONTEXT (one call) see:
32 * http://blogs.msdn.com/dangriff/archive/2003/11/19/51709.aspx */
34 /* We first try to use the Intel PIII RNG if drivers are present */
35 if (!CryptAcquireContext (&provider, NULL, NULL, PROV_INTEL_SEC, CRYPT_VERIFY_CONTEXT)) {
36 /* not a PIII or no drivers available, use default RSA CSP */
37 if (!CryptAcquireContext (&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFY_CONTEXT)) {
38 /* exception will be thrown in managed code */
47 mono_rand_win_close_provider (MONO_WIN32_CRYPT_PROVIDER_HANDLE provider)
49 CryptReleaseContext (provider, 0);
53 mono_rand_win_gen (MONO_WIN32_CRYPT_PROVIDER_HANDLE provider, guchar *buffer, size_t buffer_size)
55 return CryptGenRandom (provider, (DWORD) buffer_size, buffer);
59 mono_rand_win_seed (MONO_WIN32_CRYPT_PROVIDER_HANDLE provider, guchar *seed, size_t seed_size)
61 /* add seeding material to the RNG */
62 return CryptGenRandom (provider, (DWORD) seed_size, seed);
64 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
69 * Returns: True if random source is global, false if mono_rand_init can be called repeatedly to get randomness instances.
71 * Initializes entire RNG system. Must be called once per process before calling mono_rand_init.
81 * @seed: A string containing seed data
82 * @seed_size: Length of seed string
84 * Returns: On success, a non-NULL handle which can be used to fetch random data from mono_rand_try_get_bytes. On failure, NULL.
86 * Initializes an RNG client.
89 mono_rand_init (guchar *seed, gint seed_size)
91 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider = 0;
93 /* try to open crypto provider. */
94 provider = mono_rand_win_open_provider ();
96 /* seed the CSP with the supplied buffer (if present) */
97 if (provider != 0 && seed != NULL) {
98 /* the call we replace the seed with random - this isn't what is
99 * expected from the class library user */
100 guchar *data = g_malloc (seed_size);
102 memcpy (data, seed, seed_size);
103 /* add seeding material to the RNG */
104 mono_rand_win_seed (provider, data, seed_size);
105 /* zeroize and free */
106 memset (data, 0, seed_size);
111 return (gpointer) provider;
115 * mono_rand_try_get_bytes:
116 * @handle: A pointer to an RNG handle. Handle is set to NULL on failure.
117 * @buffer: A buffer into which to write random data.
118 * @buffer_size: Number of bytes to write into buffer.
119 * @error: Set on error.
121 * Returns: FALSE on failure and sets @error, TRUE on success.
123 * Extracts bytes from an RNG handle.
126 mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gint buffer_size, MonoError *error)
128 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider;
130 mono_error_init (error);
133 provider = (MONO_WIN32_CRYPT_PROVIDER_HANDLE) *handle;
135 /* generate random bytes */
136 if (!mono_rand_win_gen (provider, buffer, buffer_size)) {
137 mono_rand_win_close_provider (provider);
138 /* we may have lost our context with CryptoAPI, but all hope isn't lost yet! */
139 provider = mono_rand_win_open_provider ();
142 /* retry generate of random bytes */
143 if (!mono_rand_win_gen (provider, buffer, buffer_size)) {
144 /* failure, close provider */
145 mono_rand_win_close_provider (provider);
150 /* make sure client gets new opened provider handle or NULL on failure */
151 *handle = (gpointer) provider;
153 /* exception will be thrown in managed code */
154 mono_error_set_execution_engine (error, "Failed to gen random bytes (%d)", GetLastError ());
163 * @handle: An RNG handle.
165 * Releases an RNG handle.
168 mono_rand_close (gpointer handle)
170 mono_rand_win_close_provider ((MONO_WIN32_CRYPT_PROVIDER_HANDLE) handle);
172 #endif /* HOST_WIN32 */