[coop] Refactor/reuse mono_value_box_handle/mono_value_box_checked and reduce raw...
[mono-project.git] / mono / utils / mono-rand-windows.c
blob2f0ef958c14c5744cb277c4a182f752fbba3bb58
1 /**
2 * \file
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.
7 */
8 #include <config.h>
9 #include <glib.h>
10 #ifdef HOST_WIN32
11 #include "mono-error.h"
12 #include "mono-error-internals.h"
13 #include "mono-rand.h"
14 #include <windows.h>
15 #include <bcrypt.h>
16 #include <limits.h>
18 // This implementation requires Windows 7 or newer.
20 #define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
21 const static char mono_rand_provider [ ] = "BCryptGenRandom";
23 /**
24 * mono_rand_open:
26 * Returns: True if random source is global, false if mono_rand_init can be called repeatedly to get randomness instances.
28 * Initializes entire RNG system. Must be called once per process before calling mono_rand_init.
30 gboolean
31 mono_rand_open (void)
33 return TRUE;
36 /**
37 * mono_rand_init:
38 * \param seed A string containing seed data
39 * \param seed_size Length of seed string
40 * Initializes an RNG client.
41 * \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.
43 gpointer
44 mono_rand_init (const guchar *seed, gssize seed_size)
46 // NULL will be interpreted as failure; return arbitrary nonzero pointer
47 return (gpointer)mono_rand_provider;
50 /**
51 * mono_rand_try_get_bytes:
52 * \param handle A pointer to an RNG handle. Handle is set to NULL on failure.
53 * \param buffer A buffer into which to write random data.
54 * \param buffer_size Number of bytes to write into buffer.
55 * \param error Set on error.
56 * Extracts bytes from an RNG handle.
57 * \returns FALSE on failure and sets \p error, TRUE on success.
59 gboolean
60 mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gssize buffer_size, MonoError *error)
62 g_assert (buffer || !buffer_size);
63 error_init (error);
64 g_assert (handle);
65 gpointer const handle_value = *handle;
66 g_assert (handle_value == 0 || handle_value == mono_rand_provider);
67 if (!handle_value)
68 return FALSE;
69 while (buffer_size > 0) {
70 ULONG const size = (ULONG)MIN (buffer_size, ULONG_MAX);
71 NTSTATUS const status = BCryptGenRandom (0, buffer, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
72 if (!BCRYPT_SUCCESS (status)) {
73 mono_error_set_execution_engine (error, "Failed to gen random bytes (%ld)", status);
74 // failure, clear provider for future attempts
75 *handle = 0;
76 return FALSE;
78 buffer += size;
79 buffer_size -= size;
81 return TRUE;
84 /**
85 * mono_rand_close:
86 * \param handle An RNG handle.
87 * Releases an RNG handle.
89 void
90 mono_rand_close (gpointer handle)
92 g_assert (handle == 0 || handle == mono_rand_provider);
94 #endif /* HOST_WIN32 */