-typo
[oweals/gnunet.git] / src / util / crypto_random.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2003, 2004, 2005, 2006, 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19
20 */
21
22 /**
23  * @file util/crypto_random.c
24  * @brief functions to gather random numbers
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_os_lib.h"
31 #include <gcrypt.h>
32
33 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
34
35 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
36
37
38 /**
39  * GNUNET_YES if we are using a 'weak' (low-entropy) PRNG.
40  */ 
41 static int weak_random;
42
43
44
45 /* TODO: ndurner, move this to plibc? */
46 /* The code is derived from glibc, obviously */
47 #if MINGW
48 #ifdef RANDOM
49 #undef RANDOM
50 #endif
51 #ifdef SRANDOM
52 #undef SRANDOM
53 #endif
54 #define RANDOM() glibc_weak_rand32()
55 #define SRANDOM(s) glibc_weak_srand32(s)
56 #if defined(RAND_MAX)
57 #undef RAND_MAX
58 #endif
59 #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
60
61
62 static int32_t glibc_weak_rand32_state = 1;
63
64
65 void
66 glibc_weak_srand32 (int32_t s)
67 {
68   glibc_weak_rand32_state = s;
69 }
70
71
72 int32_t
73 glibc_weak_rand32 ()
74 {
75   int32_t val = glibc_weak_rand32_state;
76
77   val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
78   glibc_weak_rand32_state = val;
79   return val;
80 }
81 #endif
82
83 /**
84  * Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
85  *
86  * @return number between 0 and 1.
87  */
88 static double
89 get_weak_random ()
90 {
91   return ((double) RANDOM () / RAND_MAX);
92 }
93
94
95 /**
96  * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator
97  * can be seeded.
98  *
99  * @param seed the seed to use
100  */
101 void
102 GNUNET_CRYPTO_seed_weak_random (int32_t seed)
103 {
104   SRANDOM (seed);
105 }
106
107
108 /**
109  * Produce a random value.
110  *
111  * @param mode desired quality of the random number
112  * @param i the upper limit (exclusive) for the random number
113  * @return a random value in the interval [0,i[.
114  */
115 uint32_t
116 GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i)
117 {
118 #ifdef gcry_fast_random_poll
119   static unsigned int invokeCount;
120 #endif
121   uint32_t ret;
122   uint32_t ul;
123
124   GNUNET_assert (i > 0);
125
126   switch (mode)
127   {
128   case GNUNET_CRYPTO_QUALITY_STRONG:
129     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
130 #ifdef gcry_fast_random_poll
131     if ((invokeCount++ % 256) == 0)
132       gcry_fast_random_poll ();
133 #endif
134     ul = UINT32_MAX - (UINT32_MAX % i);
135     do
136     {
137       gcry_randomize ((unsigned char *) &ret, sizeof (uint32_t),
138                       GCRY_STRONG_RANDOM);
139     }
140     while (ret >= ul);
141     return ret % i;
142   case GNUNET_CRYPTO_QUALITY_NONCE:
143     ul = UINT32_MAX - (UINT32_MAX % i);
144     do
145     {
146       gcry_create_nonce (&ret, sizeof (ret));
147     }
148     while (ret >= ul);
149     return ret % i;
150   case GNUNET_CRYPTO_QUALITY_WEAK:
151     ret = i * get_weak_random ();
152     if (ret >= i)
153       ret = i - 1;
154     return ret;
155   default:
156     GNUNET_assert (0);
157   }
158   return 0;
159 }
160
161
162 /**
163  * Get an array with a random permutation of the
164  * numbers 0...n-1.
165  * @param mode GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive)
166  *        PRNG should be used, GNUNET_RANDOM_QUALITY_WEAK otherwise
167  * @param n the size of the array
168  * @return the permutation array (allocated from heap)
169  */
170 unsigned int *
171 GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n)
172 {
173   unsigned int *ret;
174   unsigned int i;
175   unsigned int tmp;
176   uint32_t x;
177
178   GNUNET_assert (n > 0);
179   ret = GNUNET_malloc (n * sizeof (unsigned int));
180   for (i = 0; i < n; i++)
181     ret[i] = i;
182   for (i = n - 1; i > 0; i--)
183   {
184     x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
185     tmp = ret[x];
186     ret[x] = ret[i];
187     ret[i] = tmp;
188   }
189   return ret;
190 }
191
192 /**
193  * Random on unsigned 64-bit values.
194  *
195  *
196  * @param mode desired quality of the random number
197  * @param max value returned will be in range [0,max) (exclusive)
198  * @return random 64-bit number
199  */
200 uint64_t
201 GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
202 {
203   uint64_t ret;
204   uint64_t ul;
205
206   GNUNET_assert (max > 0);
207   switch (mode)
208   {
209   case GNUNET_CRYPTO_QUALITY_STRONG:
210     ul = UINT64_MAX - (UINT64_MAX % max);
211     do
212     {
213       gcry_randomize ((unsigned char *) &ret, sizeof (uint64_t),
214                       GCRY_STRONG_RANDOM);
215     }
216     while (ret >= ul);
217     return ret % max;
218   case GNUNET_CRYPTO_QUALITY_NONCE:
219     ul = UINT64_MAX - (UINT64_MAX % max);
220     do
221     {
222       gcry_create_nonce (&ret, sizeof (ret));
223     }
224     while (ret >= ul);
225
226     return ret % max;
227   case GNUNET_CRYPTO_QUALITY_WEAK:
228     ret = max * get_weak_random ();
229     if (ret >= max)
230       ret = max - 1;
231     return ret;
232   default:
233     GNUNET_assert (0);
234   }
235   return 0;
236 }
237
238
239 /**
240  * Check if we are using weak random number generation.
241  *
242  * @return GNUNET_YES if weak number generation is on
243  */
244 int
245 GNUNET_CRYPTO_random_is_weak ()
246 {
247   return weak_random;
248 }
249
250
251 /**
252  * This function should only be called in testcases
253  * where strong entropy gathering is not desired
254  * (for example, for hostkey generation).
255  */
256 void
257 GNUNET_CRYPTO_random_disable_entropy_gathering ()
258 {
259   weak_random = GNUNET_YES;
260   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
261 }
262
263
264 /**
265  * Process ID of the "find" process that we use for
266  * entropy gathering.
267  */
268 static struct GNUNET_OS_Process *genproc;
269
270
271 /**
272  * Function called by libgcrypt whenever we are
273  * blocked gathering entropy.
274  */
275 static void
276 entropy_generator (void *cls, const char *what, int printchar, int current,
277                    int total)
278 {
279   unsigned long code;
280   enum GNUNET_OS_ProcessStatusType type;
281   int ret;
282
283   if (0 != strcmp (what, "need_entropy"))
284     return;
285   if (current == total)
286   {
287     if (genproc != NULL)
288     {
289       if (0 != GNUNET_OS_process_kill (genproc, SIGTERM))
290         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill");
291       GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
292       GNUNET_OS_process_destroy (genproc);
293       genproc = NULL;
294     }
295     return;
296   }
297   if (genproc != NULL)
298   {
299     ret = GNUNET_OS_process_status (genproc, &type, &code);
300     if (ret == GNUNET_NO)
301       return;                   /* still running */
302     if (ret == GNUNET_SYSERR)
303     {
304       GNUNET_break (0);
305       return;
306     }
307     if (0 != GNUNET_OS_process_kill (genproc, SIGTERM))
308       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill");
309     GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
310     GNUNET_OS_process_destroy (genproc);
311     genproc = NULL;
312   }
313   LOG (GNUNET_ERROR_TYPE_INFO, _("Starting `%s' process to generate entropy\n"),
314        "find");
315   genproc =
316      GNUNET_OS_start_process (GNUNET_NO, 0, 
317                               NULL, NULL, "sh", "sh", "-c",
318                               "exec find / -mount -type f -exec cp {} /dev/null \\; 2>/dev/null",
319                               NULL);
320 }
321
322
323 static void
324 killfind ()
325 {
326   if (genproc != NULL)
327   {
328     GNUNET_OS_process_kill (genproc, SIGKILL);
329     GNUNET_OS_process_destroy (genproc);
330     genproc = NULL;
331   }
332 }
333
334
335 void __attribute__ ((constructor)) GNUNET_CRYPTO_random_init ()
336 {
337   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
338   if (!gcry_check_version (GCRYPT_VERSION))
339   {
340     FPRINTF (stderr,
341              _
342              ("libgcrypt has not the expected version (version %s is required).\n"),
343              GCRYPT_VERSION);
344     GNUNET_abort ();
345   }
346 #ifdef GCRYCTL_INITIALIZATION_FINISHED
347   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
348 #endif
349 #ifdef gcry_fast_random_poll
350   gcry_fast_random_poll ();
351 #endif
352   gcry_set_progress_handler (&entropy_generator, NULL);
353   atexit (&killfind);
354   GNUNET_CRYPTO_seed_weak_random (time (NULL) ^
355                                   GNUNET_CRYPTO_random_u32
356                                   (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
357 }
358
359
360 void __attribute__ ((destructor)) GNUNET_CRYPTO_random_fini ()
361 {
362   gcry_set_progress_handler (NULL, NULL);
363 }
364
365
366
367 /* end of crypto_random.c */