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