DragonFly BSD
DragonFly submit List (threaded) for 2004-05
[Date Prev][Date Next]  [Thread Prev][Thread Next]  [Date Index][Thread Index]

[PATCH] rand.c updates from FreeBSD RELENG_5


From: "William M. Grim" <wgrim@xxxxxxxx>
Date: Wed, 12 May 2004 06:11:21 -0500

Hi.

I know there is the random(3) function, which is much better at randomness than rand(3); however, rand(3) is ISO C, whereas random(3) is not, as far as I know. Plus, many students and others tend to use rand(3) because its taught.

The FreeBSD team has already made some updates to rand.c; so, I did not need to do much to port it to DragonFly in the form of an update that generates some better randomness.

I have included the patch, but to see what I mean about the current rand(3) not being great, try this code (yes, I know, the seeding could have been done better):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int main(void) { int cs, i,r; /*cs == case*/ srand(time(0)); while(1) { cs = rand() % 2; if(cs) printf("O"); else printf("o"); fflush(stdout); } return EXIT_SUCCESS; }

Notice that this code prints "OoOoOoOoOo..." in a very predictable manner. Now, the update doesn't make rand(3) all that more secure, but it's just nice to have it be better than its current state.

Oh, and if you check revision 1.15 of the FreeBSD rand.c code (where I got this), you will notice I removed the '#include "namespace.h"' and '#include "un-namespace.h"' lines. They wrapped around the headers to make them use different functions. This doesn't seem to have any negative effects with the code I have, but it'd be nice if someone who knows more can comment. It'd be easy to just copy those files if need be and re-add the lines.

If this is viable for a commit, I would appreciate it. If not, send it back to me and I'll make the necessary changes.

Thanks again,
Mike
--- rand.c.orig	2004-05-11 01:34:30.000000000 -0500
+++ rand.c	2004-05-12 05:50:54.000000000 -0500
@@ -31,15 +31,18 @@
  * SUCH DAMAGE.
  *
  * Posix rand_r function added May 1999 by Wes Peters <wes@xxxxxxxxxxxx>.
- *
- * $FreeBSD: src/lib/libc/stdlib/rand.c,v 1.2.2.1 2001/03/05 11:33:57 obrien Exp $
- * $DragonFly: src/lib/libc/stdlib/rand.c,v 1.2 2003/06/17 04:26:46 dillon Exp $
- *
- * @(#)rand.c	8.1 (Berkeley) 6/14/93
  */
 
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rand.c	8.1 (Berkeley) 6/14/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+
+#include <sys/time.h>          /* for sranddev() */
 #include <sys/types.h>
+#include <fcntl.h>             /* for sranddev() */
 #include <stdlib.h>
+#include <unistd.h>            /* for sranddev() */
 
 #ifdef TEST
 #include <stdio.h>
@@ -48,7 +51,34 @@
 static int
 do_rand(unsigned long *ctx)
 {
+#ifdef  USE_WEAK_SEEDING
+/*
+ * Historic implementation compatibility.
+ * The random sequences do not vary much with the seed,
+ * even with overflowing.
+ */
 	return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
+#else   /* !USE_WEAK_SEEDING */
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * wihout overflowing 31 bits:
+ *      (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+	long hi, lo, x;
+
+	/* Can't be initialized with 0, so use another value. */
+	if (*ctx == 0)
+		*ctx = 123459876;
+	hi = *ctx / 127773;
+	lo = *ctx % 127773;
+	x = 16807 * lo - 2836 * hi;
+	if (x < 0)
+		x += 0x7fffffff;
+	return ((*ctx = x) % ((u_long)RAND_MAX + 1));
+#endif  /* !USE_WEAK_SEEDING */
 }
 
 
@@ -56,8 +86,10 @@
 rand_r(unsigned int *ctx)
 {
 	u_long val = (u_long) *ctx;
-	*ctx = do_rand(&val);
-	return (int) *ctx;
+	int r = do_rand(&val);
+
+	*ctx = (unsigned int) val;
+	return (r);
 }
 
 
@@ -66,7 +98,7 @@
 int
 rand()
 {
-	return do_rand(&next);
+	return (do_rand(&next));
 }
 
 void
@@ -76,6 +108,37 @@
 	next = seed;
 }
 
+
+/*
+ * sranddev:
+ *
+ * Many programs choose the seed value in a totally predictable manner.
+ * This often causes problems.  We seed the generator using the much more
+ * secure random(4) interface.
+ */
+void
+sranddev()
+{
+	int fd, done;
+
+	done = 0;
+	fd = _open("/dev/random", O_RDONLY, 0);
+	if (fd >= 0) {
+		if (_read(fd, (void *) &next, sizeof(next)) == sizeof(next))
+			done = 1;
+		_close(fd);
+	}
+
+	if (!done) {
+		struct timeval tv;
+		unsigned long junk;
+
+		gettimeofday(&tv, NULL);
+		srand((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ junk);
+	}
+}
+
+
 #ifdef TEST
 
 main()


[Date Prev][Date Next]  [Thread Prev][Thread Next]  [Date Index][Thread Index]