0
|
1 #include <stdio.h>
|
|
2 #include <stdlib.h>
|
|
3 #include <stdint.h>
|
|
4
|
|
5 #include "librandom.h"
|
|
6
|
|
7 #ifdef _WIN32
|
|
8 # define RANDOM_WIN32
|
|
9 #elif defined(__MACH__) && defined(__APPLE__)
|
|
10 # define RANDOM_ARC4RANDOM
|
|
11 #else
|
|
12 # define RANDOM_UNIX
|
|
13 #endif
|
|
14
|
|
15 #ifdef RANDOM_WIN32
|
|
16 # include <windows.h>
|
|
17 # include <wincrypt.h>
|
|
18 #endif
|
|
19
|
|
20 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x)))
|
|
21
|
|
22 /* NOTE: I am not sure if other platforms provide real APIs for good
|
|
23 * randomness. Macintosh provides SetRandomSeed and RandomBits, but I
|
|
24 * am skeptical of its use as a good random number generator. */
|
|
25
|
|
26 #ifdef RANDOM_UNIX
|
|
27
|
|
28 struct random_unix {
|
|
29 FILE *f;
|
|
30 };
|
|
31
|
|
32 static void random_unix_close(struct random *r)
|
|
33 {
|
|
34 struct random_unix *ru = r->userdata;
|
|
35
|
|
36 if (ru->f)
|
|
37 fclose(ru->f);
|
|
38
|
|
39 free(ru);
|
|
40 }
|
|
41
|
|
42 static size_t random_unix_read(struct random *r, void *ptr, size_t s)
|
|
43 {
|
|
44 struct random_unix *ru = r->userdata;
|
|
45
|
|
46 return fread(ptr, s, 1, ru->f);
|
|
47 }
|
|
48
|
|
49 static int random_unix_init(struct random *r)
|
|
50 {
|
|
51 /* hmmm. */
|
|
52 static const char *names[] = {
|
|
53 "/dev/random",
|
|
54 "/dev/urandom",
|
|
55 };
|
|
56 struct random_unix *ru = malloc(sizeof(*ru));
|
|
57 size_t i;
|
|
58
|
|
59 for (i = 0; i < ARRAY_SIZE(names); i++) {
|
|
60 ru->f = fopen(names[i], "rb");
|
|
61 if (ru->f)
|
|
62 goto gotdevice;
|
|
63 }
|
|
64
|
|
65 free(ru);
|
|
66 return -1;
|
|
67
|
|
68 gotdevice:
|
|
69
|
|
70 r->userdata = ru;
|
|
71 r->close = random_unix_close;
|
|
72 r->read = random_unix_read;
|
|
73
|
|
74 return 0;
|
|
75 }
|
|
76
|
|
77 #endif
|
|
78
|
|
79 /* ------------------------------------------------------------------------ */
|
|
80
|
|
81 #ifdef RANDOM_ARC4RANDOM
|
|
82
|
|
83 static size_t random_arc4random_read(struct random *r, void *ptr, size_t s)
|
|
84 {
|
|
85 size_t l = s;
|
|
86
|
|
87 while (l > 0) {
|
|
88 size_t amt;
|
|
89 uint32_t x;
|
|
90
|
|
91 amt = MIN(sizeof(x), l);
|
|
92 x = arc4random();
|
|
93
|
|
94 memcpy(ptr, &x, amt);
|
|
95
|
|
96 ptr += amt;
|
|
97 l -= amt;
|
|
98 }
|
|
99
|
|
100 return s;
|
|
101 }
|
|
102
|
|
103 static void random_arc4random_close(struct random *r)
|
|
104 {
|
|
105 /* nothing */
|
|
106 }
|
|
107
|
|
108 static int random_arc4random_init(struct random *r)
|
|
109 {
|
|
110 /* always successful */
|
|
111 r->read = random_arc4random_read;
|
|
112 r->close = random_arc4random_close;
|
|
113 return 0;
|
|
114 }
|
|
115
|
|
116 #endif
|
|
117
|
|
118 /* ------------------------------------------------------------------------ */
|
|
119
|
|
120 #ifdef RANDOM_WIN32
|
|
121
|
|
122 typedef BOOL (*pADVAPI32_CryptReleaseContext)(HCRYPTPROV hProv, DWORD dwFlags);
|
|
123 typedef BOOL (*pADVAPI32_CryptGenRandom)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
|
|
124 typedef BOOL (*pADVAPI32_CryptAcquireContextA)(HCRYPTPROV *phProv, LPCSTR szContainer, LPCSTR szProvider, DWORD dwProvType,DWORD dwFlags);
|
|
125
|
|
126 struct random_win32 {
|
|
127 HCRYPTPROV c;
|
|
128
|
|
129 HMODULE advapi32;
|
|
130 pADVAPI32_CryptReleaseContext ADVAPI32_CryptReleaseContext;
|
|
131 pADVAPI32_CryptGenRandom ADVAPI32_CryptGenRandom;
|
|
132 pADVAPI32_CryptAcquireContextA ADVAPI32_CryptAcquireContextA;
|
|
133 };
|
|
134
|
|
135 static void random_win32_close(struct random *r)
|
|
136 {
|
|
137 struct random_win32 *rw = r->userdata;
|
|
138
|
|
139 rw->ADVAPI32_CryptReleaseContext(rw->c, 0);
|
|
140 FreeLibrary(rw->advapi32);
|
|
141
|
|
142 free(rw);
|
|
143 }
|
|
144
|
|
145 static size_t random_win32_read(struct random *r, void *ptr, size_t s)
|
|
146 {
|
|
147 struct random_win32 *rw = r->userdata;
|
|
148
|
|
149 if (!rw->ADVAPI32_CryptGenRandom(rw->c, s, ptr))
|
|
150 return 0;
|
|
151
|
|
152 return s;
|
|
153 }
|
|
154
|
|
155 static int random_win32_init(struct random *r)
|
|
156 {
|
|
157 HCRYPTPROV c;
|
|
158 struct random_win32 *rw;
|
|
159
|
|
160 rw = malloc(sizeof(*rw));
|
|
161 if (!rw)
|
|
162 return -2;
|
|
163
|
|
164 rw->advapi32 = LoadLibraryA("ADVAPI32.DLL");
|
|
165 if (!rw->advapi32)
|
|
166 return -3;
|
|
167
|
|
168 #define LOADFUNC(x) \
|
|
169 rw->ADVAPI32_##x = (pADVAPI32_##x)GetProcAddress(rw->advapi32, #x); \
|
|
170 if (!rw->ADVAPI32_##x) \
|
|
171 return -4
|
|
172
|
|
173 LOADFUNC(CryptAcquireContextA);
|
|
174 LOADFUNC(CryptGenRandom);
|
|
175 LOADFUNC(CryptReleaseContext);
|
|
176
|
|
177 if (!rw->ADVAPI32_CryptAcquireContextA(&c, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
|
|
178 return -1;
|
|
179
|
|
180
|
|
181 rw->c = c;
|
|
182
|
|
183 r->userdata = rw;
|
|
184 r->close = random_win32_close;
|
|
185 r->read = random_win32_read;
|
|
186 return 0;
|
|
187 }
|
|
188
|
|
189 #endif
|
|
190
|
|
191 /* ------------------------------------------------------------------------ */
|
|
192 /* platform-independent routines */
|
|
193
|
|
194 int random_init(struct random *r)
|
|
195 {
|
|
196 int i;
|
|
197
|
|
198 int (*funcs[])(struct random *r) = {
|
|
199 #ifdef RANDOM_ARC4RANDOM
|
|
200 random_arc4random_init,
|
|
201 #endif
|
|
202 #ifdef RANDOM_UNIX
|
|
203 random_unix_init,
|
|
204 #endif
|
|
205 #ifdef RANDOM_WIN32
|
|
206 random_win32_init,
|
|
207 #endif
|
|
208 NULL,
|
|
209 };
|
|
210
|
|
211 for (i = 0; funcs[i]; i++)
|
|
212 if (!funcs[i](r))
|
|
213 return 0;
|
|
214
|
|
215 return -1;
|
|
216 }
|
|
217
|
|
218 void random_close(struct random *r)
|
|
219 {
|
|
220 r->close(r);
|
|
221 }
|
|
222
|
|
223 size_t random_read(struct random *r, void *ptr, size_t s)
|
|
224 {
|
|
225 return r->read(r, ptr, s);
|
|
226 }
|