- improve handling of duplicate connection_create
[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 3, 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_util_lib.h"
29 #include <gcrypt.h>
30
31 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
32
33 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
34
35
36 /* TODO: ndurner, move this to plibc? */
37 /* The code is derived from glibc, obviously */
38 #if !HAVE_RANDOM || !HAVE_SRANDOM
39 #ifdef RANDOM
40 #undef RANDOM
41 #endif
42 #ifdef SRANDOM
43 #undef SRANDOM
44 #endif
45 #define RANDOM() glibc_weak_rand32()
46 #define SRANDOM(s) glibc_weak_srand32(s)
47 #if defined(RAND_MAX)
48 #undef RAND_MAX
49 #endif
50 #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
51
52
53 static int32_t glibc_weak_rand32_state = 1;
54
55
56 void
57 glibc_weak_srand32 (int32_t s)
58 {
59   glibc_weak_rand32_state = s;
60 }
61
62
63 int32_t
64 glibc_weak_rand32 ()
65 {
66   int32_t val = glibc_weak_rand32_state;
67
68   val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
69   glibc_weak_rand32_state = val;
70   return val;
71 }
72 #endif
73
74 /**
75  * Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
76  *
77  * @return number between 0 and 1.
78  */
79 static double
80 get_weak_random ()
81 {
82   return ((double) RANDOM () / RAND_MAX);
83 }
84
85
86 /**
87  * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator
88  * can be seeded.
89  *
90  * @param seed the seed to use
91  */
92 void
93 GNUNET_CRYPTO_seed_weak_random (int32_t seed)
94 {
95   SRANDOM (seed);
96 }
97
98 /**
99  * @ingroup crypto
100  * Fill block with a random values.
101  *
102  * @param mode desired quality of the random number
103  * @param buffer the buffer to fill
104  * @param length buffer length
105  */
106 void
107 GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode, void *buffer, size_t length)
108 {
109 #ifdef gcry_fast_random_poll
110   static unsigned int invokeCount;
111 #endif
112   switch (mode)
113   {
114   case GNUNET_CRYPTO_QUALITY_STRONG:
115     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
116 #ifdef gcry_fast_random_poll
117     if ((invokeCount++ % 256) == 0)
118       gcry_fast_random_poll ();
119 #endif
120     gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
121     return;
122   case GNUNET_CRYPTO_QUALITY_NONCE:
123     gcry_create_nonce (buffer, length);
124     return;
125   case GNUNET_CRYPTO_QUALITY_WEAK:
126     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
127 #ifdef gcry_fast_random_poll
128     if ((invokeCount++ % 256) == 0)
129       gcry_fast_random_poll ();
130 #endif
131     gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
132     return;
133   default:
134     GNUNET_assert (0);
135   }
136 }
137
138
139 /**
140  * Produce a random value.
141  *
142  * @param mode desired quality of the random number
143  * @param i the upper limit (exclusive) for the random number
144  * @return a random value in the interval [0,i[.
145  */
146 uint32_t
147 GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i)
148 {
149 #ifdef gcry_fast_random_poll
150   static unsigned int invokeCount;
151 #endif
152   uint32_t ret;
153   uint32_t ul;
154
155   GNUNET_assert (i > 0);
156
157   switch (mode)
158   {
159   case GNUNET_CRYPTO_QUALITY_STRONG:
160     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
161 #ifdef gcry_fast_random_poll
162     if ((invokeCount++ % 256) == 0)
163       gcry_fast_random_poll ();
164 #endif
165     ul = UINT32_MAX - (UINT32_MAX % i);
166     do
167     {
168       gcry_randomize ((unsigned char *) &ret, sizeof (uint32_t),
169                       GCRY_STRONG_RANDOM);
170     }
171     while (ret >= ul);
172     return ret % i;
173   case GNUNET_CRYPTO_QUALITY_NONCE:
174     ul = UINT32_MAX - (UINT32_MAX % i);
175     do
176     {
177       gcry_create_nonce (&ret, sizeof (ret));
178     }
179     while (ret >= ul);
180     return ret % i;
181   case GNUNET_CRYPTO_QUALITY_WEAK:
182     ret = i * get_weak_random ();
183     if (ret >= i)
184       ret = i - 1;
185     return ret;
186   default:
187     GNUNET_assert (0);
188   }
189   return 0;
190 }
191
192
193 /**
194  * Get an array with a random permutation of the
195  * numbers 0...n-1.
196  * @param mode GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive)
197  *        PRNG should be used, GNUNET_RANDOM_QUALITY_WEAK otherwise
198  * @param n the size of the array
199  * @return the permutation array (allocated from heap)
200  */
201 unsigned int *
202 GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n)
203 {
204   unsigned int *ret;
205   unsigned int i;
206   unsigned int tmp;
207   uint32_t x;
208
209   GNUNET_assert (n > 0);
210   ret = GNUNET_malloc (n * sizeof (unsigned int));
211   for (i = 0; i < n; i++)
212     ret[i] = i;
213   for (i = n - 1; i > 0; i--)
214   {
215     x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
216     tmp = ret[x];
217     ret[x] = ret[i];
218     ret[i] = tmp;
219   }
220   return ret;
221 }
222
223 /**
224  * Random on unsigned 64-bit values.
225  *
226  *
227  * @param mode desired quality of the random number
228  * @param max value returned will be in range [0,max) (exclusive)
229  * @return random 64-bit number
230  */
231 uint64_t
232 GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
233 {
234   uint64_t ret;
235   uint64_t ul;
236
237   GNUNET_assert (max > 0);
238   switch (mode)
239   {
240   case GNUNET_CRYPTO_QUALITY_STRONG:
241     ul = UINT64_MAX - (UINT64_MAX % max);
242     do
243     {
244       gcry_randomize ((unsigned char *) &ret, sizeof (uint64_t),
245                       GCRY_STRONG_RANDOM);
246     }
247     while (ret >= ul);
248     return ret % max;
249   case GNUNET_CRYPTO_QUALITY_NONCE:
250     ul = UINT64_MAX - (UINT64_MAX % max);
251     do
252     {
253       gcry_create_nonce (&ret, sizeof (ret));
254     }
255     while (ret >= ul);
256
257     return ret % max;
258   case GNUNET_CRYPTO_QUALITY_WEAK:
259     ret = max * get_weak_random ();
260     if (ret >= max)
261       ret = max - 1;
262     return ret;
263   default:
264     GNUNET_assert (0);
265   }
266   return 0;
267 }
268
269
270 /**
271  * Process ID of the "find" process that we use for
272  * entropy gathering.
273  */
274 static struct GNUNET_OS_Process *genproc;
275
276
277 /**
278  * Function called by libgcrypt whenever we are
279  * blocked gathering entropy.
280  */
281 static void
282 entropy_generator (void *cls, const char *what, int printchar, int current,
283                    int total)
284 {
285   unsigned long code;
286   enum GNUNET_OS_ProcessStatusType type;
287   int ret;
288
289   if (0 != strcmp (what, "need_entropy"))
290     return;
291   if (current == total)
292   {
293     if (genproc != NULL)
294     {
295       if (0 != GNUNET_OS_process_kill (genproc, SIGKILL))
296         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill");
297       GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
298       GNUNET_OS_process_destroy (genproc);
299       genproc = NULL;
300     }
301     return;
302   }
303   if (genproc != NULL)
304   {
305     ret = GNUNET_OS_process_status (genproc, &type, &code);
306     if (ret == GNUNET_NO)
307       return;                   /* still running */
308     if (ret == GNUNET_SYSERR)
309     {
310       GNUNET_break (0);
311       return;
312     }
313     if (0 != GNUNET_OS_process_kill (genproc, SIGKILL))
314       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill");
315     GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
316     GNUNET_OS_process_destroy (genproc);
317     genproc = NULL;
318   }
319   LOG (GNUNET_ERROR_TYPE_INFO, _("Starting `%s' process to generate entropy\n"),
320        "find");
321   genproc =
322      GNUNET_OS_start_process (GNUNET_NO, 0,
323                               NULL, NULL, "sh", "sh", "-c",
324                               "exec find / -mount -type f -exec cp {} /dev/null \\; 2>/dev/null",
325                               NULL);
326 }
327
328
329 static void
330 killfind ()
331 {
332   if (genproc != NULL)
333   {
334     GNUNET_OS_process_kill (genproc, SIGKILL);
335     GNUNET_OS_process_destroy (genproc);
336     genproc = NULL;
337   }
338 }
339
340
341 void __attribute__ ((constructor))
342 GNUNET_CRYPTO_random_init ()
343 {
344   gcry_error_t rc;
345
346   if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
347   {
348     FPRINTF (stderr,
349              _
350              ("libgcrypt has not the expected version (version %s is required).\n"),
351              NEED_LIBGCRYPT_VERSION);
352     GNUNET_abort ();
353   }
354   if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
355     FPRINTF (stderr, "Failed to set libgcrypt option %s: %s\n", "DISABLE_SECMEM",
356              gcry_strerror (rc));
357   /* we only generate ephemeral keys in-process; for those,
358      we are fine with "just" using GCRY_STRONG_RANDOM */
359   if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
360     FPRINTF (stderr,  "Failed to set libgcrypt option %s: %s\n", "ENABLE_QUICK_RANDOM",
361              gcry_strerror (rc));
362
363 #ifdef GCRYCTL_INITIALIZATION_FINISHED
364   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
365 #endif
366 #ifdef gcry_fast_random_poll
367   gcry_fast_random_poll ();
368 #endif
369   gcry_set_progress_handler (&entropy_generator, NULL);
370   atexit (&killfind);
371   GNUNET_CRYPTO_seed_weak_random (time (NULL) ^
372                                   GNUNET_CRYPTO_random_u32
373                                   (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
374 }
375
376
377 void __attribute__ ((destructor))
378 GNUNET_CRYPTO_random_fini ()
379 {
380   gcry_set_progress_handler (NULL, NULL);
381 }
382
383
384
385 /* end of crypto_random.c */