diff --git a/_test/tests/inc/auth_random.test.php b/_test/tests/inc/auth_random.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..f380eba537fec7fc1c00e4b9aec8e056e791e0c8
--- /dev/null
+++ b/_test/tests/inc/auth_random.test.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * Tests the random generator functions
+ */
+class auth_random_test extends DokuWikiTest {
+    function testRandomRange() {
+        $rand = auth_random(300, 2000);
+        $this->assertTrue($rand <= 2000, 'The generated number was above the limit');
+        $this->assertTrue($rand >= 300, 'The generate number was too low');
+    }
+
+    function testLargeRandoms() {
+        $min = (1 << 30);
+        $max = $min + (1 << 33) + 17;
+        $rand = auth_random($min, $max);
+        $this->assertTrue($rand >= $min, 'The generated number was too low');
+        $this->assertTrue($rand <= $max, 'The generated number was too high');
+    }
+}
diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php
index 61bd74939f8eb4e48f29ce82f25030f3afdab28c..607661a2205c0b00e58a18806850fbf2473aeb85 100644
--- a/inc/PassHash.class.php
+++ b/inc/PassHash.class.php
@@ -98,7 +98,7 @@ class PassHash {
         $salt  = '';
         $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
         for($i = 0; $i < $len; $i++) {
-            $salt .= $chars[mt_rand(0, 61)];
+            $salt .= $chars[auth_random(0, 61)];
         }
         return $salt;
     }
diff --git a/inc/auth.php b/inc/auth.php
index 47b29eff77885662158390c116b2cc943e97a7df..e840ef6d752f5aa01dfbe9ab1f8b54b172ae96a9 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -294,7 +294,7 @@ function auth_validateToken($token) {
  * @return string The auth token
  */
 function auth_createToken() {
-    $token = md5(mt_rand());
+    $token = md5(auth_randombytes(16));
     @session_start(); // reopen the session if needed
     $_SESSION[DOKU_COOKIE]['auth']['token'] = $token;
     session_write_close();
@@ -349,6 +349,102 @@ function auth_cookiesalt($addsession = false) {
     return $salt;
 }
 
+/**
+ * Return truly (pseudo) random bytes if available, otherwise fall back to mt_rand
+ *
+ * @author Mark Seecof
+ * @author Michael Hamann <michael@content-space.de>
+ * @link   http://www.php.net/manual/de/function.mt-rand.php#83655
+ * @param int $length number of bytes to get
+ * @throws Exception when no usable random generator is found
+ * @return string binary random strings
+ */
+function auth_randombytes($length) {
+    $strong = false;
+    $rbytes = false;
+
+    if (function_exists('openssl_random_pseudo_bytes')
+        && (version_compare(PHP_VERSION, '5.3.4') >= 0
+            || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
+    ) {
+        $rbytes = openssl_random_pseudo_bytes($length, $strong);
+    }
+
+    if (!$strong && function_exists('mcrypt_create_iv')
+        && (version_compare(PHP_VERSION, '5.3.7') >= 0
+            || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
+    ) {
+        $rbytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
+        if ($rbytes !== false && strlen($rbytes) === $length) {
+            $strong = true;
+        }
+    }
+
+
+    // If no strong randoms available, try OS the specific ways
+    if(!$strong) {
+        // Unix/Linux platform
+        $fp = @fopen('/dev/urandom', 'rb');
+        if($fp !== false) {
+            $rbytes = fread($fp, $length);
+            fclose($fp);
+        }
+
+        // MS-Windows platform
+        if(class_exists('COM')) {
+            // http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
+            try {
+                $CAPI_Util = new COM('CAPICOM.Utilities.1');
+                $rbytes    = $CAPI_Util->GetRandom($length, 0);
+
+                // if we ask for binary data PHP munges it, so we
+                // request base64 return value.
+                if($rbytes) $rbytes = base64_decode($rbytes);
+            } catch(Exception $ex) {
+                // fail
+            }
+        }
+    }
+    if(strlen($rbytes) < $length) $rbytes = false;
+
+    // still no random bytes available - fall back to mt_rand()
+    if($rbytes === false) {
+        $rbytes = '';
+        for ($i = 0; $i < $length; ++$i) {
+            $rbytes .= chr(mt_rand(0, 255));
+        }
+    }
+
+    return $rbytes;
+}
+
+/**
+ * Random number generator using the best available source
+ *
+ * @author Michael Samuel
+ * @author Michael Hamann <michael@content-space.de>
+ * @param int $min
+ * @param int $max
+ * @return int
+ */
+function auth_random($min, $max) {
+    $abs_max = $max - $min;
+
+    $nbits = 0;
+    for ($n = $abs_max; $n > 0; $n >>= 1) {
+        ++$nbits;
+    }
+
+    $mask = (1 << $nbits) - 1;
+    do {
+        $bytes    = auth_randombytes(PHP_INT_SIZE);
+        $integers = unpack('Inum', $bytes);
+        $integer  = $integers["num"] & $mask;
+    } while ($integer > $abs_max);
+
+    return $min + $integer;
+}
+
 /**
  * Log out the current user
  *
@@ -703,12 +799,12 @@ function auth_pwgen($foruser = '') {
 
         //use thre syllables...
         for($i = 0; $i < 3; $i++) {
-            $data['password'] .= $c[mt_rand(0, strlen($c) - 1)];
-            $data['password'] .= $v[mt_rand(0, strlen($v) - 1)];
-            $data['password'] .= $a[mt_rand(0, strlen($a) - 1)];
+            $data['password'] .= $c[auth_random(0, strlen($c) - 1)];
+            $data['password'] .= $v[auth_random(0, strlen($v) - 1)];
+            $data['password'] .= $a[auth_random(0, strlen($a) - 1)];
         }
         //... and add a nice number and special
-        $data['password'] .= mt_rand(10, 99).$s[mt_rand(0, strlen($s) - 1)];
+        $data['password'] .= auth_random(10, 99).$s[auth_random(0, strlen($s) - 1)];
     }
     $evt->advise_after();
 
@@ -1007,7 +1103,7 @@ function act_resendpwd() {
         }
 
         // generate auth token
-        $token = md5(uniqid(mt_rand(), true)); // random secret
+        $token = md5(auth_randombytes(16)); // random secret
         $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth';
         $url   = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&');