OSSP CVS Repository

ossp - Check-in [5117]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 5117
Date: 2005-Aug-30 17:26:07 (local)
2005-Aug-30 15:26:07 (UTC)
User:rse
Branch:
Comment: Improve the PRNG in case no stronger system PRNG device is available by passing time and rand(3) based entropy into the MD5 one-way hash function to achieve at least some sort of weaker PRN data.
Tickets:
#64 Repeats uuids on fast machines
Inspections:
Files:
ossp-pkg/uuid/ChangeLog      1.75 -> 1.76     5 inserted, 0 deleted
ossp-pkg/uuid/uuid_prng.c      1.5 -> 1.6     53 inserted, 22 deleted
ossp-pkg/uuid/uuid_prng.h      1.2 -> 1.3     2 inserted, 1 deleted

ossp-pkg/uuid/ChangeLog 1.75 -> 1.76

--- ChangeLog    2005/08/29 20:25:44     1.75
+++ ChangeLog    2005/08/30 15:26:07     1.76
@@ -13,6 +13,11 @@
 
   Changes between 1.2.0 and 1.2.1 (23-Jan-2005 to xx-Mar-2005)
 
+   o Improve the PRNG in case no stronger system PRNG device is
+     available by passing time and rand(3) based entropy into the MD5
+     one-way hash function to achieve at least some sort of weaker PRN data.
+     [Ralf S. Engelschall]
+
    o Fix MAC address determination under Solaris by using the result of
      ioctl(...,SIOCGARP,...) only if arp_flags had ATF_COM set.
      [Ralf S. Engelschall]


ossp-pkg/uuid/uuid_prng.c 1.5 -> 1.6

--- uuid_prng.c  2005/03/29 19:01:41     1.5
+++ uuid_prng.c  2005/08/30 15:26:07     1.6
@@ -35,9 +35,12 @@
 #include <fcntl.h>
 
 #include "uuid_prng.h"
+#include "uuid_md5.h"
 
 struct prng_st {
-    int devfd;
+    int    dev; /* system PRNG device */
+    md5_t *md5; /* local MD5 PRNG engine */
+    long   cnt; /* time resolution compensation counter */
 };
 
 prng_rc_t prng_create(prng_t **prng)
@@ -56,14 +59,21 @@
         return PRNG_RC_MEM;
 
     /* try to open the system PRNG device */
-    (*prng)->devfd = -1;
+    (*prng)->dev = -1;
     if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
         fd = open("/dev/random", O_RDONLY|O_NONBLOCK);
     if (fd != -1) {
         fcntl(fd, F_SETFD, FD_CLOEXEC);
-        (*prng)->devfd = fd;
+        (*prng)->dev = fd;
     }
 
+    /* initialize MD5 engine */
+    if (md5_create(&((*prng)->md5)) != MD5_RC_OK)
+        return PRNG_RC_INT;
+
+    /* initialize time resolution compensation counter */
+    (*prng)->cnt = 0;
+
     /* seed the C library PRNG once */
     gettimeofday(&tv, NULL);
     pid = getpid();
@@ -72,10 +82,7 @@
         ^ (unsigned int)pid
         ^ (unsigned int)tv.tv_sec
         ^ (unsigned int)tv.tv_usec));
-
-    /* crank the PRNG a few times */
-    gettimeofday(&tv, NULL);
-    for (i = (unsigned int)(tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
+    for (i = (unsigned int)((tv.tv_sec ^ tv.tv_usec) & 0x1F); i > 0; i--)
         (void)rand();
 
     return PRNG_RC_OK;
@@ -85,35 +92,59 @@
 {
     size_t n;
     unsigned char *p;
-    int cnt;
+    struct {
+        struct timeval tv;
+        long cnt;
+        int rnd;
+    } entropy;
+    unsigned char md5_buf[MD5_LEN_BIN];
+    unsigned char *md5_ptr;
+    size_t md5_len;
+    int retries;
     int i;
 
     /* sanity check argument(s) */
     if (prng == NULL || data_len == 0)
         return PRNG_RC_ARG;
 
-    /* try to gather data from the system PRNG device */
-    if (prng->devfd != -1) {
-        p = (unsigned char *)data_ptr;
-        n = data_len;
-        cnt = 0;
+    /* prepare for generation */
+    p = (unsigned char *)data_ptr;
+    n = data_len;
+
+    /* approach 1: try to gather data via stronger system PRNG device */
+    if (prng->dev != -1) {
+        retries = 0;
         while (n > 0) {
-            i = read(prng->devfd, (void *)p, n);
+            i = read(prng->dev, (void *)p, n);
             if (i <= 0) {
-                if (cnt++ > 16)
+                if (retries++ > 16)
                     break;
                 continue;
             }
+            retries = 0;
             n -= (unsigned int)i;
             p += (unsigned int)i;
-            cnt = 0;
         }
     }
 
-    /* always also apply the weaker PRNG. In case the stronger PRNG device
-       based source failed, this is the only remaining randomness, of course */
-    for (p = (unsigned char *)data_ptr, n = 0; n < data_len; n++)
-        *p++ ^= (unsigned char)(((unsigned int)rand() >> 7) & 0xFF);
+    /* approach 2: try to gather data via weaker libc PRNG API. */
+    while (n > 0) {
+        /* gather new entropy */
+        gettimeofday(&(entropy.tv), NULL);
+        entropy.cnt = prng->cnt++;
+        entropy.rnd = rand();
+
+        /* pass entropy into MD5 engine */
+        md5_update(prng->md5, (void *)&entropy, sizeof(entropy));
+
+        /* store MD5 engine state as PRN output */
+        md5_ptr = md5_buf;
+        md5_len = sizeof(md5_buf);
+        md5_store(prng->md5, (void *)&md5_ptr, &md5_len);
+        for (i = 0; i < MD5_LEN_BIN && n > 0; i++, n--)
+            *p++ ^= md5_buf[i]; /* intentionally no assignment because arbitrary
+                                   caller buffer content is leveraged, too */
+    }
 
     return PRNG_RC_OK;
 }
@@ -125,8 +156,8 @@
         return PRNG_RC_ARG;
 
     /* close PRNG device */
-    if (prng->devfd != -1)
-        close(prng->devfd);
+    if (prng->dev != -1)
+        close(prng->dev);
 
     /* free object */
     free(prng);


ossp-pkg/uuid/uuid_prng.h 1.2 -> 1.3

--- uuid_prng.h  2004/12/31 19:20:34     1.2
+++ uuid_prng.h  2005/08/30 15:26:07     1.3
@@ -56,7 +56,8 @@
 typedef enum {
     PRNG_RC_OK  = 0,
     PRNG_RC_ARG = 1,
-    PRNG_RC_MEM = 2
+    PRNG_RC_MEM = 2,
+    PRNG_RC_INT = 3
 } prng_rc_t;
 
 extern prng_rc_t prng_create  (prng_t **prng);

CVSTrac 2.0.1