Use extra counter to check random pool filling.
authorWerner Koch <wk@gnupg.org>
Thu, 23 Aug 2007 07:29:14 +0000 (07:29 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 23 Aug 2007 07:29:14 +0000 (07:29 +0000)
Updated the documentation.
Typo and comment fixes.

TODO
cipher/ChangeLog
cipher/random.c
doc/gcrypt.texi
src/dumpsexp.c

diff --git a/TODO b/TODO
index 3870dd0..6a2a3d5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -26,6 +26,8 @@ What's left to do                                 -*- outline -*-
   the asymmetric ciphers could be changed for convenient interaction
   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.
+  ==> It is unlikely that we will do that.  The AC interafce turned
+  out to be more complicated than the regular one.
 
 * cipher/pubkey.c and pubkey implementaions.
   Don't rely on the secure memory based wiping function but add an
@@ -34,19 +36,6 @@ What's left to do                                 -*- outline -*-
 * update/improve documentation
 ** it's outdated for e.g. gcry_pk_algo_info.
 ** document algorithm capabilities
-** Explain seed files and correlation
-  Multiple instances of the applications sharing the same random seed
-  file can be started in parallel, in which case they will read out
-  the same pool and then race for updating it (the last update
-  overwrites earlier updates).  They will differentiate only by the
-  weak entropy that is added in read_seed_file based on the PID and
-  clock, and up to 16 bytes of weak random non-blockingly.  The
-  consequence is that the output of these different instances is
-  correlated to some extent.  In the perfect scenario, the attacker
-  can control (or at least guess) the PID and clock of the
-  application, and drain the system's entropy pool to reduce the "up
-  to 16 bytes" above to 0.  Then the dependencies of the inital states
-  of the pools are completely known.
 ** Init requirements for random
    The documentation says in "Controlling the library" that some
    functions can only be used at initialization time, but it does not
@@ -72,7 +61,7 @@ What's left to do                                 -*- outline -*-
 
 * Use builtin bit functions of gcc 3.4
 
-* Consider using a daemon to maintainhe random pool
+* Consider using a daemon to maintain the random pool
   [Partly done] The down side of this is that we can't assume that the
   random has has always been stored in "secure memory".  And we rely
   on that sniffing of Unix domain sockets is not possible.  We can
@@ -102,18 +91,6 @@ What's left to do                                 -*- outline -*-
 * gcryptrnd.c
   Requires a test for pth [done] as well as some other tests.
 
-* random.c
- If add_randomness is invoked before the pool is filled, but with a
- weak source of entropy, for example the fast random poll, which
- may happen from other parts of gcrypt, then the pool is filled
- partially with weak random, defeating the purpose of pool_filled
- and the "source > 1" check in add_randomness.
-
- Suggestion: Count initial filling bytes with source > 1 in
- add_randomness seperately from the pool_writepos cursor.  Only set
- pool_filled if really POOLSIZE bytes with source > 1 have been
- added.
-
 * secmem.c
   Check whether the memory block is valid before releasing it and
   print a diagnosic, like glibc does.
index 0e9df8f..868a8ad 100644 (file)
@@ -1,3 +1,8 @@
+2007-08-23  Werner Koch  <wk@g10code.com>
+
+       * random.c (pool_filled_counter): New.
+       (add_randomness): Use it.
+
 2007-08-22  Werner Koch  <wk@g10code.com>
 
        * rndw32.c, rndunix.c: Switched to LGPL.
index 5c8aee9..40a4219 100644 (file)
@@ -112,10 +112,14 @@ static size_t pool_writepos;
 static size_t pool_readpos;
 
 /* This flag is set to true as soon as the pool has been completely
-   filles.  This may happen either by rerading a seed file or by
-   adding enough entropy.  */
+   filled the first time.  This may happen either by rereading a seed
+   file or by adding enough entropy.  */
 static int pool_filled;
 
+/* This counter is used to track whether the initial seeding has been
+   done with enough bytes from a reliable entropy source.  */
+static size_t pool_filled_counter;
+
 /* If random of level GCRY_VERY_STRONG_RANDOM has been requested we
    have stricter requirements on what kind of entropy is in the pool.
    In particular POOL_FILLED is not sufficient.  Thus we add some
@@ -133,7 +137,7 @@ static int pool_balance;
 static int just_mixed;
 
 /* The name of the seed file or NULL if no seed file has been defined.
-   The seed file needs to be regsitered at initialiation time.  we
+   The seed file needs to be regsitered at initialiation time.  We
    keep a malloced copy here.  */
 static char *seed_file_name;
 
@@ -742,8 +746,21 @@ lock_seed_file (int fd, const char *fname, int for_write)
 }
 
 
-/* Read in a seed form the random_seed file
-   and return true if this was successful.   */
+/* Read in a seed from the random_seed file and return true if this
+   was successful.
+
+   Note: Multiple instances of applications sharing the same random
+   seed file can be started in parallel, in which case they will read
+   out the same pool and then race for updating it (the last update
+   overwrites earlier updates).  They will differentiate only by the
+   weak entropy that is added in read_seed_file based on the PID and
+   clock, and up to 16 bytes of weak random non-blockingly.  The
+   consequence is that the output of these different instances is
+   correlated to some extent.  In the perfect scenario, the attacker
+   can control (or at least guess) the PID and clock of the
+   application, and drain the system's entropy pool to reduce the "up
+   to 16 bytes" above to 0.  Then the dependencies of the inital
+   states of the pools are completely known.  */
 static int
 read_seed_file (void)
 {
@@ -837,7 +854,7 @@ read_seed_file (void)
   /* And read a few bytes from our entropy source.  By using a level
    * of 0 this will not block and might not return anything with some
    * entropy drivers, however the rndlinux driver will use
-   * /dev/urandom and return some stuff - Do not read to much as we
+   * /dev/urandom and return some stuff - Do not read too much as we
    * want to be friendly to the scare system entropy resource. */
   read_random_source ( RANDOM_ORIGIN_INIT, 16, GCRY_WEAK_RANDOM );
 
@@ -927,7 +944,7 @@ _gcry_update_random_seed_file()
 
 /* Read random out of the pool.  This function is the core of the
    public random functions.  Note that Level GCRY_WEAK_RANDOM is not
-   anymore handled special and in fact is an alias in teh API for
+   anymore handled special and in fact is an alias in the API for
    level GCRY_STRONG_RANDOM.  Must be called with the pool already
    locked.  */
 static void
@@ -1059,8 +1076,8 @@ read_pool (byte *buffer, size_t length, int level)
   /* 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.  This test here is to detect forks
-     in a multi-threaded process.  It does not work with all trhead
-     implementaions in particualr not with pthreads.  However it is
+     in a multi-threaded process.  It does not work with all thread
+     implementations in particular not with pthreads.  However it is
      good enough for GNU Pth. */
   if ( getpid () != my_pid2 )
     {
@@ -1091,8 +1108,16 @@ add_randomness (const void *buffer, size_t length, enum random_origins origin)
       rndpool[pool_writepos++] ^= *p++;
       if (pool_writepos >= POOLSIZE )
         {
-          if (origin >= RANDOM_ORIGIN_SLOWPOLL)
-            pool_filled = 1;
+          /* It is possible that we are invoked before the pool is
+             filled using an unreliable origin of entropy, for example
+             the fast random poll.  To avoid flagging the pool as
+             filled in this case, we track the initial filling state
+             separately.  See also the remarks about the seed file. */
+          if (origin >= RANDOM_ORIGIN_SLOWPOLL && !pool_filled)
+            {
+              if (++pool_filled_counter >= POOLSIZE)
+                pool_filled = 1;
+            }
           pool_writepos = 0;
           mix_pool(rndpool); rndstats.mixrnd++;
           just_mixed = !length;
index 4258dfd..c475aac 100644 (file)
@@ -570,14 +570,29 @@ FIXME: what about initialization time?
 This command specifies the file, which is to be used as seed file for
 the PRNG.  If the seed file is registered prior to initialization of the
 PRNG, the seed file's content (if it exists and seems to be valid) is
-feed into the PRNG pool.  After the seed file has been registered, the
+fed into the PRNG pool.  After the seed file has been registered, the
 PRNG can be signalled to write out the PRNG pool's content into the seed
 file with the following command.
 
+
 @item GCRYCTL_UPDATE_RANDOM_SEED_FILE; Arguments: none
 
 Write out the PRNG pool's content into the registered seed file.
 
+Multiple instances of the applications sharing the same random seed file
+can be started in parallel, in which case they will read out the same
+pool and then race for updating it (the last update overwrites earlier
+updates).  They will differentiate only by the weak entropy that is
+added in read_seed_file based on the PID and clock, and up to 16 bytes
+of weak random non-blockingly.  The consequence is that the output of
+these different instances is correlated to some extent.  In the perfect
+scenario, the attacker can control (or at least guess) the PID and clock
+of the application, and drain the system's entropy pool to reduce the
+"up to 16 bytes" above to 0.  Then the dependencies of the inital states
+of the pools are completely known.  Note that this is not an issue if
+random of @code{GCRY_VERY_STRONG_RANDOM} quality is requested as in this
+case enough extra entropy gets mixed.
+
 @item GCRYCTL_SET_VERBOSITY
 
 
@@ -1241,6 +1256,12 @@ future use.
 @item GCRY_CIPHER_SEED
 A 128 bit cipher as described by RFC4269.
 
+@item  GCRY_CIPHER_CAMELLIA128
+@itemx GCRY_CIPHER_CAMELLIA192
+@itemx GCRY_CIPHER_CAMELLIA256
+The Camellia cipher by NTT.  See
+@uref{http://info.isl.ntt.co.jp/@/crypt/@/eng/@/camellia/@/specifications.html}.
+
 @end table
 
 @node Cipher modules
index 6f03104..2494c18 100644 (file)
@@ -32,6 +32,7 @@
 
 static int verbose;  /* Verbose mode.  */
 static int decimal;  /* Print addresses in decimal.  */
+static int assume_hex;  /* Assume input is hexencoded.  */
 
 static void
 print_version (int with_help)
@@ -49,6 +50,8 @@ print_version (int with_help)
            "Usage: " PGM " [OPTIONS] [file]\n"
            "Debug tool for S-expressions\n"
            "\n"
+           "  --decimal     Print offsetc using decimal notation\n"
+           "  --assume-hex  Assume input is a hex dump\n"
            "  --verbose     Show what we are doing\n"
            "  --version     Print version of the program and exit\n"
            "  --help        Display this help and exit\n"
@@ -66,13 +69,16 @@ print_usage (void)
 }
 
 
-#define digit_p(a)   ((a) >= '0' && (a) <= '9')
+#define space_p(a)    ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
+#define digit_p(a)    ((a) >= '0' && (a) <= '9')
 #define octdigit_p(a) ((a) >= '0' && (a) <= '7')
 #define alpha_p(a)    (   ((a) >= 'A' && (a) <= 'Z')  \
                        || ((a) >= 'a' && (a) <= 'z'))
 #define hexdigit_p(a) (digit_p (a)                     \
                        || ((a) >= 'A' && (a) <= 'F')  \
                        || ((a) >= 'a' && (a) <= 'f'))
+#define xtoi_1(a)     ((a) <= '9'? ((a)- '0'): \
+                       (a) <= 'F'? ((a)-'A'+10):((a)-'a'+10))
 
 
 /* Return true if P points to a byte containing a whitespace according
@@ -109,6 +115,46 @@ static int nbytesprinted;
 /* The file offset of the current data buffer .  */
 static unsigned long databufferoffset;
 
+
+
+static int
+my_getc (FILE *fp)
+{
+  int c1, c2;
+
+  if (!assume_hex)
+    return getc (fp);
+
+  while ( (c1=getc (fp)) != EOF && space_p (c1) )
+    ;
+  if (c1 == EOF)
+    return EOF;
+
+  if (!hexdigit_p (c1))
+    {
+      logit ("non hex-digit encountered\n");
+      return EOF;
+    }
+
+  while ( (c2=getc (fp)) != EOF && space_p (c2) )
+    ;
+  if (c2 == EOF)
+    {
+      logit ("error reading second hex nibble\n");
+      return EOF;
+    }
+  if (!hexdigit_p (c2))
+    {
+      logit ("second hex nibble is not a hex-digit\n");
+      return EOF;
+    }
+  return xtoi_1 (c1) * 16 + xtoi_1 (c2);
+}
+
+
+
+
+
 /* Flush the raw data buffer.  */
 static void
 flushdatabuffer (void)
@@ -229,6 +275,8 @@ printhex (int c)
 
 
 
+
+
 static int
 parse_and_print (FILE *fp)
 {
@@ -253,7 +301,7 @@ parse_and_print (FILE *fp)
   state = INIT_STATE;
   
 
-  while ((c = getc (fp)) != EOF )
+  while ((c = my_getc (fp)) != EOF )
     {
       addrawdata (c);
       switch (state)
@@ -527,6 +575,11 @@ main (int argc, char **argv)
           argc--; argv++;
           decimal = 1;
         }
+      else if (!strcmp (*argv, "--assume-hex"))
+        {
+          argc--; argv++;
+          assume_hex = 1;
+        }
       else
         print_usage ();
     }