2 * rand.c: System.Security.Cryptography.RNGCryptoServiceProvider support
5 * Mark Crichton (crichton@gimp.org)
6 * Patrik Torstensson (p@rxc.se)
8 * (C) 2001 Ximian, Inc.
14 #include <sys/types.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/rand.h>
21 #include <mono/metadata/exception.h>
23 #if !defined(PLATFORM_WIN32)
24 #include <sys/socket.h>
29 get_entropy_from_server (const char *path, guchar *buf, int len)
34 struct sockaddr_un egd_addr;
36 file = socket (PF_UNIX, SOCK_STREAM, 0);
40 egd_addr.sun_family = AF_UNIX;
41 strncpy (egd_addr.sun_path, path, MONO_SIZEOF_SUNPATH - 1);
42 egd_addr.sun_path [MONO_SIZEOF_SUNPATH-1] = '\0';
43 ret = connect (file, (struct sockaddr *)&egd_addr, sizeof(egd_addr));
48 g_warning ("Entropy problem! Can't create or connect to egd socket %s", path);
49 mono_raise_exception (mono_get_exception_execution_engine ("Failed to open egd socket"));
56 request [0] = 2; /* block until daemon can return enough entropy */
57 request [1] = len < 255 ? len : 255;
59 int sent = write (file, request + count, 2 - count);
62 else if (errno == EINTR)
66 g_warning ("Send egd request failed %d", errno);
67 mono_raise_exception (mono_get_exception_execution_engine ("Failed to send request to egd socket"));
72 while (count != request [1]) {
74 received = read(file, buf + offset, request [1] - count);
78 } else if (received < 0 && errno == EINTR) {
82 g_warning ("Receive egd request failed %d", errno);
83 mono_raise_exception (mono_get_exception_execution_engine ("Failed to get response from egd socket"));
94 #if defined (PLATFORM_WIN32)
98 static int s_providerInitialized = 0;
\r
99 static HCRYPTPROV s_provider;
\r
101 static HCRYPTPROV GetProvider()
\r
103 if (s_providerInitialized == 1)
\r
106 if (!CryptAcquireContext (&s_provider, NULL, NULL, PROV_RSA_FULL, 0))
\r
108 if (GetLastError() != NTE_BAD_KEYSET)
\r
109 mono_raise_exception (mono_get_exception_execution_engine ("Failed to acquire crypt context"));
\r
111 // Generate a new keyset if needed
\r
112 if (!CryptAcquireContext (&s_provider, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
\r
113 mono_raise_exception (mono_get_exception_execution_engine ("Failed to acquire crypt context (new keyset)"));
\r
116 s_providerInitialized = 1;
\r
121 void ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGetBytes(MonoObject *self, MonoArray *arry)
126 len = mono_array_length (arry);
127 buf = mono_array_addr (arry, guchar, 0);
129 if (0 == CryptGenRandom (GetProvider(), len, buf))
130 mono_raise_exception (mono_get_exception_execution_engine ("Failed to generate random bytes from CryptAPI"));
\r
135 #ifndef NAME_DEV_URANDOM
136 #define NAME_DEV_URANDOM "/dev/urandom"
140 ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGetBytes (MonoObject *self, MonoArray *arry)
148 len = mono_array_length(arry);
149 buf = mono_array_addr(arry, guchar, 0);
151 #if defined (NAME_DEV_URANDOM)
152 file = open (NAME_DEV_URANDOM, O_RDONLY);
155 #if defined (NAME_DEV_RANDOM)
157 file = open (NAME_DEV_RANDOM, O_RDONLY);
161 const char *socket_path = getenv("MONO_EGD_SOCKET");
163 if (socket_path == NULL)
164 mono_raise_exception (mono_get_exception_execution_engine ("Failed to open /dev/urandom or /dev/random device, or find egd socket"));
166 get_entropy_from_server (socket_path, mono_array_addr(arry, guchar, 0), mono_array_length(arry));
170 /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */
173 err = read(file, buf + count, len - count);
175 } while (err >= 0 && count < len);
178 g_warning("Entropy error! Error in read.");
179 mono_raise_exception (mono_get_exception_execution_engine ("Failed to read a random byte from /dev/urandom or /dev/random device"));
\r
185 #endif /* OS definition */