123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- /*
- This file is part of GNUnet. Copyright (C) 2001-2014 Christian Grothoff
- (and other contributing authors)
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file util/crypto_random.c
- * @brief functions to gather random numbers
- * @author Christian Grothoff
- */
- #include "platform.h"
- #include "gnunet_crypto_lib.h"
- #include <gcrypt.h>
- #define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-random", __VA_ARGS__)
- #define LOG_STRERROR(kind, syscall) \
- GNUNET_log_from_strerror (kind, "util-crypto-random", syscall)
- /* TODO: ndurner, move this to plibc? */
- /* The code is derived from glibc, obviously */
- #if ! HAVE_RANDOM || ! HAVE_SRANDOM
- #ifdef RANDOM
- #undef RANDOM
- #endif
- #ifdef SRANDOM
- #undef SRANDOM
- #endif
- #define RANDOM() glibc_weak_rand32 ()
- #define SRANDOM(s) glibc_weak_srand32 (s)
- #if defined(RAND_MAX)
- #undef RAND_MAX
- #endif
- #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
- static int32_t glibc_weak_rand32_state = 1;
- void
- glibc_weak_srand32 (int32_t s)
- {
- glibc_weak_rand32_state = s;
- }
- int32_t
- glibc_weak_rand32 ()
- {
- int32_t val = glibc_weak_rand32_state;
- val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff;
- glibc_weak_rand32_state = val;
- return val;
- }
- #endif
- /**
- * Create a cryptographically weak pseudo-random number in the interval of 0 to 1.
- *
- * @return number between 0 and 1.
- */
- static double
- get_weak_random ()
- {
- return((double) random () / RAND_MAX);
- }
- /**
- * Seed a weak random generator. Only #GNUNET_CRYPTO_QUALITY_WEAK-mode generator
- * can be seeded.
- *
- * @param seed the seed to use
- */
- void
- GNUNET_CRYPTO_seed_weak_random (int32_t seed)
- {
- srandom (seed);
- }
- /**
- * @ingroup crypto
- * Zero out @a buffer, securely against compiler optimizations.
- * Used to delete key material.
- *
- * @param buffer the buffer to zap
- * @param length buffer length
- */
- void
- GNUNET_CRYPTO_zero_keys (void *buffer, size_t length)
- {
- #if HAVE_MEMSET_S
- memset_s (buffer, length, 0, length);
- #elif HAVE_EXPLICIT_BZERO
- explicit_bzero (buffer, length);
- #else
- volatile unsigned char *p = buffer;
- while (length--)
- *p++ = 0;
- #endif
- }
- /**
- * @ingroup crypto
- * Fill block with a random values.
- *
- * @param mode desired quality of the random number
- * @param buffer the buffer to fill
- * @param length buffer length
- */
- void
- GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode,
- void *buffer,
- size_t length)
- {
- #ifdef gcry_fast_random_poll
- static unsigned int invokeCount;
- #endif
- switch (mode)
- {
- case GNUNET_CRYPTO_QUALITY_STRONG:
- /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
- #ifdef gcry_fast_random_poll
- if ((invokeCount++ % 256) == 0)
- gcry_fast_random_poll ();
- #endif
- gcry_randomize (buffer, length, GCRY_STRONG_RANDOM);
- return;
- case GNUNET_CRYPTO_QUALITY_NONCE:
- gcry_create_nonce (buffer, length);
- return;
- case GNUNET_CRYPTO_QUALITY_WEAK:
- /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
- #ifdef gcry_fast_random_poll
- if ((invokeCount++ % 256) == 0)
- gcry_fast_random_poll ();
- #endif
- gcry_randomize (buffer, length, GCRY_WEAK_RANDOM);
- return;
- default:
- GNUNET_assert (0);
- }
- }
- /**
- * Produce a random unsigned 32-bit number modulo @a i.
- *
- * @param mode desired quality of the random number
- * @param i the upper limit (exclusive) for the random number
- * @return a random value in the interval [0,i[.
- */
- uint32_t
- GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i)
- {
- #ifdef gcry_fast_random_poll
- static unsigned int invokeCount;
- #endif
- uint32_t ret;
- uint32_t ul;
- GNUNET_assert (i > 0);
- switch (mode)
- {
- case GNUNET_CRYPTO_QUALITY_STRONG:
- /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */
- #ifdef gcry_fast_random_poll
- if ((invokeCount++ % 256) == 0)
- gcry_fast_random_poll ();
- #endif
- ul = UINT32_MAX - (UINT32_MAX % i);
- do
- {
- gcry_randomize ((unsigned char *) &ret,
- sizeof(uint32_t),
- GCRY_STRONG_RANDOM);
- }
- while (ret >= ul);
- return ret % i;
- case GNUNET_CRYPTO_QUALITY_NONCE:
- ul = UINT32_MAX - (UINT32_MAX % i);
- do
- {
- gcry_create_nonce (&ret, sizeof(ret));
- }
- while (ret >= ul);
- return ret % i;
- case GNUNET_CRYPTO_QUALITY_WEAK:
- ret = i * get_weak_random ();
- if (ret >= i)
- ret = i - 1;
- return ret;
- default:
- GNUNET_assert (0);
- }
- return 0;
- }
- /**
- * Get an array with a random permutation of the
- * numbers 0...n-1.
- * @param mode #GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive)
- * PRNG should be used, #GNUNET_RANDOM_QUALITY_WEAK otherwise
- * @param n the size of the array
- * @return the permutation array (allocated from heap)
- */
- unsigned int *
- GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n)
- {
- unsigned int *ret;
- unsigned int i;
- unsigned int tmp;
- uint32_t x;
- GNUNET_assert (n > 0);
- ret = GNUNET_malloc (n * sizeof(unsigned int));
- for (i = 0; i < n; i++)
- ret[i] = i;
- for (i = n - 1; i > 0; i--)
- {
- x = GNUNET_CRYPTO_random_u32 (mode, i + 1);
- tmp = ret[x];
- ret[x] = ret[i];
- ret[i] = tmp;
- }
- return ret;
- }
- /**
- * Generate random unsigned 64-bit value.
- *
- * @param mode desired quality of the random number
- * @param max value returned will be in range [0,max) (exclusive)
- * @return random 64-bit number
- */
- uint64_t
- GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
- {
- uint64_t ret;
- uint64_t ul;
- GNUNET_assert (max > 0);
- switch (mode)
- {
- case GNUNET_CRYPTO_QUALITY_STRONG:
- ul = UINT64_MAX - (UINT64_MAX % max);
- do
- {
- gcry_randomize ((unsigned char *) &ret,
- sizeof(uint64_t),
- GCRY_STRONG_RANDOM);
- }
- while (ret >= ul);
- return ret % max;
- case GNUNET_CRYPTO_QUALITY_NONCE:
- ul = UINT64_MAX - (UINT64_MAX % max);
- do
- {
- gcry_create_nonce (&ret, sizeof(ret));
- }
- while (ret >= ul);
- return ret % max;
- case GNUNET_CRYPTO_QUALITY_WEAK:
- ret = max * get_weak_random ();
- if (ret >= max)
- ret = max - 1;
- return ret;
- default:
- GNUNET_assert (0);
- }
- return 0;
- }
- /**
- * Allocation wrapper for libgcrypt, used to avoid bad locking
- * strategy of libgcrypt implementation.
- */
- static void *
- w_malloc (size_t n)
- {
- return calloc (n, 1);
- }
- /**
- * Allocation wrapper for libgcrypt, used to avoid bad locking
- * strategy of libgcrypt implementation.
- */
- static int
- w_check (const void *p)
- {
- (void) p;
- return 0; /* not secure memory */
- }
- /**
- * Initialize libgcrypt.
- */
- void __attribute__ ((constructor)) GNUNET_CRYPTO_random_init ()
- {
- gcry_error_t rc;
- if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
- {
- fprintf (
- stderr,
- _ ("libgcrypt has not the expected version (version %s is required).\n"),
- NEED_LIBGCRYPT_VERSION);
- GNUNET_assert (0);
- }
- /* set custom allocators */
- gcry_set_allocation_handler (&w_malloc, &w_malloc, &w_check, &realloc, &free);
- /* Disable use of secure memory */
- if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
- fprintf (stderr,
- "Failed to set libgcrypt option %s: %s\n",
- "DISABLE_SECMEM",
- gcry_strerror (rc));
- /* Otherwise gnunet-ecc takes forever to complete, besides
- we are fine with "just" using GCRY_STRONG_RANDOM */
- if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0)))
- fprintf (stderr,
- "Failed to set libgcrypt option %s: %s\n",
- "ENABLE_QUICK_RANDOM",
- gcry_strerror (rc));
- gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
- gcry_fast_random_poll ();
- GNUNET_CRYPTO_seed_weak_random (
- time (NULL)
- ^ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
- }
- /**
- * Nicely shut down libgcrypt.
- */
- void __attribute__ ((destructor)) GNUNET_CRYPTO_random_fini ()
- {
- gcry_set_progress_handler (NULL, NULL);
- #ifdef GCRYCTL_CLOSE_RANDOM_DEVICE
- (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
- #endif
- }
- /* end of crypto_random.c */
|