Improve PRNG robustness.
authorBodo Möller <bodo@openssl.org>
Tue, 30 May 2000 21:44:36 +0000 (21:44 +0000)
committerBodo Möller <bodo@openssl.org>
Tue, 30 May 2000 21:44:36 +0000 (21:44 +0000)
CHANGES
crypto/rand/md_rand.c

diff --git a/CHANGES b/CHANGES
index f50e931..5e9d4dd 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,19 @@
 
  Changes between 0.9.5a and 0.9.6  [xx XXX 2000]
 
+  *) When generating bytes for the first time in md_rand.c, 'stir the pool'
+     by seeding with STATE_SIZE dummy bytes (with zero entropy count).
+     (The PRNG state consists of two parts, the large pool 'state' and 'md',
+     where all of 'md' is used each time the PRNG is used, but 'state'
+     is used only indexed by a cyclic counter. As entropy may not be
+     well distributed from the beginning, 'md' is important as a
+     chaining variable. However, the output function chains only half
+     of 'md', i.e. 80 bits.  ssleay_rand_add, on the other hand, chains
+     all of 'md', and seeding with STATE_SIZE dummy bytes will result
+     in all of 'state' being rewritten, with the new values depending
+     on virtually all of 'md'.  This overcomes the 80 bit limitation.)
+     [Bodo Moeller]
+
   *) In ssl/s2_clnt.c and ssl/s3_clnt.c, call ERR_clear_error() when
      the handshake is continued after ssl_verify_cert_chain();
      otherwise, if SSL_VERIFY_NONE is set, remaining error codes
index da4258c..ebb98ba 100644 (file)
  *
  */
 
-#define ENTROPY_NEEDED 16  /* require 128 bits = 16 bytes of randomness */
+#define ENTROPY_NEEDED 20  /* require 160 bits = 20 bytes of randomness */
 
 #ifndef MD_RAND_DEBUG
 # ifndef NDEBUG
@@ -411,6 +411,7 @@ static void ssleay_rand_initialize(void)
 
 static int ssleay_rand_bytes(unsigned char *buf, int num)
        {
+       static volatile int stirred_pool = 0;
        int i,j,k,st_num,st_idx;
        int ok;
        long md_c[2];
@@ -419,6 +420,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
 #ifndef GETPID_IS_MEANINGLESS
        pid_t curr_pid = getpid();
 #endif
+       int do_stir_pool = 0;
 
 #ifdef PREDICT
        if (rand_predictable)
@@ -455,6 +457,9 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
        if (!initialized)
                ssleay_rand_initialize();
 
+       if (!stirred_pool)
+               do_stir_pool = 1;
+       
        ok = (entropy >= ENTROPY_NEEDED);
        if (!ok)
                {
@@ -464,12 +469,42 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
                 * Once we've had enough initial seeding we don't bother to
                 * adjust the entropy count, though, because we're not ambitious
                 * to provide *information-theoretic* randomness.
+                *
+                * NOTE: This approach fails if the program forks before
+                * we have enough entropy. Entropy should be collected
+                * in a separate input pool and be transferred to the
+                * output pool only when the entropy limit has been reached.
                 */
                entropy -= num;
                if (entropy < 0)
                        entropy = 0;
                }
 
+       if (do_stir_pool)
+               {
+               /* Our output function chains only half of 'md', so we better
+                * make sure that the required entropy gets 'evenly distributed'
+                * through 'state', our randomness pool.  The input function
+                * (ssleay_rand_add) chains all of 'md', which makes it more
+                * suitable for this purpose.
+                */
+
+               int n = STATE_SIZE; /* so that the complete pool gets accessed */
+               while (n > 0)
+                       {
+#if MD_DIGEST_LENGTH > 20
+# error "Please adjust DUMMY_SEED."
+#endif
+#define DUMMY_SEED "...................." /* at least MD_DIGEST_LENGTH */
+                       /* Note that the seed does not matter, it's just that
+                        * ssleay_rand_add expects to have something to hash. */
+                       ssleay_rand_add(DUMMY_SEED, MD_DIGEST_LENGTH, 0.0);
+                       n -= MD_DIGEST_LENGTH;
+                       }
+               if (ok)
+                       stirred_pool = 1;
+               }
+
        st_idx=state_index;
        st_num=state_num;
        md_c[0] = md_count[0];