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