Added some missing ChangeLog entries.
[libgcrypt.git] / cipher / random.c
index f573db5..60445fb 100644 (file)
@@ -1,24 +1,23 @@
 /* random.c  - random number generator
- *     Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
  * Libgcrypt 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 of the License, or
- * (at your option) any later version.
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
  * Libgcrypt 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 General Public License for more details.
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
-
 /****************
  * This random number generator is modelled after the one described
  * in Peter Gutmann's Paper: "Software Generation of Practically
@@ -56,7 +55,7 @@
 #include "rand-internal.h"
 #include "dynload.h"
 #include "cipher.h" /* only used for the rmd160_hash_buffer() prototype */
-#include "mutex.h"
+#include "ath.h"
 
 #ifndef RAND_MAX   /* for SunOS */
   #define RAND_MAX 32767
@@ -106,8 +105,8 @@ static int secure_alloc;
 static int quick_test;
 static int faked_rng;
 
-static mutex_t pool_lock;
-static int pool_is_locked; /* only for assertion */
+static ath_mutex_t pool_lock = ATH_MUTEX_INITIALIZER;
+static int pool_is_locked; /* only used for assertion */
 
 static byte *get_random_bytes( size_t nbytes, int level, int secure );
 static void read_pool( byte *buffer, size_t length, int level );
@@ -131,6 +130,9 @@ static struct {
     ulong naddbytes;
 } rndstats;
 
+static void (*progress_cb) (void *,const char*,int,int, int );
+static void *progress_cb_data;
+
 
 /* Note, we assume that this function is used before any concurrent
    access happens */
@@ -139,7 +141,7 @@ initialize(void)
 {
   int err;
 
-  err = mutex_init (pool_lock);
+  err = ath_mutex_init (&pool_lock);
   if (err)
     log_fatal ("failed to create the pool lock: %s\n", strerror (err) );
     
@@ -154,22 +156,42 @@ initialize(void)
   _gcry_cipher_modules_constructor ();
 }
 
-static void
-burn_stack (int bytes)
+
+/* Used to register a progress callback. */
+void
+_gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
+                                void *cb_data )
 {
-    char buf[128];
-    
-    memset (buf, 0, sizeof buf);
-    bytes -= sizeof buf;
-    if (bytes > 0)
-        burn_stack (bytes);
+  progress_cb = cb;
+  progress_cb_data = cb_data;
 }
 
 
+/* This progress function is currently used by the random modules to give hint
+   on how much more entropy is required. */
+void
+_gcry_random_progress (const char *what, int printchar, int current, int total)
+{
+  if (progress_cb)
+    progress_cb (progress_cb_data, what, printchar, current, total);
+}
+
+
+/* Initialize this random subsystem.  This function memrely calls the
+   initialzies and does not do anything more.  Doing this is not
+   really required but when running in a threaded environment we might
+   get a race condition otherwise. */
+void
+_gcry_random_initialize ()
+{
+  if (!is_initialized)
+    initialize ();
+}
+
 void
 _gcry_random_dump_stats()
 {
-    fprintf(stderr,
+    log_info (
            "random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
            "              outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu\n",
        POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
@@ -200,21 +222,6 @@ _gcry_quick_random_gen( int onoff )
     return faked_rng? 1 : last;
 }
 
-
-/****************
- * Fill the buffer with LENGTH bytes of cryptographically strong
- * random bytes. level 0 is not very strong, 1 is strong enough
- * for most usage, 2 is good for key generation stuff but may be very slow.
- */
-void
-gcry_randomize( byte *buffer, size_t length, enum gcry_random_level level )
-{
-    char *p = get_random_bytes( length, level, 1 );
-    memcpy( buffer, p, length );
-    gcry_free(p);
-}
-
-
 int
 _gcry_random_is_faked()
 {
@@ -238,7 +245,7 @@ get_random_bytes( size_t nbytes, int level, int secure )
        level = 1;
     MASK_LEVEL(level);
 
-    err = mutex_lock (pool_lock);
+    err = ath_mutex_lock (&pool_lock);
     if (err)
       log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
     pool_is_locked = 1;
@@ -261,25 +268,100 @@ get_random_bytes( size_t nbytes, int level, int secure )
     }
 
     pool_is_locked = 0;
-    err = mutex_unlock (pool_lock);
+    err = ath_mutex_unlock (&pool_lock);
     if (err)
       log_fatal ("failed to release the pool lock: %s\n", strerror (err));
     return buf;
 }
 
+
+/* Add BUFLEN bytes from BUF to the internal random pool.  QUALITY
+   should be in the range of 0..100 to indicate the goodness of the
+   entropy added, or -1 for goodness not known. 
+
+   Note, that this fucntion currently does nothing.
+*/
+int 
+gcry_random_add_bytes (const void * buf, size_t buflen, int quality)
+{
+  if (!buf || quality < -1 || quality > 100)
+    return GCRYERR_INV_ARG;
+  if (!buflen)
+    return 0; /* Shortcut this dummy case. */
+  /* Before we actuall enbale this code, we need to lock the pool,
+     have a look at the quality and find a way to add them without
+     disturbing the real entropy (we have estimated). */
+  /*add_randomness( buf, buflen, 1 );*/
+  return 0;
+}   
+    
+
 void *
 gcry_random_bytes( size_t nbytes, enum gcry_random_level level )
 {
-    return get_random_bytes( nbytes, level, 0 );
+  if (!is_initialized)
+    initialize();
+  return get_random_bytes( nbytes, level, 0 );
 }
 
 void *
 gcry_random_bytes_secure( size_t nbytes, enum gcry_random_level level )
 {
-    return get_random_bytes( nbytes, level, 1 );
+  if (!is_initialized)
+    initialize();
+  return get_random_bytes( nbytes, level, 1 );
 }
 
 
+/* Fill the buffer with LENGTH bytes of cryptographically strong
+   random bytes. level 0 is not very strong, 1 is strong enough for
+   most usage, 2 is good for key generation stuff but may be very
+   slow.  */
+void
+gcry_randomize (byte *buffer, size_t length, enum gcry_random_level level)
+{
+  byte *p;
+  int err;
+
+  if (!is_initialized)
+    initialize ();
+
+  if( quick_test && level > 1 )
+    level = 1;
+  MASK_LEVEL(level);
+
+  err = ath_mutex_lock (&pool_lock);
+  if (err)
+    log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
+  pool_is_locked = 1;
+  if (level == 1)
+    {
+      rndstats.getbytes1 += length;
+      rndstats.ngetbytes1++;
+    }
+  else if (level >= 2)
+    {
+      rndstats.getbytes2 += length;
+      rndstats.ngetbytes2++;
+    }
+
+  for (p = buffer; length > 0;)
+    {
+      size_t n = length > POOLSIZE? POOLSIZE : length;
+      read_pool (p, n, level);
+      length -= n;
+      p += n;
+    }
+
+  pool_is_locked = 0;
+  err = ath_mutex_unlock (&pool_lock);
+  if (err)
+    log_fatal ("failed to release the pool lock: %s\n", strerror (err));
+}
+
+
+
+
 /*
    Mix the pool:
 
@@ -366,7 +448,7 @@ mix_pool(byte *pool)
         _gcry_rmd160_hash_buffer (failsafe_digest, pool, POOLSIZE);
         failsafe_digest_valid = 1;
       }
-    burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */
+    _gcry_burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */
 }
 
 void
@@ -476,7 +558,7 @@ _gcry_update_random_seed_file()
       return;
     }
 
-  err = mutex_lock (pool_lock);
+  err = ath_mutex_lock (&pool_lock);
   if (err)
     log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
   pool_is_locked = 1;
@@ -511,7 +593,7 @@ _gcry_update_random_seed_file()
     }
 
   pool_is_locked = 0;
-  err = mutex_unlock (pool_lock);
+  err = ath_mutex_unlock (&pool_lock);
   if (err)
     log_fatal ("failed to release the pool lock: %s\n", strerror (err));
 }
@@ -738,18 +820,18 @@ _gcry_fast_random_poll()
   /* We have to make sure that the intialization is done because this
      gatherer might be called before any other functions and it is not
      sufficient to initialize it within do_fast_random_pool becuase we
-     want to use the mutex here. FIXME: Weh should initialie the mutex
-     using a global constructore independent from the initialization
+     want to use the mutex here. FIXME: Whe should initialize the mutex
+     using a global constructor independent from the initialization
      of the pool. */
   if (!is_initialized)
     initialize ();
-  err = mutex_lock (pool_lock);
+  err = ath_mutex_lock (&pool_lock);
   if (err)
     log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
   pool_is_locked = 1;
   do_fast_random_poll ();
   pool_is_locked = 0;
-  err = mutex_unlock (pool_lock);
+  err = ath_mutex_unlock (&pool_lock);
   if (err)
     log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));