-remove find() forking, we pretty much should not need this anymore, and it confused...
[oweals/gnunet.git] / src / util / crypto_random.c
index e8522d5e768942428c83e1f29ecfc804a59bfcc4..6840445d19f7d51846421add1325a8ce178059fb 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
+     (C) 2001-2013 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
  * @author Christian Grothoff
  */
 #include "platform.h"
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_crypto_lib.h"
-#include "gnunet_os_lib.h"
+#include "gnunet_util_lib.h"
 #include <gcrypt.h>
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
 
 #include <gcrypt.h>
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
 
+
 /* TODO: ndurner, move this to plibc? */
 /* The code is derived from glibc, obviously */
 /* TODO: ndurner, move this to plibc? */
 /* The code is derived from glibc, obviously */
-#if MINGW
+#if !HAVE_RANDOM || !HAVE_SRANDOM
 #ifdef RANDOM
 #undef RANDOM
 #endif
 #ifdef RANDOM
 #undef RANDOM
 #endif
 #undef RAND_MAX
 #endif
 #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
 #undef RAND_MAX
 #endif
 #define RAND_MAX 0x7fffffff /* Hopefully this is correct */
+
+
 static int32_t glibc_weak_rand32_state = 1;
 
 static int32_t glibc_weak_rand32_state = 1;
 
+
 void
 glibc_weak_srand32 (int32_t s)
 {
   glibc_weak_rand32_state = s;
 }
 
 void
 glibc_weak_srand32 (int32_t s)
 {
   glibc_weak_rand32_state = s;
 }
 
+
 int32_t
 glibc_weak_rand32 ()
 {
 int32_t
 glibc_weak_rand32 ()
 {
@@ -74,11 +77,12 @@ glibc_weak_rand32 ()
  * @return number between 0 and 1.
  */
 static double
  * @return number between 0 and 1.
  */
 static double
-weak_random ()
+get_weak_random ()
 {
   return ((double) RANDOM () / RAND_MAX);
 }
 
 {
   return ((double) RANDOM () / RAND_MAX);
 }
 
+
 /**
  * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator
  * can be seeded.
 /**
  * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator
  * can be seeded.
@@ -91,6 +95,48 @@ GNUNET_CRYPTO_seed_weak_random (int32_t seed)
   SRANDOM (seed);
 }
 
   SRANDOM (seed);
 }
 
+
+/**
+ * @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 value.
  *
 /**
  * Produce a random value.
  *
@@ -134,7 +180,7 @@ GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i)
     while (ret >= ul);
     return ret % i;
   case GNUNET_CRYPTO_QUALITY_WEAK:
     while (ret >= ul);
     return ret % i;
   case GNUNET_CRYPTO_QUALITY_WEAK:
-    ret = i * weak_random ();
+    ret = i * get_weak_random ();
     if (ret >= i)
       ret = i - 1;
     return ret;
     if (ret >= i)
       ret = i - 1;
     return ret;
@@ -175,6 +221,7 @@ GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n)
   return ret;
 }
 
   return ret;
 }
 
+
 /**
  * Random on unsigned 64-bit values.
  *
 /**
  * Random on unsigned 64-bit values.
  *
@@ -211,7 +258,7 @@ GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
 
     return ret % max;
   case GNUNET_CRYPTO_QUALITY_WEAK:
 
     return ret % max;
   case GNUNET_CRYPTO_QUALITY_WEAK:
-    ret = max * weak_random ();
+    ret = max * get_weak_random ();
     if (ret >= max)
       ret = max - 1;
     return ret;
     if (ret >= max)
       ret = max - 1;
     return ret;
@@ -221,116 +268,44 @@ GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
   return 0;
 }
 
   return 0;
 }
 
-/**
- * This function should only be called in testcases
- * where strong entropy gathering is not desired
- * (for example, for hostkey generation).
- */
-void
-GNUNET_CRYPTO_random_disable_entropy_gathering ()
-{
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-}
-
-
-/**
- * Process ID of the "find" process that we use for
- * entropy gathering.
- */
-static struct GNUNET_OS_Process *genproc;
-
-/**
- * Function called by libgcrypt whenever we are
- * blocked gathering entropy.
- */
-static void
-entropy_generator (void *cls, const char *what, int printchar, int current,
-                   int total)
-{
-  unsigned long code;
-  enum GNUNET_OS_ProcessStatusType type;
-  int ret;
-
-  if (0 != strcmp (what, "need_entropy"))
-    return;
-  if (current == total)
-  {
-    if (genproc != NULL)
-    {
-      if (0 != GNUNET_OS_process_kill (genproc, SIGTERM))
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill");
-      GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
-      GNUNET_OS_process_destroy (genproc);
-      genproc = NULL;
-    }
-    return;
-  }
-  if (genproc != NULL)
-  {
-    ret = GNUNET_OS_process_status (genproc, &type, &code);
-    if (ret == GNUNET_NO)
-      return;                   /* still running */
-    if (ret == GNUNET_SYSERR)
-    {
-      GNUNET_break (0);
-      return;
-    }
-    if (0 != GNUNET_OS_process_kill (genproc, SIGTERM))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill");
-    GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
-    GNUNET_OS_process_destroy (genproc);
-    genproc = NULL;
-  }
-  LOG (GNUNET_ERROR_TYPE_INFO, _("Starting `%s' process to generate entropy\n"),
-       "find");
-  genproc =
-     GNUNET_OS_start_process (GNUNET_NO,
-                             NULL, NULL, "sh", "sh", "-c",
-                             "exec find / -mount -type f -exec cp {} /dev/null \\; 2>/dev/null",
-                             NULL);
-}
-
 
 
-static void
-killfind ()
+void __attribute__ ((constructor))
+GNUNET_CRYPTO_random_init ()
 {
 {
-  if (genproc != NULL)
-  {
-    GNUNET_OS_process_kill (genproc, SIGKILL);
-    GNUNET_OS_process_destroy (genproc);
-    genproc = NULL;
-  }
-}
-
+  gcry_error_t rc;
 
 
-void __attribute__ ((constructor)) GNUNET_CRYPTO_random_init ()
-{
-  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
-  if (!gcry_check_version (GCRYPT_VERSION))
+  if (! gcry_check_version (NEED_LIBGCRYPT_VERSION))
   {
     FPRINTF (stderr,
   {
     FPRINTF (stderr,
-             _
-             ("libgcrypt has not the expected version (version %s is required).\n"),
-             GCRYPT_VERSION);
+             _("libgcrypt has not the expected version (version %s is required).\n"),
+             NEED_LIBGCRYPT_VERSION);
     GNUNET_abort ();
   }
     GNUNET_abort ();
   }
-#ifdef GCRYCTL_INITIALIZATION_FINISHED
+  if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0)))
+    FPRINTF (stderr,
+             "Failed to set libgcrypt option %s: %s\n",
+             "DISABLE_SECMEM",
+            gcry_strerror (rc));
+  /* we only generate ephemeral keys in-process; for those,
+     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_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
-#endif
-#ifdef gcry_fast_random_poll
   gcry_fast_random_poll ();
   gcry_fast_random_poll ();
-#endif
-  gcry_set_progress_handler (&entropy_generator, NULL);
-  atexit (&killfind);
   GNUNET_CRYPTO_seed_weak_random (time (NULL) ^
                                   GNUNET_CRYPTO_random_u32
                                   (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
 }
 
 
   GNUNET_CRYPTO_seed_weak_random (time (NULL) ^
                                   GNUNET_CRYPTO_random_u32
                                   (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
 }
 
 
-void __attribute__ ((destructor)) GNUNET_CRYPTO_random_fini ()
+void __attribute__ ((destructor))
+GNUNET_CRYPTO_random_fini ()
 {
   gcry_set_progress_handler (NULL, NULL);
 {
   gcry_set_progress_handler (NULL, NULL);
+  (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
 }
 
 
 }