That's it, I've seen questions about this one time too many for
[openssl.git] / crypto / rand / md_rand.c
index 9f8da22917056fee1071edd08f38ab962a0d580f..668da9549997cc9b2586331d05ef4e574b1f8e48 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
+#ifdef MD_RAND_DEBUG
 # ifndef NDEBUG
 #   define NDEBUG
 # endif
@@ -359,7 +359,7 @@ static void ssleay_rand_seed(const void *buf, int num)
        ssleay_rand_add(buf, num, num);
        }
 
-static void ssleay_rand_initialize(void)
+static void ssleay_rand_initialize(void) /* not exported in RAND_METHOD */
        {
        unsigned long l;
 #ifndef GETPID_IS_MEANINGLESS
@@ -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];
@@ -536,6 +571,8 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
        else
                {
                RANDerr(RAND_F_SSLEAY_RAND_BYTES,RAND_R_PRNG_NOT_SEEDED);
+               ERR_add_error_data(1, "You need to read the OpenSSL FAQ, "
+                       "http://www.openssl.org/support/faq.html");
                return(0);
                }
        }
@@ -559,146 +596,15 @@ static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num)
 
 static int ssleay_rand_status(void)
        {
-       if (!initialized)
-               ssleay_rand_initialize();
-       return (entropy >= ENTROPY_NEEDED);
-       }
+       int ret;
 
-#ifdef WINDOWS
-#include <windows.h>
-#include <openssl/rand.h>
-
-int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
-        {
-        double add_entropy=0;
-        SYSTEMTIME t;
-
-        switch (iMsg)
-                {
-        case WM_KEYDOWN:
-                        {
-                        static WPARAM key;
-                        if (key != wParam)
-                                add_entropy = 0.05;
-                        key = wParam;
-                        }
-                        break;
-       case WM_MOUSEMOVE:
-                        {
-                        static int lastx,lasty,lastdx,lastdy;
-                        int x,y,dx,dy;
-
-                        x=LOWORD(lParam);
-                        y=HIWORD(lParam);
-                        dx=lastx-x;
-                        dy=lasty-y;
-                        if (dx != 0 && dy != 0 && dx-lastdx != 0 && dy-lastdy != 0)
-                                entropy += .2;
-                        lastx=x,lasty=y;
-                        lastdx=dx, lastdy=dy;
-                        }
-               break;
-               }
+       CRYPTO_w_lock(CRYPTO_LOCK_RAND);
 
-        GetSystemTime(&t);
-        RAND_add(&iMsg, sizeof(iMsg), add_entropy);
-       RAND_add(&wParam, sizeof(wParam), 0);
-       RAND_add(&lParam, sizeof(lParam), 0);
-        RAND_add(&t, sizeof(t), 0);
+       if (!initialized)
+               ssleay_rand_initialize();
+       ret = entropy >= ENTROPY_NEEDED;
 
-       return (RAND_status());
-       }
+       CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
 
-/*****************************************************************************
- * Initialisation function for the SSL random generator.  Takes the contents
- * of the screen as random seed.
- *
- * Created 960901 by Gertjan van Oosten, gertjan@West.NL, West Consulting B.V.
- *
- * Code adapted from
- * <URL:http://www.microsoft.com/kb/developr/win_dk/q97193.htm>;
- * the original copyright message is:
- *
- *   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
- *
- *   You have a royalty-free right to use, modify, reproduce and
- *   distribute the Sample Files (and/or any modified version) in
- *   any way you find useful, provided that you agree that
- *   Microsoft has no warranty obligations or liability for any
- *   Sample Application Files which are modified.
- */
-/*
- * I have modified the loading of bytes via RAND_seed() mechanism since
- * the original would have been very very CPU intensive since RAND_seed()
- * does an MD5 per 16 bytes of input.  The cost to digest 16 bytes is the same
- * as that to digest 56 bytes.  So under the old system, a screen of
- * 1024*768*256 would have been CPU cost of approximately 49,000 56 byte MD5
- * digests or digesting 2.7 mbytes.  What I have put in place would
- * be 48 16k MD5 digests, or effectively 48*16+48 MD5 bytes or 816 kbytes
- * or about 3.5 times as much.
- * - eric 
- */
-void RAND_screen(void)
-{
-  HDC          hScrDC;         /* screen DC */
-  HDC          hMemDC;         /* memory DC */
-  HBITMAP      hBitmap;        /* handle for our bitmap */
-  HBITMAP      hOldBitmap;     /* handle for previous bitmap */
-  BITMAP       bm;             /* bitmap properties */
-  unsigned int size;           /* size of bitmap */
-  char         *bmbits;        /* contents of bitmap */
-  int          w;              /* screen width */
-  int          h;              /* screen height */
-  int          y;              /* y-coordinate of screen lines to grab */
-  int          n = 16;         /* number of screen lines to grab at a time */
-
-  /* Create a screen DC and a memory DC compatible to screen DC */
-  hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
-  hMemDC = CreateCompatibleDC(hScrDC);
-
-  /* Get screen resolution */
-  w = GetDeviceCaps(hScrDC, HORZRES);
-  h = GetDeviceCaps(hScrDC, VERTRES);
-
-  /* Create a bitmap compatible with the screen DC */
-  hBitmap = CreateCompatibleBitmap(hScrDC, w, n);
-
-  /* Select new bitmap into memory DC */
-  hOldBitmap = SelectObject(hMemDC, hBitmap);
-
-  /* Get bitmap properties */
-  GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
-  size = (unsigned int)bm.bmWidthBytes * bm.bmHeight * bm.bmPlanes;
-
-  bmbits = Malloc(size);
-  if (bmbits) {
-    /* Now go through the whole screen, repeatedly grabbing n lines */
-    for (y = 0; y < h-n; y += n)
-       {
-       unsigned char md[MD_DIGEST_LENGTH];
-
-       /* Bitblt screen DC to memory DC */
-       BitBlt(hMemDC, 0, 0, w, n, hScrDC, 0, y, SRCCOPY);
-
-       /* Copy bitmap bits from memory DC to bmbits */
-       GetBitmapBits(hBitmap, size, bmbits);
-
-       /* Get the MD5 of the bitmap */
-       MD(bmbits,size,md);
-
-       /* Seed the random generator with the MD5 digest */
-       RAND_seed(md, MD_DIGEST_LENGTH);
+       return ret;
        }
-
-    Free(bmbits);
-  }
-
-  /* Select old bitmap back into memory DC */
-  hBitmap = SelectObject(hMemDC, hOldBitmap);
-
-  /* Clean up */
-  DeleteObject(hBitmap);
-  DeleteDC(hMemDC);
-  DeleteDC(hScrDC);
-}
-#endif