[svn] gcry - r1147 - in trunk: . cipher tests

svn author wk cvs at cvs.gnupg.org
Tue Mar 14 14:13:13 CET 2006


Author: wk
Date: 2006-03-14 14:13:11 +0100 (Tue, 14 Mar 2006)
New Revision: 1147

Modified:
   trunk/ChangeLog
   trunk/NEWS
   trunk/TODO
   trunk/cipher/ChangeLog
   trunk/cipher/random.c
   trunk/configure.ac
   trunk/tests/ChangeLog
   trunk/tests/ac-data.c
   trunk/tests/ac.c
   trunk/tests/basic.c
   trunk/tests/keygen.c
   trunk/tests/pkbench.c
   trunk/tests/pubkey.c
Log:
Use quick key generation.
Cleaned up output; i.e. take care of --verbose.


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/ChangeLog	2006-03-14 13:13:11 UTC (rev 1147)
@@ -1,3 +1,7 @@
+2006-03-14  Werner Koch  <wk at g10code.com>
+
+	* configure.ac: Check for fctnl and ftruncate.
+
 2005-12-08  Werner Koch  <wk at g10code.com>
 
 	* configure.ac: Changed the random device names for netbsd.  From
@@ -1032,7 +1036,7 @@
 
 	
  Copyright 1998, 1999, 2000, 2001, 2002, 2003,
-	   2004 Free Software Foundation, Inc.
+	   2004, 2006 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/NEWS	2006-03-14 13:13:11 UTC (rev 1147)
@@ -7,6 +7,11 @@
    general a good idea to spread this macro into the application code
    to make sure that these polls happen often enough.
 
+ * Reading and writing the random seed file is now protected by a
+   fcntl style file lock on systems that provide this function.
+
+ * Support for SHA-224 and HMAC using SHA-384 and SHA-512.
+
  * Interface changes relative to the 1.2.0 release:
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 gcry_fast_random_poll	NEW

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/TODO	2006-03-14 13:13:11 UTC (rev 1147)
@@ -1,6 +1,6 @@
 What's left to do                                 -*- outline -*-
 
-* Add more tests.  Even basic is very minimal.
+* Add more tests.
 
 * udiv-qrnbd.o should get build as *.lo [HPUX]
 
@@ -26,9 +26,6 @@
   with the ac interface (i.e. by using ac's `data sets') and the pk
   interface could be changed to be a wrapper for the ac interface.
 
-* HMAC won't work with sha-512 due to the different block size.  OTOH,
-  I can imagine no cryptographic reason to use it.
-
 * cipher/pubkey.c and pubkey implementaions.
   Don't rely on the secure memory based wiping function but add an
   extra wiping.
@@ -39,3 +36,15 @@
 
 * Use builtin bit functions of gcc 3.4
 
+* Consider using a daemon to maintain he random pool
+
+  The down side of this is that we can't assume that the random das
+  has always been stored in "secure memory".  And we rely on that
+  sniffing of Unix domain sockets is not possible.  We can implement
+  this simply by detecting a special prefixed random seed name and
+  divert in this case to the daemon.  There are several benefits with
+  such an approach: We keep the state of the RNG over invocations of
+  libgcrypt based applications, don't need time consuming
+  initialization of the pool and in case the entropy collectros need
+  to run that bunch of Unix utilities we don't waste their precious
+  results.

Modified: trunk/cipher/ChangeLog
===================================================================
--- trunk/cipher/ChangeLog	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/cipher/ChangeLog	2006-03-14 13:13:11 UTC (rev 1147)
@@ -1,3 +1,12 @@
+2006-03-14  Werner Koch  <wk at g10code.com>
+
+	* random.c (lock_seed_file): New.
+	(read_seed_file, _gcry_update_random_seed_file): Use it.
+
+	* random.c (gcry_create_nonce):  Detect a fork and re-seed.
+	(read_pool): Fixed the fork detection; it used to work only for
+	multi-threaded processes.
+
 2006-03-12  Brad Hards  <bradh at frogmouth.net>  (wk)
 
 	* md.c (md_open): Use new variable macpads_Bsize instead of

Modified: trunk/cipher/random.c
===================================================================
--- trunk/cipher/random.c	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/cipher/random.c	2006-03-14 13:13:11 UTC (rev 1147)
@@ -1,6 +1,6 @@
 /* random.c  -	random number generator
  * Copyright (C) 1998, 2000, 2001, 2002, 2003,
- *               2004  Free Software Foundation, Inc.
+ *               2004, 2005, 2006  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -62,7 +62,14 @@
 #define RAND_MAX 32767
 #endif
 
+/* Check whether we can lock the seed file read write. */
+#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM)
+#define LOCK_SEED_FILE 1
+#else
+#define LOCK_SEED_FILE 0
+#endif
 
+
 #if SIZEOF_UNSIGNED_LONG == 8
 #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
 #elif SIZEOF_UNSIGNED_LONG == 4
@@ -259,7 +266,8 @@
   byte *buf, *p;
   int err;
 
-  /* First a hack toavoid the strong random using our regression test suite. */
+  /* First a hack to avoid the strong random using our regression test
+     suite. */
   if (quick_test && level > 1)
     level = 1;
 
@@ -531,6 +539,45 @@
 }
 
 
+/* Lock an open file identified by file descriptor FD and wait a
+   reasonable time to succeed.  With FOR_WRITE set to true a write
+   lock will be taken.  FNAME is used only for diagnostics. Returns 0
+   on success or -1 on error. */
+static int
+lock_seed_file (int fd, const char *fname, int for_write)
+{
+#if LOCK_SEED_FILE
+  struct flock lck;
+  struct timeval tv;
+  int backoff=0;
+
+  /* We take a lock on the entire file. */
+  memset (&lck, 0, sizeof lck);
+  lck.l_type = for_write? F_WRLCK : F_RDLCK;
+  lck.l_whence = SEEK_SET;
+
+  while (fcntl (fd, F_SETLK, &lck) == -1)
+    {
+      if (errno != EAGAIN && errno != EACCES)
+        {
+          log_info (_("can't lock `%s': %s\n"), fname, strerror (errno));
+          return -1;
+        }
+
+      if (backoff > 2) /* Show the first message after ~2.25 seconds. */
+        log_info( _("waiting for lock on `%s'...\n"), fname);
+      
+      tv.tv_sec = backoff;
+      tv.tv_usec = 250000;
+      select (0, NULL, NULL, NULL, &tv);
+      if (backoff < 10)
+        backoff++ ;
+    }
+#endif /*LOCK_SEED_FILE*/
+  return 0;
+}
+
+
 /*
   Read in a seed form the random_seed file
   and return true if this was successful.
@@ -564,6 +611,11 @@
       log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
       return 0;
     }
+  if (lock_seed_file (fd, seed_file_name, 0))
+    {
+      close (fd);
+      return 0;
+    }
   if (fstat( fd, &sb ) )
     {
       log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
@@ -652,7 +704,7 @@
     log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
   pool_is_locked = 1;
 
-  /* copy the entropy pool to a scratch pool and mix both of them */
+  /* Copy the entropy pool to a scratch pool and mix both of them. */
   for (i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
        i < POOLWORDS; i++, dp++, sp++ ) 
     {
@@ -661,28 +713,41 @@
   mix_pool(rndpool); rndstats.mixrnd++;
   mix_pool(keypool); rndstats.mixkey++;
 
-#ifdef HAVE_DOSISH_SYSTEM
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
   fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
              S_IRUSR|S_IWUSR );
 #else
-  fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# if LOCK_SEED_FILE
+    fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
+# else
+    fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# endif
 #endif
 
   if (fd == -1 )
     log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+  else if (lock_seed_file (fd, seed_file_name, 1))
+    {
+      close (fd);
+    }
+#if LOCK_SEED_FILE
+  else if (ftruncate (fd, 0))
+    {
+      log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno));
+      close (fd);
+    }
+#endif /*LOCK_SEED_FILE*/
   else 
     {
       do
         {
           i = write (fd, keypool, POOLSIZE );
         } 
-      while( i == -1 && errno == EINTR );
+      while (i == -1 && errno == EINTR);
       if (i != POOLSIZE) 
-        log_info (_("can't write `%s': %s\n"),
-                  seed_file_name, strerror(errno) );
+        log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno));
       if (close(fd))
-        log_info(_("can't close `%s': %s\n"),
-                 seed_file_name, strerror(errno) );
+        log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno));
     }
   
   pool_is_locked = 0;
@@ -694,22 +759,40 @@
 
 
 /* Read random out of the pool. This function is the core of the
-   public random fucntions.  Note that Level 0 is not anymore handeld
-   special and in fact an alias for level 1. */
+   public random functions.  Note that Level 0 is not anymore handeld
+   special and in fact an alias for level 1.  Must be called with the
+   pool already locked.  */
 static void
 read_pool (byte *buffer, size_t length, int level)
 {
   int i;
   unsigned long *sp, *dp;
-  volatile pid_t my_pid; /* The volatile is there to make sure the
-                            compiler does not optimize the code away
-                            in case the getpid function is badly
-                            attributed. */
+  /* The volatile is there to make sure the compiler does not optimize
+     the code away in case the getpid function is badly attributed.
+     Note that we keep a pid in a static variable as well as in a
+     stack based one; the latter is to detect ill behaving thread
+     libraries, ignoring the pool mutexes. */
+  static volatile pid_t my_pid = (pid_t)(-1); 
+  volatile pid_t my_pid2;
 
+
  retry:
   /* Get our own pid, so that we can detect a fork. */
-  my_pid = getpid ();
+  my_pid2 = getpid ();
+  if (my_pid == (pid_t)(-1))                                
+    my_pid = my_pid2;
+  if ( my_pid != my_pid2 )
+    {
+      /* We detected a plain fork; i.e. we are now the child.  Update
+         the static pid and add some randomness. */
+      pid_t x;
 
+      my_pid = my_pid2;
+      x = my_pid;
+      add_randomness (&x, sizeof(x), 0);
+      just_mixed = 0; /* Make sure it will get mixed. */
+    }
+
   assert (pool_is_locked);
 
   /* Our code does not allow to extract more than POOLSIZE.  Better
@@ -756,7 +839,7 @@
       pool_balance += needed;
     }
 
-  /* make sure the pool is filled */
+  /* Make sure the pool is filled. */
   while (!pool_filled)
     random_poll();
 
@@ -765,7 +848,10 @@
   
   /* Mix the pid in so that we for sure won't deliver the same random
      after a fork. */
-  add_randomness (&my_pid, sizeof (my_pid), 0);
+  {
+    pid_t apid = my_pid;
+    add_randomness (&apid, sizeof (apid), 0);
+  }
 
   /* Mix the pool (if add_randomness() didn't it). */
   if (!just_mixed)
@@ -783,8 +869,8 @@
   mix_pool(rndpool); rndstats.mixrnd++;
   mix_pool(keypool); rndstats.mixkey++;
 
-  /* Read the required data.  We use a readpointer to read from a
-     different position each time */
+  /* Read the requested data.  We use a read pointer to read from a
+     different position each time.  */
   while (length--)
     {
       *buffer++ = keypool[pool_readpos++];
@@ -801,17 +887,14 @@
 
   /* We need to detect whether a fork has happened.  A fork might have
      an identical pool and thus the child and the parent could emit
-     the very same random number.  Obviously this can only happen when
-     running multi-threaded and the pool lock should even catch this.
-     However things do get wrong and thus we better check and retry it
-     here.  We assume that the thread library has no other fatal
-     faults, though.
-   */
-  if ( getpid () != my_pid )
+     the very same random number.  This test here is to detect forks
+     in a multi-threaded process. */
+  if ( getpid () != my_pid2 )
     {
       pid_t x = getpid();
       add_randomness (&x, sizeof(x), 0);
       just_mixed = 0; /* Make sure it will get mixed. */
+      my_pid = x;     /* Also update the static pid. */
       goto retry;
     }
 }
@@ -1101,6 +1184,10 @@
 {
   static unsigned char nonce_buffer[20+8];
   static int nonce_buffer_initialized = 0;
+  static volatile pid_t my_pid; /* The volatile is there to make sure the
+                                   compiler does not optimize the code away
+                                   in case the getpid function is badly
+                                   attributed. */
   unsigned char *p;
   size_t n;
   int err;
@@ -1121,6 +1208,8 @@
       pid_t apid = getpid ();
       time_t atime = time (NULL);
 
+      my_pid = apid;
+
       if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
         BUG ();
 
@@ -1137,6 +1226,12 @@
 
       nonce_buffer_initialized = 1;
     }
+  else if ( my_pid != getpid () )
+    {
+      /* We forked. Need to reseed the buffer - doing this for the
+         private part should be sufficient. */
+      gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
+    }
 
   /* Create the nonce by hashing the entire buffer, returning the hash
      and updating the first 20 bytes of the buffer with this hash. */

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/configure.ac	2006-03-14 13:13:11 UTC (rev 1147)
@@ -1,6 +1,6 @@
 # Configure.ac script for Libgcrypt
 # Copyright (C) 1998, 1999, 2000, 2001, 2002
-#               2003, 2004 Free Software Foundation, Inc.
+#               2003, 2004, 2006 Free Software Foundation, Inc.
 #
 # This file is part of Libgcrypt.
 #
@@ -484,6 +484,7 @@
 # Other checks
 AC_CHECK_FUNCS(strerror rand mmap getpagesize waitpid wait4)
 AC_CHECK_FUNCS(gettimeofday getrusage gethrtime clock_gettime)
+AC_CHECK_FUNCS(fcntl ftruncate)
 
 GNUPG_CHECK_MLOCK
 

Modified: trunk/tests/ChangeLog
===================================================================
--- trunk/tests/ChangeLog	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/tests/ChangeLog	2006-03-14 13:13:11 UTC (rev 1147)
@@ -1,3 +1,15 @@
+2006-03-14  Werner Koch  <wk at g10code.com>
+
+	* ac-data.c (check_sexp_conversion, check_run): Take care of VERBOSE.
+	* basic.c (main): Speed up test key generation.
+	(main): use progress handler only in verbose mode.
+	* ac.c (main): Ditto.
+	* pubkey.c (main): Ditto.
+	* keygen.c (main): Ditto.
+	(check_rsa_keys): Print key only in verbose mode.
+
+	* pkbench.c (main): Ditto.
+
 2006-03-10  Brad Hards  <bradh at frogmouth.net>  (wk, patch 2006-02-18)
 
 	* basic.c (check_one_hmac, check_hmac): New.

Modified: trunk/tests/ac-data.c
===================================================================
--- trunk/tests/ac-data.c	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/tests/ac-data.c	2006-03-14 13:13:11 UTC (rev 1147)
@@ -63,7 +63,8 @@
 
   err = gcry_ac_data_to_sexp (data, &sexp, identifiers);
   assert_err (err);
-  gcry_sexp_dump (sexp);
+  if (verbose)
+    gcry_sexp_dump (sexp);
   err = gcry_ac_data_from_sexp (&data2, sexp, identifiers);
   assert_err (err);
 
@@ -128,7 +129,8 @@
   check_sexp_conversion (data, identifiers_null);
   check_sexp_conversion (data, NULL);
 
-  printf ("data-set-test-0 succeeded\n");
+  if (verbose)
+    printf ("data-set-test-0 succeeded\n");
 
   gcry_ac_data_clear (data);
 
@@ -161,16 +163,18 @@
   assert_err (err);
   gcry_free ((void *) label1);	/* FIXME!! */
   gcry_mpi_release (mpi1);
-    
-  printf ("data-set-test-1 succeeded\n");
 
+  if (verbose)
+    printf ("data-set-test-1 succeeded\n");
+
   gcry_ac_data_clear (data);
   assert (! gcry_ac_data_length (data));
   check_sexp_conversion (data, identifiers);
   check_sexp_conversion (data, identifiers_null);
   check_sexp_conversion (data, NULL);
 
-  printf ("data-set-test-2 succeeded\n");
+  if (verbose)
+    printf ("data-set-test-2 succeeded\n");
  
   gcry_ac_data_destroy (data);
  

Modified: trunk/tests/ac.c
===================================================================
--- trunk/tests/ac.c	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/tests/ac.c	2006-03-14 13:13:11 UTC (rev 1147)
@@ -152,6 +152,8 @@
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+  /* No valuable keys are create, so we can speed up our RNG. */
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
   for (; i > 0; i--)
     check_run ();

Modified: trunk/tests/basic.c
===================================================================
--- trunk/tests/basic.c	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/tests/basic.c	2006-03-14 13:13:11 UTC (rev 1147)
@@ -1096,7 +1096,7 @@
       { GCRY_MD_SHA1, "!" /* kludge for "a"*1000000 */ ,
 	"\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E"
 	"\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" },
-      // From RFC3874
+      /* From RFC3874 */
       {	GCRY_MD_SHA224, "abc",
 	"\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3"
 	"\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7" },
@@ -1920,12 +1920,16 @@
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
 
-  gcry_set_progress_handler (progress_handler, NULL);
+  if (verbose)
+    gcry_set_progress_handler (progress_handler, NULL);
   
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+  /* No valuable keys are create, so we can speed up our RNG. */
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
   check_ciphers ();
   check_aes128_cbc_cts_cipher ();
   check_cbc_mac_cipher ();

Modified: trunk/tests/keygen.c
===================================================================
--- trunk/tests/keygen.c	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/tests/keygen.c	2006-03-14 13:13:11 UTC (rev 1147)
@@ -139,8 +139,9 @@
   {
     char buffer[20000];
     gcry_sexp_sprint (key, GCRYSEXP_FMT_ADVANCED, buffer, sizeof buffer);
-    printf ("=============================\n%s\n"
-            "=============================\n", buffer);
+    if (verbose)
+      printf ("=============================\n%s\n"
+              "=============================\n", buffer);
   }
   gcry_sexp_release (key);
   exit (0);

Modified: trunk/tests/pkbench.c
===================================================================
--- trunk/tests/pkbench.c	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/tests/pkbench.c	2006-03-14 13:13:11 UTC (rev 1147)
@@ -335,6 +335,9 @@
       char *algorithm = NULL;
       char *key_size = NULL;
 
+      /* No valuable keys are create, so we can speed up our RNG. */
+      gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
       if (argv[2])
 	{
 	  algorithm = argv[2];

Modified: trunk/tests/pubkey.c
===================================================================
--- trunk/tests/pubkey.c	2006-03-13 08:57:47 UTC (rev 1146)
+++ trunk/tests/pubkey.c	2006-03-14 13:13:11 UTC (rev 1147)
@@ -247,6 +247,8 @@
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+  /* No valuable keys are create, so we can speed up our RNG. */
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
   for (; i > 0; i--)
     check_run ();




More information about the Gnupg-commits mailing list