resolve merge conflict with peerinfo plugin move
[oweals/gnunet.git] / src / util / crypto_random.c
1 /*
2      This file is part of GNUnet.  Copyright (C) 2001-2014 Christian Grothoff
3      (and other contributing authors)
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20 /**
21  * @file util/crypto_random.c
22  * @brief functions to gather random numbers
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_crypto_lib.h"
27 #include <gcrypt.h>
28
29 #define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-random", __VA_ARGS__)
30
31 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-random", syscall)
32
33
34 /* TODO: ndurner, move this to plibc? */
35 /* The code is derived from glibc, obviously */
36 #if !HAVE_RANDOM || !HAVE_SRANDOM
37 #ifdef RANDOM
38 #undef RANDOM
39 #endif
40 #ifdef SRANDOM
41 #undef SRANDOM
42 #endif
43 #define RANDOM() glibc_weak_rand32()
44 #define SRANDOM(s) glibc_weak_srand32(s)
45 #if defined(RAND_MAX)
46 #undef RAND_MAX
47 #endif
48 #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
49
50
51 static int32_t glibc_weak_rand32_state = 1;
52
53
54 void
55 glibc_weak_srand32 (int32_t s)
56 {
57   glibc_weak_rand32_state = s;
58 }
59
60
61 int32_t
62 glibc_weak_rand32 ()
63 {
64   int32_t val = glibc_weak_rand32_state;
65
66   val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
67   glibc_weak_rand32_state = val;
68   return val;
69 }
70 #endif
71
72 /**
73  * Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
74  *
75  * @return number between 0 and 1.
76  */
77 static double
78 get_weak_random ()
79 {
80   return ((double) RANDOM () / RAND_MAX);
81 }
82
83
84 /**
85  * Seed a weak random generator. Only #GNUNET_CRYPTO_QUALITY_WEAK-mode generator
86  * can be seeded.
87  *
88  * @param seed the seed to use
89  */
90 void
91 GNUNET_CRYPTO_seed_weak_random (int32_t seed)
92 {
93   SRANDOM (seed);
94 }
95
96
97 /**
98  * @ingroup crypto
99  * Fill block with a random values.
100  *
101  * @param mode desired quality of the random number
102  * @param buffer the buffer to fill
103  * @param length buffer length
104  */
105 void
106 GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode, void *buffer, size_t length)
107 {
108 #ifdef gcry_fast_random_poll
109   static unsigned int invokeCount;
110 #endif
111   switch (mode)
112   {
113   case GNUNET_CRYPTO_QUALITY_STRONG:
114     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
115 #ifdef gcry_fast_random_poll
116     if ((invokeCount++ % 256) == 0)
117       gcry_fast_random_poll ();
118 #endif
119     gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
120     return;
121   case GNUNET_CRYPTO_QUALITY_NONCE:
122     gcry_create_nonce (buffer, length);
123     return;
124   case GNUNET_CRYPTO_QUALITY_WEAK:
125     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
126 #ifdef gcry_fast_random_poll
127     if ((invokeCount++ % 256) == 0)
128       gcry_fast_random_poll ();
129 #endif
130     gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
131     return;
132   default:
133     GNUNET_assert (0);
134   }
135 }
136
137
138 /**
139  * Produce a random unsigned 32-bit number modulo @a i.
140  *
141  * @param mode desired quality of the random number
142  * @param i the upper limit (exclusive) for the random number
143  * @return a random value in the interval [0,i[.
144  */
145 uint32_t
146 GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode,
147                           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,
203                               unsigned int n)
204 {
205   unsigned int *ret;
206   unsigned int i;
207   unsigned int tmp;
208   uint32_t x;
209
210   GNUNET_assert (n > 0);
211   ret = GNUNET_malloc (n * sizeof (unsigned int));
212   for (i = 0; i < n; i++)
213     ret[i] = i;
214   for (i = n - 1; i > 0; i--)
215   {
216     x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
217     tmp = ret[x];
218     ret[x] = ret[i];
219     ret[i] = tmp;
220   }
221   return ret;
222 }
223
224
225 /**
226  * Generate random unsigned 64-bit value.
227  *
228  * @param mode desired quality of the random number
229  * @param max value returned will be in range [0,max) (exclusive)
230  * @return random 64-bit number
231  */
232 uint64_t
233 GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
234 {
235   uint64_t ret;
236   uint64_t ul;
237
238   GNUNET_assert (max > 0);
239   switch (mode)
240   {
241   case GNUNET_CRYPTO_QUALITY_STRONG:
242     ul = UINT64_MAX - (UINT64_MAX % max);
243     do
244     {
245       gcry_randomize ((unsigned char *) &ret, sizeof (uint64_t),
246                       GCRY_STRONG_RANDOM);
247     }
248     while (ret >= ul);
249     return ret % max;
250   case GNUNET_CRYPTO_QUALITY_NONCE:
251     ul = UINT64_MAX - (UINT64_MAX % max);
252     do
253     {
254       gcry_create_nonce (&ret, sizeof (ret));
255     }
256     while (ret >= ul);
257
258     return ret % max;
259   case GNUNET_CRYPTO_QUALITY_WEAK:
260     ret = max * get_weak_random ();
261     if (ret >= max)
262       ret = max - 1;
263     return ret;
264   default:
265     GNUNET_assert (0);
266   }
267   return 0;
268 }
269
270
271 /**
272  * Allocation wrapper for libgcrypt, used to avoid bad locking
273  * strategy of libgcrypt implementation.
274  */
275 static void *
276 w_malloc (size_t n)
277 {
278   return calloc (n, 1);
279 }
280
281
282 /**
283  * Allocation wrapper for libgcrypt, used to avoid bad locking
284  * strategy of libgcrypt implementation.
285  */
286 static int
287 w_check (const void *p)
288 {
289   return 0; /* not secure memory */
290 }
291
292
293 /**
294  * Initialize libgcrypt.
295  */
296 void __attribute__ ((constructor))
297 GNUNET_CRYPTO_random_init ()
298 {
299   gcry_error_t rc;
300
301   if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
302   {
303     FPRINTF (stderr,
304              _("libgcrypt has not the expected version (version %s is required).\n"),
305              NEED_LIBGCRYPT_VERSION);
306     GNUNET_assert (0);
307   }
308   /* set custom allocators */
309   gcry_set_allocation_handler (&w_malloc,
310                                &w_malloc,
311                                &w_check,
312                                &realloc,
313                                &free);
314   /* Disable use of secure memory */
315   if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
316     FPRINTF (stderr,
317              "Failed to set libgcrypt option %s: %s\n",
318              "DISABLE_SECMEM",
319              gcry_strerror (rc));
320   /* Otherwise gnunet-ecc takes forever to complete, besides
321      we are fine with "just" using GCRY_STRONG_RANDOM */
322   if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
323     FPRINTF (stderr,
324              "Failed to set libgcrypt option %s: %s\n",
325              "ENABLE_QUICK_RANDOM",
326              gcry_strerror (rc));
327   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
328   gcry_fast_random_poll ();
329   GNUNET_CRYPTO_seed_weak_random (time (NULL) ^
330                                   GNUNET_CRYPTO_random_u32
331                                   (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
332 }
333
334
335 /**
336  * Nicely shut down libgcrypt.
337  */
338 void __attribute__ ((destructor))
339 GNUNET_CRYPTO_random_fini ()
340 {
341   gcry_set_progress_handler (NULL, NULL);
342 #ifdef GCRYCTL_CLOSE_RANDOM_DEVICE
343   (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
344 #endif
345 }
346
347
348
349 /* end of crypto_random.c */