Line data Source code
1 : /*
2 : * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * 3. Neither the name of the Institute nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : */
35 :
36 : #include <config.h>
37 :
38 : #include <stdio.h>
39 : #include <stdlib.h>
40 : #include <rand.h>
41 : #include <randi.h>
42 :
43 : #include <roken.h>
44 :
45 : #ifndef O_BINARY
46 : #define O_BINARY 0
47 : #endif
48 :
49 : #ifdef _WIN32
50 : #include<shlobj.h>
51 : #endif
52 :
53 : /**
54 : * @page page_rand RAND - random number
55 : *
56 : * See the library functions here: @ref hcrypto_rand
57 : */
58 :
59 : const static RAND_METHOD *selected_meth = NULL;
60 : static ENGINE *selected_engine = NULL;
61 :
62 : static void
63 1780604 : init_method(void)
64 : {
65 1796537 : if (selected_meth != NULL)
66 1762995 : return;
67 : #if defined(_WIN32)
68 : selected_meth = &hc_rand_w32crypto_method;
69 : #elif defined(__APPLE__)
70 : selected_meth = &hc_rand_unix_method;
71 : #else
72 18189 : selected_meth = &hc_rand_fortuna_method;
73 : #endif
74 : }
75 :
76 : /**
77 : * Seed that random number generator. Secret material can securely be
78 : * feed into the function, they will never be returned.
79 : *
80 : * @param indata seed data
81 : * @param size length seed data
82 : *
83 : * @ingroup hcrypto_rand
84 : */
85 :
86 : void
87 0 : RAND_seed(const void *indata, size_t size)
88 : {
89 0 : init_method();
90 0 : (*selected_meth->seed)(indata, size);
91 0 : }
92 :
93 : /**
94 : * Get a random block from the random generator, can be used for key material.
95 : *
96 : * @param outdata random data
97 : * @param size length random data
98 : *
99 : * @return 1 on success, 0 on failure.
100 : *
101 : * @ingroup hcrypto_rand
102 : */
103 : int
104 1760173 : RAND_bytes(void *outdata, size_t size)
105 : {
106 1760173 : if (size == 0)
107 0 : return 1;
108 1745398 : init_method();
109 1760173 : return (*selected_meth->bytes)(outdata, size);
110 : }
111 :
112 : /**
113 : * Reset and free memory used by the random generator.
114 : *
115 : * @ingroup hcrypto_rand
116 : */
117 :
118 : void
119 0 : RAND_cleanup(void)
120 : {
121 0 : const RAND_METHOD *meth = selected_meth;
122 0 : ENGINE *engine = selected_engine;
123 :
124 0 : selected_meth = NULL;
125 0 : selected_engine = NULL;
126 :
127 0 : if (meth)
128 0 : (*meth->cleanup)();
129 0 : if (engine)
130 0 : ENGINE_finish(engine);
131 0 : }
132 :
133 : /**
134 : * Seed that random number generator. Secret material can securely be
135 : * feed into the function, they will never be returned.
136 : *
137 : * @param indata the input data.
138 : * @param size size of in data.
139 : * @param entropi entropi in data.
140 : *
141 : *
142 : * @ingroup hcrypto_rand
143 : */
144 :
145 : void
146 0 : RAND_add(const void *indata, size_t size, double entropi)
147 : {
148 0 : init_method();
149 0 : (*selected_meth->add)(indata, size, entropi);
150 0 : }
151 :
152 : /**
153 : * Get a random block from the random generator, should NOT be used for key material.
154 : *
155 : * @param outdata random data
156 : * @param size length random data
157 : *
158 : * @return 1 on success, 0 on failure.
159 : *
160 : * @ingroup hcrypto_rand
161 : */
162 :
163 : int
164 0 : RAND_pseudo_bytes(void *outdata, size_t size)
165 : {
166 0 : init_method();
167 0 : return (*selected_meth->pseudorand)(outdata, size);
168 : }
169 :
170 : /**
171 : * Return status of the random generator
172 : *
173 : * @return 1 if the random generator can deliver random data.
174 : *
175 : * @ingroup hcrypto_rand
176 : */
177 :
178 : int
179 36364 : RAND_status(void)
180 : {
181 35206 : init_method();
182 36364 : return (*selected_meth->status)();
183 : }
184 :
185 : /**
186 : * Set the default random method.
187 : *
188 : * @param meth set the new default method.
189 : *
190 : * @return 1 on success.
191 : *
192 : * @ingroup hcrypto_rand
193 : */
194 :
195 : int
196 0 : RAND_set_rand_method(const RAND_METHOD *meth)
197 : {
198 0 : const RAND_METHOD *old = selected_meth;
199 0 : selected_meth = meth;
200 0 : if (old)
201 0 : (*old->cleanup)();
202 0 : if (selected_engine) {
203 0 : ENGINE_finish(selected_engine);
204 0 : selected_engine = NULL;
205 : }
206 0 : return 1;
207 : }
208 :
209 : /**
210 : * Get the default random method.
211 : *
212 : * @ingroup hcrypto_rand
213 : */
214 :
215 : const RAND_METHOD *
216 0 : RAND_get_rand_method(void)
217 : {
218 0 : init_method();
219 0 : return selected_meth;
220 : }
221 :
222 : /**
223 : * Set the default random method from engine.
224 : *
225 : * @param engine use engine, if NULL is passed it, old method and engine is cleared.
226 : *
227 : * @return 1 on success, 0 on failure.
228 : *
229 : * @ingroup hcrypto_rand
230 : */
231 :
232 : int
233 0 : RAND_set_rand_engine(ENGINE *engine)
234 : {
235 0 : const RAND_METHOD *meth, *old = selected_meth;
236 :
237 0 : if (engine) {
238 0 : ENGINE_up_ref(engine);
239 0 : meth = ENGINE_get_RAND(engine);
240 0 : if (meth == NULL) {
241 0 : ENGINE_finish(engine);
242 0 : return 0;
243 : }
244 : } else {
245 0 : meth = NULL;
246 : }
247 :
248 0 : if (old)
249 0 : (*old->cleanup)();
250 :
251 0 : if (selected_engine)
252 0 : ENGINE_finish(selected_engine);
253 :
254 0 : selected_engine = engine;
255 0 : selected_meth = meth;
256 :
257 0 : return 1;
258 : }
259 :
260 : #define RAND_FILE_SIZE 1024
261 :
262 : /**
263 : * Load a a file and feed it into RAND_seed().
264 : *
265 : * @param filename name of file to read.
266 : * @param size minimum size to read.
267 : *
268 : * @ingroup hcrypto_rand
269 : */
270 :
271 : int
272 0 : RAND_load_file(const char *filename, size_t size)
273 : {
274 : unsigned char buf[128];
275 : size_t len;
276 : ssize_t slen;
277 : int fd;
278 :
279 0 : fd = open(filename, O_RDONLY | O_BINARY, 0600);
280 0 : if (fd < 0)
281 0 : return 0;
282 0 : rk_cloexec(fd);
283 0 : len = 0;
284 0 : while(len < size) {
285 0 : slen = read(fd, buf, sizeof(buf));
286 0 : if (slen <= 0)
287 0 : break;
288 0 : RAND_seed(buf, slen);
289 0 : len += slen;
290 : }
291 0 : close(fd);
292 :
293 0 : return len ? 1 : 0;
294 : }
295 :
296 : /**
297 : * Write of random numbers to a file to store for later initiation with RAND_load_file().
298 : *
299 : * @param filename name of file to write.
300 : *
301 : * @return 1 on success and non-one on failure.
302 : * @ingroup hcrypto_rand
303 : */
304 :
305 : int
306 0 : RAND_write_file(const char *filename)
307 : {
308 : unsigned char buf[128];
309 : size_t len;
310 0 : int res = 0, fd;
311 :
312 0 : fd = open(filename, O_WRONLY | O_CREAT | O_BINARY, 0600);
313 0 : if (fd < 0)
314 0 : return 0;
315 0 : rk_cloexec(fd);
316 :
317 0 : len = 0;
318 0 : while(len < RAND_FILE_SIZE) {
319 0 : res = RAND_bytes(buf, sizeof(buf));
320 0 : if (res != 1)
321 0 : break;
322 0 : if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
323 0 : res = 0;
324 0 : break;
325 : }
326 0 : len += sizeof(buf);
327 : }
328 :
329 0 : close(fd);
330 :
331 0 : return res;
332 : }
333 :
334 : /**
335 : * Return the default random state filename for a user to use for
336 : * RAND_load_file(), and RAND_write_file().
337 : *
338 : * @param filename buffer to hold file name.
339 : * @param size size of buffer filename.
340 : *
341 : * @return the buffer filename or NULL on failure.
342 : *
343 : * @ingroup hcrypto_rand
344 : */
345 :
346 : const char *
347 18182 : RAND_file_name(char *filename, size_t size)
348 : {
349 18182 : const char *e = NULL;
350 18182 : int pathp = 0, ret;
351 :
352 18182 : if (!issuid()) {
353 18182 : e = getenv("RANDFILE");
354 18182 : if (e == NULL)
355 18182 : e = getenv("HOME");
356 18182 : if (e)
357 18182 : pathp = 1;
358 : }
359 :
360 : #ifndef _WIN32
361 : /*
362 : * Here we really want to call getpwuid(getuid()) but this will
363 : * cause recursive lookups if the nss library uses
364 : * gssapi/krb5/hcrypto to authenticate to the ldap servers.
365 : *
366 : * So at least return the unix /dev/random if we have one
367 : */
368 18182 : if (e == NULL) {
369 : int fd;
370 :
371 0 : fd = _hc_unix_device_fd(O_RDONLY, &e);
372 0 : if (fd >= 0)
373 0 : close(fd);
374 : }
375 : #else /* Win32 */
376 :
377 : if (e == NULL) {
378 : char profile[MAX_PATH];
379 :
380 : if (SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
381 : SHGFP_TYPE_CURRENT, profile) == S_OK) {
382 : ret = snprintf(filename, size, "%s\\.rnd", profile);
383 :
384 : if (ret > 0 && ret < size)
385 : return filename;
386 : }
387 : }
388 :
389 : #endif
390 :
391 18182 : if (e == NULL)
392 0 : return NULL;
393 :
394 18182 : if (pathp)
395 18761 : ret = snprintf(filename, size, "%s/.rnd", e);
396 : else
397 0 : ret = snprintf(filename, size, "%s", e);
398 :
399 18182 : if (ret <= 0 || ret >= size)
400 0 : return NULL;
401 :
402 18182 : return filename;
403 : }
|