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