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