$OpenBSD: patch-kdecore_util_krandom_cpp,v 1.1 2013/12/08 19:13:32 zhuk Exp $
More correct implementation of random() & Co., using arc4random().
--- kdecore/util/krandom.cpp.orig	Fri Jun 28 21:03:40 2013
+++ kdecore/util/krandom.cpp	Wed Oct 16 21:59:22 2013
@@ -19,18 +19,36 @@
     Boston, MA 02110-1301, USA.
         */
 
-#include "krandom.h"
+#include <config.h>
+#include <config-util.h>
 
+#include <sys/types.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <time.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <kde_file.h>
 
+#if HAVE_ARC4RANDOM
+# include <limits.h>
+#else
+# include <unistd.h>
+# include <stdio.h>
+# include <time.h>
+# include <sys/time.h>
+# include <fcntl.h>
+# include <kde_file.h>
+#endif
+
+#include "krandom.h"
+
 int KRandom::random()
 {
+#if HAVE_ARC4RANDOM_UNIFORM
+   // Even given that urandom provides the same source on OpenBSD as
+   // arc4random(), we avoid race and extra opening a file descriptor here.
+   return arc4random_uniform(RAND_MAX);
+#elif HAVE_ARC4RANDOM
+   // RAND_MAX+1 is usually (always?) a power of two, so this should be
+   // uniformly distributed. Well, not worse than the variant below.
+   return arc4random() % ((uint32_t)(RAND_MAX) + 1);
+#else
    static bool init = false;
    if (!init)
    {
@@ -47,17 +65,72 @@ int KRandom::random()
       srand(seed);
    }
    return rand();
+#endif
 }
 
+uint32_t KRandom::random32()
+{
+#if HAVE_ARC4RANDOM
+   // Even given that urandom provides the same source on OpenBSD,
+   // we avoid race and extra opening a file descriptor here.
+   return arc4random();
+#else
+   uint32_t result = 0;
+   unsigned long long maxResult = 1;
+   do {
+      result *= (RAND_MAX + 1);
+      result |= KRandom::random();
+      maxResult *= (RAND_MAX + 1);
+   } while (maxResult < UINT_MAX);
+   return result;
+#endif
+}
+
+uint32_t KRandom::uniform(uint32_t upperBound)
+{
+#if HAVE_ARC4RANDOM_UNIFORM
+   return arc4random_uniform(upperBound);
+#else
+   // The problem with classical "int n = random() % upperBound"
+   // approach is that when upper bound is not a power of two,
+   // and thus the value returned by random(), if divided by upperBound,
+   // results in non-zero reminder, we won't get uniformly distributed
+   // numbers. This is well described in the arc4random_uniform(3).
+   //
+   // Algorithm as follows:
+   //   1. Calculate the "ignoreIf" delta between upperBound and
+   //      minimal (power of two minus one) that fits in this range.
+   uint32_t mask = 1;
+   while (mask < upperBound) {
+      mask <<= 1;
+      mask |= 1;
+   }
+   uint32_t ignoreIf = mask - upperBound;
+
+   // 2. Continously try getting random value until it satisfy the
+   //    requirement: 0 <= value <= (UINT32_MAX - ignoreIf).
+   //    This way we make sure that we don't use numbers from
+   //    the problematic range.
+   uint32_t r;
+   do {
+      r = KRandom::random32();
+   } while (r > UINT32_MAX - ignoreIf);
+
+   // 3. Get a reminder of division on upperBound, now that we're safe.
+   return (r % upperBound);
+#endif
+}
+
 QString KRandom::randomString(int length)
 {
    if (length <=0 ) return QString();
 
    QString str; str.resize( length );
+
    int i = 0;
    while (length--)
    {
-      int r=random() % 62;
+      int r=(int)uniform(62);
       r+=48;
       if (r>57) r+=7;
       if (r>90) r+=6;
