* random.c (add_randomness): Xor new data into the pool and not
authorWerner Koch <wk@gnupg.org>
Sun, 10 Feb 2002 21:34:58 +0000 (21:34 +0000)
committerWerner Koch <wk@gnupg.org>
Sun, 10 Feb 2002 21:34:58 +0000 (21:34 +0000)
just copy it.  This avoids any choosen input attacks which are not
serious in our setting because an outsider won't be able to mix
data in and even then we keep going with a PRNG.  Thanks to Stefan
Keller for pointing this out.
* random.c (mix_pool): Carry an extra failsafe_digest buffer
around to make the function more robust.

cipher/ChangeLog
cipher/random.c

index a1971ce..5c17a30 100644 (file)
@@ -1,3 +1,16 @@
+2002-02-10  Werner Koch  <wk@gnupg.org>
+
+       * random.c (mix_pool): Carry an extra failsafe_digest buffer
+       around to make the function more robust.
+
+2002-02-08  Werner Koch  <wk@gnupg.org>
+
+       * random.c (add_randomness): Xor new data into the pool and not
+       just copy it.  This avoids any choosen input attacks which are not
+       serious in our setting because an outsider won't be able to mix
+       data in and even then we keep going with a PRNG.  Thanks to Stefan
+       Keller for pointing this out.
+
 2002-01-04  Werner Koch  <wk@gnupg.org>
 
        * pubkey.c (gcry_pk_genkey): Do not release skey - it is static.
 2002-01-04  Werner Koch  <wk@gnupg.org>
 
        * pubkey.c (gcry_pk_genkey): Do not release skey - it is static.
index 5c48bf6..2ae2fc8 100644 (file)
@@ -55,6 +55,7 @@
 #include "random.h"
 #include "rand-internal.h"
 #include "dynload.h"
 #include "random.h"
 #include "rand-internal.h"
 #include "dynload.h"
+#include "cipher.h" /* only used for the rmd160_hash_buffer() prototype */
 
 
 #ifndef RAND_MAX   /* for SunOS */
 
 
 #ifndef RAND_MAX   /* for SunOS */
@@ -98,6 +99,9 @@ static int did_initial_extra_seeding;
 static char *seed_file_name;
 static int allow_seed_file_update;
 
 static char *seed_file_name;
 static int allow_seed_file_update;
 
+static unsigned char failsafe_digest[DIGESTLEN];
+static int failsafe_digest_valid;
+
 static int secure_alloc;
 static int quick_test;
 static int faked_rng;
 static int secure_alloc;
 static int quick_test;
 static int faked_rng;
@@ -250,8 +254,38 @@ gcry_random_bytes_secure( size_t nbytes, enum gcry_random_level level )
 }
 
 
 }
 
 
-/****************
- * Mix the pool
+/*
+   Mix the pool:
+
+   |........blocks*20byte........|20byte|..44byte..|
+   <..44byte..>           <20byte> 
+        |                    |
+        |                    +------+
+        +---------------------------|----------+
+                                    v          v
+   |........blocks*20byte........|20byte|..44byte..|
+                                 <.....64bytes.....>   
+                                         |
+      +----------------------------------+
+     Hash
+      v
+   |.............................|20byte|..44byte..|
+   <20byte><20byte><..44byte..>
+      |                |
+      |                +---------------------+
+      +-----------------------------+        |
+                                    v        v
+   |.............................|20byte|..44byte..|
+                                 <.....64byte......>
+                                        |
+              +-------------------------+
+             Hash
+              v
+   |.............................|20byte|..44byte..|
+   <20byte><20byte><..44byte..>
+
+   and so on until we did this for all blocks. 
+
  */
 static void
 mix_pool(byte *pool)
  */
 static void
 mix_pool(byte *pool)
@@ -271,6 +305,11 @@ mix_pool(byte *pool)
     memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
     _gcry_rmd160_mixblock( &md, hashbuf);
     memcpy(pool, hashbuf, 20 );
     memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
     _gcry_rmd160_mixblock( &md, hashbuf);
     memcpy(pool, hashbuf, 20 );
+    if (failsafe_digest_valid && (char *)pool == rndpool)
+      {
+        for (i=0; i < 20; i++)
+          pool[i] ^= failsafe_digest[i];
+      }
 
     p = pool;
     for( n=1; n < POOLBLOCKS; n++ ) {
 
     p = pool;
     for( n=1; n < POOLBLOCKS; n++ ) {
@@ -291,7 +330,16 @@ mix_pool(byte *pool)
        _gcry_rmd160_mixblock( &md, hashbuf);
        memcpy(p, hashbuf, 20 );
     }
        _gcry_rmd160_mixblock( &md, hashbuf);
        memcpy(p, hashbuf, 20 );
     }
-    burn_stack (200); /* for the rmd160_mixblock() */
+    /* Hmmm: our hash implementation does only leave small parts (64
+       bytes) of the pool on the stack, so I thnik it ios okay not to
+       require secure memory here.  Before we use this pool, it gets
+       copied to the help buffer anyway. */
+    if ( (char*)pool == rndpool)
+      {
+        _gcry_rmd160_hash_buffer (failsafe_digest, pool, POOLSIZE);
+        failsafe_digest_valid = 1;
+      }
+    burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */
 }
 
 void
 }
 
 void
@@ -539,7 +587,7 @@ add_randomness( const void *buffer, size_t length, int source )
     rndstats.addbytes += length;
     rndstats.naddbytes++;
     while( length-- ) {
     rndstats.addbytes += length;
     rndstats.naddbytes++;
     while( length-- ) {
-       rndpool[pool_writepos++] = *p++;
+       rndpool[pool_writepos++] ^= *p++;
        if( pool_writepos >= POOLSIZE ) {
            if( source > 1 )
                pool_filled = 1;
        if( pool_writepos >= POOLSIZE ) {
            if( source > 1 )
                pool_filled = 1;