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 * \param seed A string containing seed data
83 * \param seed_size Length of seed string
84 * Initializes an RNG client.
85 * \returns On success, a non-NULL handle which can be used to fetch random data from \c mono_rand_try_get_bytes. On failure, NULL.
88 mono_rand_init (guchar *seed, gint seed_size)
90 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider = 0;
92 /* try to open crypto provider. */
93 provider = mono_rand_win_open_provider ();
95 /* seed the CSP with the supplied buffer (if present) */
96 if (provider != 0 && seed != NULL) {
97 /* the call we replace the seed with random - this isn't what is
98 * expected from the class library user */
99 guchar *data = g_malloc (seed_size);
101 memcpy (data, seed, seed_size);
102 /* add seeding material to the RNG */
103 mono_rand_win_seed (provider, data, seed_size);
104 /* zeroize and free */
105 memset (data, 0, seed_size);
110 return (gpointer) provider;
114 * mono_rand_try_get_bytes:
115 * \param handle A pointer to an RNG handle. Handle is set to NULL on failure.
116 * \param buffer A buffer into which to write random data.
117 * \param buffer_size Number of bytes to write into buffer.
118 * \param error Set on error.
119 * Extracts bytes from an RNG handle.
120 * \returns FALSE on failure and sets \p error, TRUE on success.
123 mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gint buffer_size, MonoError *error)
125 MONO_WIN32_CRYPT_PROVIDER_HANDLE provider;
130 provider = (MONO_WIN32_CRYPT_PROVIDER_HANDLE) *handle;
132 /* generate random bytes */
133 if (!mono_rand_win_gen (provider, buffer, buffer_size)) {
134 mono_rand_win_close_provider (provider);
135 /* we may have lost our context with CryptoAPI, but all hope isn't lost yet! */
136 provider = mono_rand_win_open_provider ();
139 /* retry generate of random bytes */
140 if (!mono_rand_win_gen (provider, buffer, buffer_size)) {
141 /* failure, close provider */
142 mono_rand_win_close_provider (provider);
147 /* make sure client gets new opened provider handle or NULL on failure */
148 *handle = (gpointer) provider;
150 /* exception will be thrown in managed code */
151 mono_error_set_execution_engine (error, "Failed to gen random bytes (%d)", GetLastError ());
160 * \param handle An RNG handle.
161 * Releases an RNG handle.
164 mono_rand_close (gpointer handle)
166 mono_rand_win_close_provider ((MONO_WIN32_CRYPT_PROVIDER_HANDLE) handle);
168 #endif /* HOST_WIN32 */