2003-12-20 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / rand.c
1 /*
2  * rand.c: System.Security.Cryptography.RNGCryptoServiceProvider support
3  *
4  * Author:
5  *      Mark Crichton (crichton@gimp.org)
6  *      Patrik Torstensson (p@rxc.se)
7  *
8  * (C) 2001 Ximian, Inc.
9  *
10  */
11
12 #include <config.h>
13 #include <glib.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/rand.h>
21 #include <mono/metadata/exception.h>
22
23 #if defined (PLATFORM_WIN32)
24
25 #include <WinCrypt.h>
26 \r
27 static int s_providerInitialized = 0;\r
28 static HCRYPTPROV s_provider;\r
29
30 static HCRYPTPROV GetProvider()\r
31 {\r
32     if (s_providerInitialized == 1)\r
33         return s_provider;\r
34 \r
35     if (!CryptAcquireContext (&s_provider, NULL, NULL, PROV_RSA_FULL, 0))  \r
36     {\r
37         if (GetLastError() != NTE_BAD_KEYSET)\r
38             mono_raise_exception (mono_get_exception_execution_engine ("Failed to acquire crypt context"));\r
39 \r
40                 // Generate a new keyset if needed\r
41         if (!CryptAcquireContext (&s_provider, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))\r
42             mono_raise_exception (mono_get_exception_execution_engine ("Failed to acquire crypt context (new keyset)"));\r
43     }\r
44     \r
45     s_providerInitialized =  1;\r
46 \r
47     return s_provider;\r
48 }\r
49
50 void ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGetBytes(MonoObject *self, MonoArray *arry)
51 {
52     guint32 len;
53     guchar *buf;
54
55     len = mono_array_length (arry);
56     buf = mono_array_addr (arry, guchar, 0);
57
58     if (0 == CryptGenRandom (GetProvider(), len, buf))
59        mono_raise_exception (mono_get_exception_execution_engine ("Failed to generate random bytes from CryptAPI"));\r
60 }
61
62 #elif defined (NAME_DEV_RANDOM) && defined (HAVE_CRYPT_RNG)
63
64 #ifndef NAME_DEV_URANDOM
65 #define NAME_DEV_URANDOM "/dev/urandom"
66 #endif
67
68 void 
69 ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGetBytes (MonoObject *self, MonoArray *arry)
70 {
71     guint32 len;
72     gint file;
73     gint err;
74     gint count;
75     guchar *buf;
76
77     len = mono_array_length(arry);
78     buf = mono_array_addr(arry, guchar, 0);
79
80     file = open (NAME_DEV_URANDOM, O_RDONLY);
81
82     if (file < 0)
83             file = open (NAME_DEV_RANDOM, O_RDONLY);
84
85     if (file < 0) {
86         g_warning ("Entropy problem! Can't open %s or %s", NAME_DEV_URANDOM, NAME_DEV_RANDOM);
87
88         mono_raise_exception (mono_get_exception_execution_engine ("Failed to open /dev/urandom or /dev/random device"));\r
89     }
90
91     /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */
92     count = 0;
93     do {
94             err = read(file, buf + count, len - count);
95             count += err;
96     } while (err >= 0 && count < len);
97
98     if (err < 0) {
99         g_warning("Entropy error! Error in read.");
100         mono_raise_exception (mono_get_exception_execution_engine ("Failed to read a random byte from /dev/urandom or /dev/random device"));\r
101     }
102
103     close(file);
104 }
105
106 #else
107
108 void ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGetBytes(MonoObject *self, MonoArray *arry)
109 {
110     mono_raise_exception(mono_get_exception_not_implemented());
111 }
112
113 #endif /* OS definition */