r25660: Add a new interface 'generate_secret_buffer()', to be used when we
authorAndrew Bartlett <abartlet@samba.org>
Mon, 15 Oct 2007 23:27:15 +0000 (01:27 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 21 Dec 2007 04:43:03 +0000 (05:43 +0100)
require top-quality entropy.  We don't want to waste system enropy
generating challenges (which simply need to be unpredictable, not
secret) or when generating UUIDs.

Rework generate_random_buffer() to use /dev/urandom less often, only
to seed the existing RC4 based PRNG.  (With an exception to ensure we
don't waste this setup cost for very small entropy requests).

Perhaps we should be using heimdal's code for this instead?

This should drasticly reduce our entropy use, particularly in the
build farm (automated Samba build on hosts without much other source
of entropy).

Andrew Bartlett
(This used to be commit 6a5630d37191542022f02fae519227b7829ef620)

source4/auth/ntlmssp/ntlmssp_client.c
source4/lib/util/genrand.c
source4/lib/util/util.h

index 61d6f1b25f719d9730a377fb92a374719964690c..bff9fc0b8a7e62627a1ff72bb368be6b676e16e7 100644 (file)
@@ -226,7 +226,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
        if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
                /* Make up a new session key */
                uint8_t client_session_key[16];
-               generate_random_buffer(client_session_key, sizeof(client_session_key));
+               generate_secret_buffer(client_session_key, sizeof(client_session_key));
 
                /* Encrypt the new session key with the old one */
                encrypted_session_key = data_blob_talloc(gensec_ntlmssp_state, 
index 4d976cecf8c22065b3be4680ee9f3d4d74ff262e..31c0fce63326e43c41744dfefb28fcc2cf7129f2 100644 (file)
@@ -33,6 +33,10 @@ static unsigned char hash[258];
 static uint32_t counter;
 
 static bool done_reseed = false;
+static unsigned int bytes_since_reseed = 0;
+
+static int urand_fd = -1;
+
 static void (*reseed_callback)(int *newseed);
 
 /**
@@ -51,6 +55,7 @@ _PUBLIC_ void set_rand_reseed_callback(void (*fn)(int *))
 _PUBLIC_ void set_need_random_reseed(void)
 {
        done_reseed = false;
+       bytes_since_reseed = 0;
 }
 
 static void get_rand_reseed_data(int *reseed_data)
@@ -163,12 +168,16 @@ static int do_reseed(bool use_fd, int fd)
        int reseed_data = 0;
 
        if (use_fd) {
-               if (fd != -1)
-                       return fd;
-
-               fd = open( "/dev/urandom", O_RDONLY,0);
-               if(fd >= 0)
+               if (fd == -1) {
+                       fd = open( "/dev/urandom", O_RDONLY,0);
+               }
+               if (fd != -1
+                   && (read(fd, seed_inbuf, sizeof(seed_inbuf)) == sizeof(seed_inbuf))) {
+                       DEBUG(0, ("do_reseed: need %d\n", sizeof(seed_inbuf)));
+                       call_backtrace();
+                       seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
                        return fd;
+               }
        }
 
        /* Add in some secret file contents */
@@ -205,28 +214,33 @@ static int do_reseed(bool use_fd, int fd)
 
 /**
  Interface to the (hopefully) good crypto random number generator.
+ Will use our internal PRNG if more than 40 bytes of random generation
+ has been requested, otherwise tries to read from /dev/random
 **/
 _PUBLIC_ void generate_random_buffer(uint8_t *out, int len)
 {
-       static int urand_fd = -1;
        unsigned char md4_buf[64];
        unsigned char tmp_buf[16];
        unsigned char *p;
 
        if(!done_reseed) {
-               urand_fd = do_reseed(true, urand_fd);
-               done_reseed = true;
-       }
-
-       if (urand_fd != -1 && len > 0) {
-
-               if (read(urand_fd, out, len) == len)
-                       return; /* len bytes of random data read from urandom. */
+               bytes_since_reseed += len;
+               
+               /* Magic constant to try and avoid reading 40 bytes
+                * and setting up the PRNG if the app only ever wants
+                * a few bytes */
+               if (bytes_since_reseed < 40) {
+                       if (urand_fd == -1) {
+                               urand_fd = open( "/dev/urandom", O_RDONLY,0);
+                       }
+                       DEBUG(0, ("generate_random_buffer: need %d\n", len));
+                       call_backtrace();
+                       if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
+                               return;
+                       }
+               }
 
-               /* Read of urand error, drop back to non urand method. */
-               close(urand_fd);
-               urand_fd = -1;
-               do_reseed(false, -1);
+               urand_fd = do_reseed(true, urand_fd);
                done_reseed = true;
        }
 
@@ -249,6 +263,24 @@ _PUBLIC_ void generate_random_buffer(uint8_t *out, int len)
        }
 }
 
+/**
+ Interface to the (hopefully) good crypto random number generator.
+ Will always use /dev/urandom if available.
+**/
+_PUBLIC_ void generate_secret_buffer(uint8_t *out, int len)
+{
+       if (urand_fd == -1) {
+               urand_fd = open( "/dev/urandom", O_RDONLY,0);
+       }
+       DEBUG(0, ("generate_random_buffer: need %d\n", len));
+       call_backtrace();
+       if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
+               return;
+       }
+       
+       generate_random_buffer(out, len);
+}
+
 /**
   generate a single random uint32_t
 **/
index 42dde70a4477ffaf2906ebd2d565771de0e46cb9..fc9cb1e57a3ac56ce4951757a25a51e48ad58750 100644 (file)
@@ -226,9 +226,17 @@ _PUBLIC_ void set_need_random_reseed(void);
 
 /**
  Interface to the (hopefully) good crypto random number generator.
+ Will use our internal PRNG if more than 40 bytes of random generation
+ has been requested, otherwise tries to read from /dev/random
 **/
 _PUBLIC_ void generate_random_buffer(uint8_t *out, int len);
 
+/**
+ Interface to the (hopefully) good crypto random number generator.
+ Will always use /dev/urandom if available.
+**/
+_PUBLIC_ void generate_secret_buffer(uint8_t *out, int len);
+
 /**
   generate a single random uint32_t
 **/