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