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