Skip to content

Commit

Permalink
Added entropy sources + unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
ezimuel committed Mar 7, 2013
1 parent 8aba60f commit c6db24e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 37 deletions.
16 changes: 16 additions & 0 deletions demo.php
@@ -0,0 +1,16 @@
<?php
/**
* Demo of usage secyre_random_bytes() function
*
*/
require_once 'srand.php';

$c1 = microtime(true);
if (isset($_GET['l'])) {
$t = secure_random_bytes($_GET['l']);
} else {
$t = secure_random_bytes();
}
$c2 = microtime(true);

echo "Token: $t<br>Execution time: " . (int)(($c2-$c1)*1000000);
66 changes: 29 additions & 37 deletions srand.php
Expand Up @@ -48,24 +48,26 @@ function secure_random_bytes($len = 10)
substr(PHP_OS, 0, 3) !== 'WIN'))
{
$SSLstr = openssl_random_pseudo_bytes($len, $strong);
if ($strong)
if ($strong) {
return $SSLstr;
}
}

/*
* If mcrypt extension is available then we use it to gather entropy from
* the operating system's PRNG. This is better than reading /dev/urandom
* directly since it avoids reading larger blocks of data than needed.
* Older versions of mcrypt_create_iv may be broken or take too much time
* to finish so we only use this function with PHP 5.3 and above.
* to finish so we only use this function with PHP 5.3.7 and above.
* @see https://bugs.php.net/bug.php?id=55169
*/
if (function_exists('mcrypt_create_iv') &&
(version_compare(PHP_VERSION, '5.3.0') >= 0 ||
substr(PHP_OS, 0, 3) !== 'WIN'))
{
(version_compare(PHP_VERSION, '5.3.7') >= 0 ||
substr(PHP_OS, 0, 3) !== 'WIN')) {
$str = mcrypt_create_iv($len, MCRYPT_DEV_URANDOM);
if ($str !== false)
if ($str !== false) {
return $str;
}
}


Expand All @@ -83,9 +85,10 @@ function secure_random_bytes($len = 10)
$total = $len; // total bytes of entropy to collect

$handle = @fopen('/dev/urandom', 'rb');
if ($handle && function_exists('stream_set_read_buffer'))
if ($handle && function_exists('stream_set_read_buffer')) {
@stream_set_read_buffer($handle, 0);

}

do
{
$bytes = ($total > $hash_len)? $hash_len : $total;
Expand All @@ -94,20 +97,23 @@ function secure_random_bytes($len = 10)
//collect any entropy available from the PHP system and filesystem
$entropy = rand() . uniqid(mt_rand(), true) . $SSLstr;
$entropy .= implode('', @fstat(@fopen( __FILE__, 'r')));
$entropy .= memory_get_usage();
if ($handle)
{
$entropy .= @fread($handle, $bytes);
$entropy .= memory_get_usage() . getmypid();
$entropy .= serialize($_ENV) . serialize($_SERVER);
if (function_exists('posix_times')) {
$entropy .= serialize(posix_times());
}
if (function_exists('zend_thread_id')) {
$entropy .= zend_thread_id();
}
else
{
if ($handle) {
$entropy .= @fread($handle, $bytes);
} else {
// Measure the time that the operations will take on average
for ($i = 0; $i < 3; $i ++)
for ($i = 0; $i < 3; $i++)
{
$c1 = microtime(true);
$var = sha1(mt_rand());
for ($j = 0; $j < 50; $j++)
{
for ($j = 0; $j < 50; $j++) {
$var = sha1($var);
}
$c2 = microtime(true);
Expand All @@ -116,17 +122,15 @@ function secure_random_bytes($len = 10)

// Based on the above measurement determine the total rounds
// in order to bound the total running time.
$rounds = (int)($msec_per_round*50 / (int)(($c2-$c1)*1000000));
$rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000));

// Take the additional measurements. On average we can expect
// at least $bits_per_round bits of entropy from each measurement.
$iter = $bytes*(int)(ceil(8 / $bits_per_round));
for ($i = 0; $i < $iter; $i ++)
{
$iter = $bytes * (int) (ceil(8 / $bits_per_round));
for ($i = 0; $i < $iter; $i++) {
$c1 = microtime();
$var = sha1(mt_rand());
for ($j = 0; $j < $rounds; $j++)
{
for ($j = 0; $j < $rounds; $j++) {
$var = sha1($var);
}
$c2 = microtime();
Expand All @@ -138,20 +142,8 @@ function secure_random_bytes($len = 10)
$str .= sha1($entropy, true);
} while ($len > strlen($str));

if ($handle)
if ($handle) {
@fclose($handle);

}
return substr($str, 0, $len);
}


$c1 = microtime(true);
if (isset($_GET['l']))
$t = secure_random_bytes($_GET['l']);
else
$t = secure_random_bytes();
$c2 = microtime(true);

echo "Token: $t<br>Execution time: " . (int)(($c2-$c1)*1000000);
?>

19 changes: 19 additions & 0 deletions tests/SrandTest.php
@@ -0,0 +1,19 @@
<?php
namespace SrandTest;

require_once '../srand.php';

class SrandTest extends \PHPUnit_Framework_TestCase
{

public function testRandBytes()
{
for ($length = 1; $length < 4096; $length++) {
$rand = secure_random_bytes($length);
$this->assertTrue($rand !== false);
$this->assertEquals($length, strlen($rand));
}
}

}

0 comments on commit c6db24e

Please sign in to comment.