GNUnet 0.21.0
crypto_random.c
Go to the documentation of this file.
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
28#include "platform.h"
29#include "gnunet_util_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
60{
62}
63
64
65int32_t
67{
68 int32_t val = glibc_weak_rand32_state;
69
70 val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
72 return val;
73}
74
75
76#endif
77
83static double
85{
86 return((double) random () / RAND_MAX);
87}
88
89
90void
92{
93#ifdef OPENBSD
94 srandom_deterministic (seed);
95#else
96 srandom (seed);
97#endif
98}
99
100
109void
110GNUNET_CRYPTO_zero_keys (void *buffer, size_t length)
111{
112#if HAVE_MEMSET_S
113 memset_s (buffer, length, 0, length);
114#elif HAVE_EXPLICIT_BZERO
115 explicit_bzero (buffer, length);
116#else
117 volatile unsigned char *p = buffer;
118 while (length--)
119 *p++ = 0;
120#endif
121}
122
123
132void
134 void *buffer,
135 size_t length)
136{
137#ifdef gcry_fast_random_poll
138 static unsigned int invokeCount;
139#endif
140 switch (mode)
141 {
143 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
144#ifdef gcry_fast_random_poll
145 if ((invokeCount++ % 256) == 0)
146 gcry_fast_random_poll ();
147#endif
148 gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
149 return;
150
152 gcry_create_nonce (buffer, length);
153 return;
154
156 /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
157#ifdef gcry_fast_random_poll
158 if ((invokeCount++ % 256) == 0)
159 gcry_fast_random_poll ();
160#endif
161 gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
162 return;
163
164 default:
165 GNUNET_assert (0);
166 }
167}
168
169
177uint32_t
179 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 {
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
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
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
237unsigned int *
239 unsigned int n)
240{
241 unsigned int *ret;
242 unsigned int i;
243 unsigned int tmp;
244 uint32_t x;
245
246 GNUNET_assert (n > 0);
247 ret = GNUNET_malloc (n * sizeof(unsigned int));
248 for (i = 0; i < n; i++)
249 ret[i] = i;
250 for (i = n - 1; i > 0; i--)
251 {
252 x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
253 tmp = ret[x];
254 ret[x] = ret[i];
255 ret[i] = tmp;
256 }
257 return ret;
258}
259
260
261uint64_t
263 uint64_t max)
264{
265 uint64_t ret;
266 uint64_t ul;
267
268 GNUNET_assert (max > 0);
269 switch (mode)
270 {
272 ul = UINT64_MAX - (UINT64_MAX % max);
273 do
274 {
275 gcry_randomize ((unsigned char *) &ret,
276 sizeof(uint64_t),
277 GCRY_STRONG_RANDOM);
278 }
279 while (ret >= ul);
280 return ret % max;
281
283 ul = UINT64_MAX - (UINT64_MAX % max);
284 do
285 {
286 gcry_create_nonce (&ret, sizeof(ret));
287 }
288 while (ret >= ul);
289
290 return ret % max;
291
293 ret = max * get_weak_random ();
294 if (ret >= max)
295 ret = max - 1;
296 return ret;
297
298 default:
299 GNUNET_assert (0);
300 }
301 return 0;
302}
303
304
315void
317 struct GNUNET_Uuid *uuid)
318{
319 struct GNUNET_TIME_Absolute now;
320 uint64_t ms;
321 uint64_t be;
322 char *base;
323
325 uuid,
326 sizeof (struct GNUNET_Uuid));
328 ms = now.abs_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
329 be = GNUNET_htonll (ms);
330 base = (char *) &be;
331 memcpy (uuid,
332 base + 2,
333 sizeof (be) - 2);
334}
335
336
341static void *
342w_malloc (size_t n)
343{
344 return calloc (n, 1);
345}
346
347
352static int
353w_check (const void *p)
354{
355 (void) p;
356 return 0; /* not secure memory */
357}
358
359
363void __attribute__ ((constructor))
364GNUNET_CRYPTO_random_init ()
365{
366 gcry_error_t rc;
367
368 if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
369 {
370 fprintf (
371 stderr,
372 _ ("libgcrypt has not the expected version (version %s is required).\n"),
373 NEED_LIBGCRYPT_VERSION);
374 GNUNET_assert (0);
375 }
376 /* set custom allocators */
377 gcry_set_allocation_handler (&w_malloc, &w_malloc, &w_check, &realloc, &free);
378 /* Disable use of secure memory */
379 if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
380 fprintf (stderr,
381 "Failed to set libgcrypt option %s: %s\n",
382 "DISABLE_SECMEM",
383 gcry_strerror (rc));
384 /* Otherwise gnunet-ecc takes forever to complete, besides
385 we are fine with "just" using GCRY_STRONG_RANDOM */
386 if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
387 fprintf (stderr,
388 "Failed to set libgcrypt option %s: %s\n",
389 "ENABLE_QUICK_RANDOM",
390 gcry_strerror (rc));
391 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
392 gcry_fast_random_poll ();
394 time (NULL)
396}
397
398
402void __attribute__ ((destructor))
403GNUNET_CRYPTO_random_fini ()
404{
405 gcry_set_progress_handler (NULL, NULL);
406#ifdef GCRYCTL_CLOSE_RANDOM_DEVICE
407 (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
408#endif
409}
410
411
412/* end of crypto_random.c */
static int32_t glibc_weak_rand32_state
Definition: crypto_random.c:55
void glibc_weak_srand32(int32_t s)
Definition: crypto_random.c:59
#define RAND_MAX
Definition: crypto_random.c:52
int32_t glibc_weak_rand32()
Definition: crypto_random.c:66
static double get_weak_random(void)
Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
Definition: crypto_random.c:84
static void * w_malloc(size_t n)
Allocation wrapper for libgcrypt, used to avoid bad locking strategy of libgcrypt implementation.
static int w_check(const void *p)
Allocation wrapper for libgcrypt, used to avoid bad locking strategy of libgcrypt implementation.
void __attribute__((constructor))
Initialize libgcrypt.
static int ret
Final status code.
Definition: gnunet-arm.c:94
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
static enum @44 mode
Should we do a PUT (mode = 0) or GET (mode = 1);.
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
void GNUNET_CRYPTO_random_timeflake(enum GNUNET_CRYPTO_Quality mode, struct GNUNET_Uuid *uuid)
Fill UUID with a timeflake pseudo-random value.
void GNUNET_CRYPTO_random_block(enum GNUNET_CRYPTO_Quality mode, void *buffer, size_t length)
Fill block with a random values.
GNUNET_CRYPTO_Quality
Desired quality level for random numbers.
void GNUNET_CRYPTO_seed_weak_random(int32_t seed)
Seed a weak random generator.
Definition: crypto_random.c:91
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random unsigned 32-bit number modulo i.
unsigned int * GNUNET_CRYPTO_random_permute(enum GNUNET_CRYPTO_Quality mode, unsigned int n)
Get an array with a random permutation of the numbers 0...n-1.
void GNUNET_CRYPTO_zero_keys(void *buffer, size_t length)
Zero out buffer, securely against compiler optimizations.
@ GNUNET_CRYPTO_QUALITY_STRONG
High-quality operations are desired.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
@ GNUNET_CRYPTO_QUALITY_NONCE
Randomness for IVs etc.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:37
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
#define max(x, y)
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
A UUID, a 128 bit "random" value.