GNUnet  0.17.6
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 
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 
55 static int32_t glibc_weak_rand32_state = 1;
56 
57 
58 void
59 glibc_weak_srand32 (int32_t s)
60 {
62 }
63 
64 
65 int32_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 
83 static double
85 {
86  return((double) random () / RAND_MAX);
87 }
88 
89 
90 void
92 {
93 #ifdef OPENBSD
94  srandom_deterministic (seed);
95 #else
96  srandom (seed);
97 #endif
98 }
99 
100 
109 void
110 GNUNET_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 
132 void
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 
177 uint32_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 
237 unsigned 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 
261 uint64_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 
315 void
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));
327  now = GNUNET_TIME_absolute_get ();
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 
341 static void *
342 w_malloc (size_t n)
343 {
344  return calloc (n, 1);
345 }
346 
347 
352 static int
353 w_check (const void *p)
354 {
355  (void) p;
356  return 0; /* not secure memory */
357 }
358 
359 
363 void __attribute__ ((constructor))
364 GNUNET_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 
402 void __attribute__ ((destructor))
403 GNUNET_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 void * w_malloc(size_t n)
Allocation wrapper for libgcrypt, used to avoid bad locking strategy of libgcrypt implementation.
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 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
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:37
cryptographic primitives for GNUnet
static enum @8 mode
Should we do a PUT (mode = 0) or GET (mode = 1);.
Functions related to time.
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:36
#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:110
#define max(x, y)
#define _(String)
GNU gettext support macro.
Definition: platform.h:177
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
A UUID, a 128 bit "random" value.