glitch in the license text detected by hyazinthe, thank you!
[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 */
16
17 /**
18  * @file util/crypto_random.c
19  * @brief functions to gather random numbers
20  * @author Christian Grothoff
21  */
22 #include "platform.h"
23 #include "gnunet_crypto_lib.h"
24 #include <gcrypt.h>
25
26 #define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-random", __VA_ARGS__)
27
28 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-random", syscall)
29
30
31 /* TODO: ndurner, move this to plibc? */
32 /* The code is derived from glibc, obviously */
33 #if !HAVE_RANDOM || !HAVE_SRANDOM
34 #ifdef RANDOM
35 #undef RANDOM
36 #endif
37 #ifdef SRANDOM
38 #undef SRANDOM
39 #endif
40 #define RANDOM() glibc_weak_rand32()
41 #define SRANDOM(s) glibc_weak_srand32(s)
42 #if defined(RAND_MAX)
43 #undef RAND_MAX
44 #endif
45 #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
46
47
48 static int32_t glibc_weak_rand32_state = 1;
49
50
51 void
52 glibc_weak_srand32 (int32_t s)
53 {
54   glibc_weak_rand32_state = s;
55 }
56
57
58 int32_t
59 glibc_weak_rand32 ()
60 {
61   int32_t val = glibc_weak_rand32_state;
62
63   val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
64   glibc_weak_rand32_state = val;
65   return val;
66 }
67 #endif
68
69 /**
70  * Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
71  *
72  * @return number between 0 and 1.
73  */
74 static double
75 get_weak_random ()
76 {
77   return ((double) RANDOM () / RAND_MAX);
78 }
79
80
81 /**
82  * Seed a weak random generator. Only #GNUNET_CRYPTO_QUALITY_WEAK-mode generator
83  * can be seeded.
84  *
85  * @param seed the seed to use
86  */
87 void
88 GNUNET_CRYPTO_seed_weak_random (int32_t seed)
89 {
90   SRANDOM (seed);
91 }
92
93
94 /**
95  * @ingroup crypto
96  * Fill block with a random values.
97  *
98  * @param mode desired quality of the random number
99  * @param buffer the buffer to fill
100  * @param length buffer length
101  */
102 void
103 GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode, void *buffer, size_t length)
104 {
105 #ifdef gcry_fast_random_poll
106   static unsigned int invokeCount;
107 #endif
108   switch (mode)
109   {
110   case GNUNET_CRYPTO_QUALITY_STRONG:
111     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
112 #ifdef gcry_fast_random_poll
113     if ((invokeCount++ % 256) == 0)
114       gcry_fast_random_poll ();
115 #endif
116     gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
117     return;
118   case GNUNET_CRYPTO_QUALITY_NONCE:
119     gcry_create_nonce (buffer, length);
120     return;
121   case GNUNET_CRYPTO_QUALITY_WEAK:
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     gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
128     return;
129   default:
130     GNUNET_assert (0);
131   }
132 }
133
134
135 /**
136  * Produce a random unsigned 32-bit number modulo @a i.
137  *
138  * @param mode desired quality of the random number
139  * @param i the upper limit (exclusive) for the random number
140  * @return a random value in the interval [0,i[.
141  */
142 uint32_t
143 GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode,
144                           uint32_t i)
145 {
146 #ifdef gcry_fast_random_poll
147   static unsigned int invokeCount;
148 #endif
149   uint32_t ret;
150   uint32_t ul;
151
152   GNUNET_assert (i > 0);
153
154   switch (mode)
155   {
156   case GNUNET_CRYPTO_QUALITY_STRONG:
157     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
158 #ifdef gcry_fast_random_poll
159     if ((invokeCount++ % 256) == 0)
160       gcry_fast_random_poll ();
161 #endif
162     ul = UINT32_MAX - (UINT32_MAX % i);
163     do
164     {
165       gcry_randomize ((unsigned char *) &ret, sizeof (uint32_t),
166                       GCRY_STRONG_RANDOM);
167     }
168     while (ret >= ul);
169     return ret % i;
170   case GNUNET_CRYPTO_QUALITY_NONCE:
171     ul = UINT32_MAX - (UINT32_MAX % i);
172     do
173     {
174       gcry_create_nonce (&ret, sizeof (ret));
175     }
176     while (ret >= ul);
177     return ret % i;
178   case GNUNET_CRYPTO_QUALITY_WEAK:
179     ret = i * get_weak_random ();
180     if (ret >= i)
181       ret = i - 1;
182     return ret;
183   default:
184     GNUNET_assert (0);
185   }
186   return 0;
187 }
188
189
190 /**
191  * Get an array with a random permutation of the
192  * numbers 0...n-1.
193  * @param mode #GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive)
194  *        PRNG should be used, #GNUNET_RANDOM_QUALITY_WEAK otherwise
195  * @param n the size of the array
196  * @return the permutation array (allocated from heap)
197  */
198 unsigned int *
199 GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode,
200                               unsigned int n)
201 {
202   unsigned int *ret;
203   unsigned int i;
204   unsigned int tmp;
205   uint32_t x;
206
207   GNUNET_assert (n > 0);
208   ret = GNUNET_malloc (n * sizeof (unsigned int));
209   for (i = 0; i < n; i++)
210     ret[i] = i;
211   for (i = n - 1; i > 0; i--)
212   {
213     x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
214     tmp = ret[x];
215     ret[x] = ret[i];
216     ret[i] = tmp;
217   }
218   return ret;
219 }
220
221
222 /**
223  * Generate random unsigned 64-bit value.
224  *
225  * @param mode desired quality of the random number
226  * @param max value returned will be in range [0,max) (exclusive)
227  * @return random 64-bit number
228  */
229 uint64_t
230 GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
231 {
232   uint64_t ret;
233   uint64_t ul;
234
235   GNUNET_assert (max > 0);
236   switch (mode)
237   {
238   case GNUNET_CRYPTO_QUALITY_STRONG:
239     ul = UINT64_MAX - (UINT64_MAX % max);
240     do
241     {
242       gcry_randomize ((unsigned char *) &ret, sizeof (uint64_t),
243                       GCRY_STRONG_RANDOM);
244     }
245     while (ret >= ul);
246     return ret % max;
247   case GNUNET_CRYPTO_QUALITY_NONCE:
248     ul = UINT64_MAX - (UINT64_MAX % max);
249     do
250     {
251       gcry_create_nonce (&ret, sizeof (ret));
252     }
253     while (ret >= ul);
254
255     return ret % max;
256   case GNUNET_CRYPTO_QUALITY_WEAK:
257     ret = max * get_weak_random ();
258     if (ret >= max)
259       ret = max - 1;
260     return ret;
261   default:
262     GNUNET_assert (0);
263   }
264   return 0;
265 }
266
267
268 /**
269  * Initialize libgcrypt.
270  */
271 void __attribute__ ((constructor))
272 GNUNET_CRYPTO_random_init ()
273 {
274   gcry_error_t rc;
275
276   if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
277   {
278     FPRINTF (stderr,
279              _("libgcrypt has not the expected version (version %s is required).\n"),
280              NEED_LIBGCRYPT_VERSION);
281     GNUNET_assert (0);
282   }
283   if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
284     FPRINTF (stderr,
285              "Failed to set libgcrypt option %s: %s\n",
286              "DISABLE_SECMEM",
287              gcry_strerror (rc));
288   /* Otherwise gnunet-ecc takes forever to complete, besides
289      we are fine with "just" using GCRY_STRONG_RANDOM */
290   if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
291     FPRINTF (stderr,
292              "Failed to set libgcrypt option %s: %s\n",
293              "ENABLE_QUICK_RANDOM",
294              gcry_strerror (rc));
295   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
296   gcry_fast_random_poll ();
297   GNUNET_CRYPTO_seed_weak_random (time (NULL) ^
298                                   GNUNET_CRYPTO_random_u32
299                                   (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
300 }
301
302
303 /**
304  * Nicely shut down libgcrypt.
305  */
306 void __attribute__ ((destructor))
307 GNUNET_CRYPTO_random_fini ()
308 {
309   gcry_set_progress_handler (NULL, NULL);
310 #ifdef GCRYCTL_CLOSE_RANDOM_DEVICE
311   (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
312 #endif
313 }
314
315
316
317 /* end of crypto_random.c */