b02f938c5457a6d3e1a1455494b3303d506329b2
[openafs.git] / src / external / heimdal / hcrypto / rand.c
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 /**
50  * @page page_rand RAND - random number
51  *
52  * See the library functions here: @ref hcrypto_rand
53  */
54
55 const static RAND_METHOD *selected_meth = NULL;
56 static ENGINE *selected_engine = NULL;
57
58 static void
59 init_method(void)
60 {
61     if (selected_meth != NULL)
62         return;
63 #if defined(_WIN32)
64     selected_meth = &hc_rand_w32crypto_method;
65 #elif defined(__APPLE__)
66     selected_meth = &hc_rand_unix_method;
67 #else
68     selected_meth = &hc_rand_fortuna_method;
69 #endif
70 }
71
72 /**
73  * Seed that random number generator. Secret material can securely be
74  * feed into the function, they will never be returned.
75  *
76  * @param indata seed data
77  * @param size length seed data
78  *
79  * @ingroup hcrypto_rand
80  */
81
82 void
83 RAND_seed(const void *indata, size_t size)
84 {
85     init_method();
86     (*selected_meth->seed)(indata, size);
87 }
88
89 /**
90  * Get a random block from the random generator, can be used for key material.
91  *
92  * @param outdata random data
93  * @param size length random data
94  *
95  * @return 1 on success, 0 on failure.
96  *
97  * @ingroup hcrypto_rand
98  */
99 int
100 RAND_bytes(void *outdata, size_t size)
101 {
102     if (size == 0)
103         return 1;
104     init_method();
105     return (*selected_meth->bytes)(outdata, size);
106 }
107
108 /**
109  * Reset and free memory used by the random generator.
110  *
111  * @ingroup hcrypto_rand
112  */
113
114 void
115 RAND_cleanup(void)
116 {
117     const RAND_METHOD *meth = selected_meth;
118     ENGINE *engine = selected_engine;
119
120     selected_meth = NULL;
121     selected_engine = NULL;
122
123     if (meth)
124         (*meth->cleanup)();
125     if (engine)
126         ENGINE_finish(engine);
127 }
128
129 /**
130  * Seed that random number generator. Secret material can securely be
131  * feed into the function, they will never be returned.
132  *
133  * @param indata the input data.
134  * @param size size of in data.
135  * @param entropi entropi in data.
136  *
137  *
138  * @ingroup hcrypto_rand
139  */
140
141 void
142 RAND_add(const void *indata, size_t size, double entropi)
143 {
144     init_method();
145     (*selected_meth->add)(indata, size, entropi);
146 }
147
148 /**
149  * Get a random block from the random generator, should NOT be used for key material.
150  *
151  * @param outdata random data
152  * @param size length random data
153  *
154  * @return 1 on success, 0 on failure.
155  *
156  * @ingroup hcrypto_rand
157  */
158
159 int
160 RAND_pseudo_bytes(void *outdata, size_t size)
161 {
162     init_method();
163     return (*selected_meth->pseudorand)(outdata, size);
164 }
165
166 /**
167  * Return status of the random generator
168  *
169  * @return 1 if the random generator can deliver random data.
170  *
171  * @ingroup hcrypto_rand
172  */
173
174 int
175 RAND_status(void)
176 {
177     init_method();
178     return (*selected_meth->status)();
179 }
180
181 /**
182  * Set the default random method.
183  *
184  * @param meth set the new default method.
185  *
186  * @return 1 on success.
187  *
188  * @ingroup hcrypto_rand
189  */
190
191 int
192 RAND_set_rand_method(const RAND_METHOD *meth)
193 {
194     const RAND_METHOD *old = selected_meth;
195     selected_meth = meth;
196     if (old)
197         (*old->cleanup)();
198     if (selected_engine) {
199         ENGINE_finish(selected_engine);
200         selected_engine = NULL;
201     }
202     return 1;
203 }
204
205 /**
206  * Get the default random method.
207  *
208  * @ingroup hcrypto_rand
209  */
210
211 const RAND_METHOD *
212 RAND_get_rand_method(void)
213 {
214     init_method();
215     return selected_meth;
216 }
217
218 /**
219  * Set the default random method from engine.
220  *
221  * @param engine use engine, if NULL is passed it, old method and engine is cleared.
222  *
223  * @return 1 on success, 0 on failure.
224  *
225  * @ingroup hcrypto_rand
226  */
227
228 int
229 RAND_set_rand_engine(ENGINE *engine)
230 {
231     const RAND_METHOD *meth, *old = selected_meth;
232
233     if (engine) {
234         ENGINE_up_ref(engine);
235         meth = ENGINE_get_RAND(engine);
236         if (meth == NULL) {
237             ENGINE_finish(engine);
238             return 0;
239         }
240     } else {
241         meth = NULL;
242     }
243
244     if (old)
245         (*old->cleanup)();
246
247     if (selected_engine)
248         ENGINE_finish(selected_engine);
249
250     selected_engine = engine;
251     selected_meth = meth;
252
253     return 1;
254 }
255
256 #define RAND_FILE_SIZE 1024
257
258 /**
259  * Load a a file and feed it into RAND_seed().
260  *
261  * @param filename name of file to read.
262  * @param size minimum size to read.
263  *
264  * @ingroup hcrypto_rand
265  */
266
267 int
268 RAND_load_file(const char *filename, size_t size)
269 {
270     unsigned char buf[128];
271     size_t len;
272     ssize_t slen;
273     int fd;
274
275     fd = open(filename, O_RDONLY | O_BINARY, 0600);
276     if (fd < 0)
277         return 0;
278     rk_cloexec(fd);
279     len = 0;
280     while(len < size) {
281         slen = read(fd, buf, sizeof(buf));
282         if (slen <= 0)
283             break;
284         RAND_seed(buf, slen);
285         len += slen;
286     }
287     close(fd);
288
289     return len ? 1 : 0;
290 }
291
292 /**
293  * Write of random numbers to a file to store for later initiation with RAND_load_file().
294  *
295  * @param filename name of file to write.
296  *
297  * @return 1 on success and non-one on failure.
298  * @ingroup hcrypto_rand
299  */
300
301 int
302 RAND_write_file(const char *filename)
303 {
304     unsigned char buf[128];
305     size_t len;
306     int res = 0, fd;
307
308     fd = open(filename, O_WRONLY | O_CREAT | O_BINARY, 0600);
309     if (fd < 0)
310         return 0;
311     rk_cloexec(fd);
312
313     len = 0;
314     while(len < RAND_FILE_SIZE) {
315         res = RAND_bytes(buf, sizeof(buf));
316         if (res != 1)
317             break;
318         if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
319             res = 0;
320             break;
321         }
322         len += sizeof(buf);
323     }
324
325     close(fd);
326
327     return res;
328 }
329
330 /**
331  * Return the default random state filename for a user to use for
332  * RAND_load_file(), and RAND_write_file().
333  *
334  * @param filename buffer to hold file name.
335  * @param size size of buffer filename.
336  *
337  * @return the buffer filename or NULL on failure.
338  *
339  * @ingroup hcrypto_rand
340  */
341
342 const char *
343 RAND_file_name(char *filename, size_t size)
344 {
345     const char *e = NULL;
346     int pathp = 0, ret;
347
348     if (!issuid()) {
349         e = getenv("RANDFILE");
350         if (e == NULL)
351             e = getenv("HOME");
352         if (e)
353             pathp = 1;
354     }
355     /*
356      * Here we really want to call getpwuid(getuid()) but this will
357      * cause recursive lookups if the nss library uses
358      * gssapi/krb5/hcrypto to authenticate to the ldap servers.
359      *
360      * So at least return the unix /dev/random if we have one
361      */
362 #ifndef _WIN32
363     if (e == NULL) {
364         int fd;
365
366         fd = _hc_unix_device_fd(O_RDONLY, &e);
367         if (fd >= 0)
368             close(fd);
369     }
370 #endif
371     if (e == NULL)
372         return NULL;
373
374     if (pathp)
375         ret = snprintf(filename, size, "%s/.rnd", e);
376     else
377         ret = snprintf(filename, size, "%s", e);
378
379     if (ret <= 0 || ret >= size)
380         return NULL;
381
382     return filename;
383 }