use NULL value in load_path_suffix to NOT load any files
[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      SPDX-License-Identifier: AGPL3.0-or-later
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_crypto_lib.h"
29 #include <gcrypt.h>
30
31 #define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-random", __VA_ARGS__)
32
33 #define LOG_STRERROR(kind, syscall) \
34   GNUNET_log_from_strerror (kind, "util-crypto-random", syscall)
35
36
37 /* TODO: ndurner, move this to plibc? */
38 /* The code is derived from glibc, obviously */
39 #if ! HAVE_RANDOM || ! HAVE_SRANDOM
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 #if defined(RAND_MAX)
49 #undef RAND_MAX
50 #endif
51 #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
52
53
54 static int32_t glibc_weak_rand32_state = 1;
55
56
57 void
58 glibc_weak_srand32 (int32_t s)
59 {
60   glibc_weak_rand32_state = s;
61 }
62
63
64 int32_t
65 glibc_weak_rand32 ()
66 {
67   int32_t val = glibc_weak_rand32_state;
68
69   val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
70   glibc_weak_rand32_state = val;
71   return val;
72 }
73
74
75 #endif
76
77 /**
78  * Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
79  *
80  * @return number between 0 and 1.
81  */
82 static double
83 get_weak_random ()
84 {
85   return((double) random () / RAND_MAX);
86 }
87
88
89 /**
90  * Seed a weak random generator. Only #GNUNET_CRYPTO_QUALITY_WEAK-mode generator
91  * can be seeded.
92  *
93  * @param seed the seed to use
94  */
95 void
96 GNUNET_CRYPTO_seed_weak_random (int32_t seed)
97 {
98   srandom (seed);
99 }
100
101
102 /**
103  * @ingroup crypto
104  * Zero out @a buffer, securely against compiler optimizations.
105  * Used to delete key material.
106  *
107  * @param buffer the buffer to zap
108  * @param length buffer length
109  */
110 void
111 GNUNET_CRYPTO_zero_keys (void *buffer, size_t length)
112 {
113 #if HAVE_MEMSET_S
114   memset_s (buffer, length, 0, length);
115 #elif HAVE_EXPLICIT_BZERO
116   explicit_bzero (buffer, length);
117 #else
118   volatile unsigned char *p = buffer;
119   while (length--)
120     *p++ = 0;
121 #endif
122 }
123
124
125 /**
126  * @ingroup crypto
127  * Fill block with a random values.
128  *
129  * @param mode desired quality of the random number
130  * @param buffer the buffer to fill
131  * @param length buffer length
132  */
133 void
134 GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode,
135                             void *buffer,
136                             size_t length)
137 {
138 #ifdef gcry_fast_random_poll
139   static unsigned int invokeCount;
140 #endif
141   switch (mode)
142   {
143   case GNUNET_CRYPTO_QUALITY_STRONG:
144     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
145 #ifdef gcry_fast_random_poll
146     if ((invokeCount++ % 256) == 0)
147       gcry_fast_random_poll ();
148 #endif
149     gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
150     return;
151
152   case GNUNET_CRYPTO_QUALITY_NONCE:
153     gcry_create_nonce (buffer, length);
154     return;
155
156   case GNUNET_CRYPTO_QUALITY_WEAK:
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     gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
163     return;
164
165   default:
166     GNUNET_assert (0);
167   }
168 }
169
170
171 /**
172  * Produce a random unsigned 32-bit number modulo @a i.
173  *
174  * @param mode desired quality of the random number
175  * @param i the upper limit (exclusive) for the random number
176  * @return a random value in the interval [0,i[.
177  */
178 uint32_t
179 GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i)
180 {
181 #ifdef gcry_fast_random_poll
182   static unsigned int invokeCount;
183 #endif
184   uint32_t ret;
185   uint32_t ul;
186
187   GNUNET_assert (i > 0);
188
189   switch (mode)
190   {
191   case GNUNET_CRYPTO_QUALITY_STRONG:
192     /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
193 #ifdef gcry_fast_random_poll
194     if ((invokeCount++ % 256) == 0)
195       gcry_fast_random_poll ();
196 #endif
197     ul = UINT32_MAX - (UINT32_MAX % i);
198     do
199     {
200       gcry_randomize ((unsigned char *) &ret,
201                       sizeof(uint32_t),
202                       GCRY_STRONG_RANDOM);
203     }
204     while (ret >= ul);
205     return ret % i;
206
207   case GNUNET_CRYPTO_QUALITY_NONCE:
208     ul = UINT32_MAX - (UINT32_MAX % i);
209     do
210     {
211       gcry_create_nonce (&ret, sizeof(ret));
212     }
213     while (ret >= ul);
214     return ret % i;
215
216   case GNUNET_CRYPTO_QUALITY_WEAK:
217     ret = i * get_weak_random ();
218     if (ret >= i)
219       ret = i - 1;
220     return ret;
221
222   default:
223     GNUNET_assert (0);
224   }
225   return 0;
226 }
227
228
229 /**
230  * Get an array with a random permutation of the
231  * numbers 0...n-1.
232  * @param mode #GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive)
233  *        PRNG should be used, #GNUNET_RANDOM_QUALITY_WEAK otherwise
234  * @param n the size of the array
235  * @return the permutation array (allocated from heap)
236  */
237 unsigned int *
238 GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n)
239 {
240   unsigned int *ret;
241   unsigned int i;
242   unsigned int tmp;
243   uint32_t x;
244
245   GNUNET_assert (n > 0);
246   ret = GNUNET_malloc (n * sizeof(unsigned int));
247   for (i = 0; i < n; i++)
248     ret[i] = i;
249   for (i = n - 1; i > 0; i--)
250   {
251     x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
252     tmp = ret[x];
253     ret[x] = ret[i];
254     ret[i] = tmp;
255   }
256   return ret;
257 }
258
259
260 /**
261  * Generate random unsigned 64-bit value.
262  *
263  * @param mode desired quality of the random number
264  * @param max value returned will be in range [0,max) (exclusive)
265  * @return random 64-bit number
266  */
267 uint64_t
268 GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
269 {
270   uint64_t ret;
271   uint64_t ul;
272
273   GNUNET_assert (max > 0);
274   switch (mode)
275   {
276   case GNUNET_CRYPTO_QUALITY_STRONG:
277     ul = UINT64_MAX - (UINT64_MAX % max);
278     do
279     {
280       gcry_randomize ((unsigned char *) &ret,
281                       sizeof(uint64_t),
282                       GCRY_STRONG_RANDOM);
283     }
284     while (ret >= ul);
285     return ret % max;
286
287   case GNUNET_CRYPTO_QUALITY_NONCE:
288     ul = UINT64_MAX - (UINT64_MAX % max);
289     do
290     {
291       gcry_create_nonce (&ret, sizeof(ret));
292     }
293     while (ret >= ul);
294
295     return ret % max;
296
297   case GNUNET_CRYPTO_QUALITY_WEAK:
298     ret = max * get_weak_random ();
299     if (ret >= max)
300       ret = max - 1;
301     return ret;
302
303   default:
304     GNUNET_assert (0);
305   }
306   return 0;
307 }
308
309
310 /**
311  * Allocation wrapper for libgcrypt, used to avoid bad locking
312  * strategy of libgcrypt implementation.
313  */
314 static void *
315 w_malloc (size_t n)
316 {
317   return calloc (n, 1);
318 }
319
320
321 /**
322  * Allocation wrapper for libgcrypt, used to avoid bad locking
323  * strategy of libgcrypt implementation.
324  */
325 static int
326 w_check (const void *p)
327 {
328   (void) p;
329   return 0; /* not secure memory */
330 }
331
332
333 /**
334  * Initialize libgcrypt.
335  */
336 void __attribute__ ((constructor))
337 GNUNET_CRYPTO_random_init ()
338 {
339   gcry_error_t rc;
340
341   if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
342   {
343     fprintf (
344       stderr,
345       _ ("libgcrypt has not the expected version (version %s is required).\n"),
346       NEED_LIBGCRYPT_VERSION);
347     GNUNET_assert (0);
348   }
349   /* set custom allocators */
350   gcry_set_allocation_handler (&w_malloc, &w_malloc, &w_check, &realloc, &free);
351   /* Disable use of secure memory */
352   if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
353     fprintf (stderr,
354              "Failed to set libgcrypt option %s: %s\n",
355              "DISABLE_SECMEM",
356              gcry_strerror (rc));
357   /* Otherwise gnunet-ecc takes forever to complete, besides
358      we are fine with "just" using GCRY_STRONG_RANDOM */
359   if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
360     fprintf (stderr,
361              "Failed to set libgcrypt option %s: %s\n",
362              "ENABLE_QUICK_RANDOM",
363              gcry_strerror (rc));
364   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
365   gcry_fast_random_poll ();
366   GNUNET_CRYPTO_seed_weak_random (
367     time (NULL)
368     ^ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
369 }
370
371
372 /**
373  * Nicely shut down libgcrypt.
374  */
375 void __attribute__ ((destructor))
376 GNUNET_CRYPTO_random_fini ()
377 {
378   gcry_set_progress_handler (NULL, NULL);
379 #ifdef GCRYCTL_CLOSE_RANDOM_DEVICE
380   (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
381 #endif
382 }
383
384
385 /* end of crypto_random.c */