Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Commit

Permalink
Merge pull request zendframework/zendframework#1 from wryck7/ZendHydr…
Browse files Browse the repository at this point in the history
…ator

CS fixes
  • Loading branch information
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 22 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
},
"extra": {
"branch-alias": {
"dev-master": "2.4-dev",
"dev-develop": "2.5-dev"
"dev-master": "2.1-dev",
"dev-develop": "2.2-dev"
}
},
"autoload-dev": {
Expand Down
77 changes: 57 additions & 20 deletions src/Rand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@

namespace Zend\Math;

use RandomLib;

/**
* Pseudorandom number generator (PRNG)
*/
abstract class Rand
{

/**
* Alternative random byte generator using RandomLib
*
* @var RandomLib\Generator
*/
protected static $generator = null;

/**
* Generate random bytes using OpenSSL or Mcrypt and mt_rand() as fallback
*
Expand All @@ -27,34 +37,61 @@ public static function getBytes($length, $strong = false)
if ($length <= 0) {
return false;
}
if (extension_loaded('openssl')) {
$rand = openssl_random_pseudo_bytes($length, $secure);
if ($secure === true) {
return $rand;
$bytes = '';
if (function_exists('openssl_random_pseudo_bytes')
&& (version_compare(PHP_VERSION, '5.3.4') >= 0
|| strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
) {
$bytes = openssl_random_pseudo_bytes($length, $usable);
if (true === $usable) {
return $bytes;
}
}
if (extension_loaded('mcrypt')) {
// PHP bug #55169
// @see https://bugs.php.net/bug.php?id=55169
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' ||
version_compare(PHP_VERSION, '5.3.7') >= 0) {
$rand = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
if ($rand !== false && strlen($rand) === $length) {
return $rand;
}
if (function_exists('mcrypt_create_iv')
&& (version_compare(PHP_VERSION, '5.3.7') >= 0
|| strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
) {
$bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
if ($bytes !== false && strlen($bytes) === $length) {
return $bytes;
}
}
if ($strong) {
throw new Exception\RuntimeException(
$checkAlternatives = (file_exists('/dev/urandom') && is_readable('/dev/urandom'))
|| class_exists('\\COM', false);
if (true === $strong && false === $checkAlternatives) {
throw new Exception\RuntimeException (
'This PHP environment doesn\'t support secure random number generation. ' .
'Please consider to install the OpenSSL and/or Mcrypt extensions'
'Please consider installing the OpenSSL and/or Mcrypt extensions'
);
}
$rand = '';
for ($i = 0; $i < $length; $i++) {
$rand .= chr(mt_rand(0, 255));
$generator = self::getAlternativeGenerator();
return $generator->generate($length);
}

/**
* Retrieve a fallback/alternative RNG generator
*
* @return RandomLib\Generator
*/
public static function getAlternativeGenerator()
{
if (!is_null(self::$generator)) {
return self::$generator;
}
if (!class_exists('RandomLib\\Factory')) {
throw new Exception\RuntimeException(
'The RandomLib fallback pseudorandom number generator (PRNG) '
. ' must be installed in the absence of the OpenSSL and '
. 'Mcrypt extensions'
);
}
return $rand;
$factory = new RandomLib\Factory;
$factory->registerSource(
'HashTiming',
'Zend\Math\Source\HashTiming'
);
self::$generator = $factory->getMediumStrengthGenerator();
return self::$generator;
}

/**
Expand Down
114 changes: 114 additions & 0 deletions src/Source/HashTiming.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Math\Source;

use RandomLib;
use SecurityLib\Strength;

/**
* Author:
* George Argyros <argyros.george@gmail.com>
*
* Copyright (c) 2012, George Argyros
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL GEORGE ARGYROS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*
* The function is providing, at least at the systems tested :),
* $len bytes of entropy under any PHP installation or operating system.
* The execution time should be at most 10-20 ms in any system.
*
* Modified by Padraic Brady as part of Zend Framework to use 25% of the
* original version's iterations.
*/
class HashTiming implements RandomLib\Source
{

/**
* Return an instance of Strength indicating the strength of the source
*
* @return Strength An instance of one of the strength classes
*/
public static function getStrength()
{
return new Strength(Strength::VERYLOW);
}

/**
* Generate a random string of the specified size
*
* @param int $size The size of the requested random string
*
* @return string A string of the requested size
*/
public function generate($size)
{
$result = '';
$entropy = '';
$msec_per_round = 400;
$bits_per_round = 2;
$total = $size;
$bytes = 0;
$hash_length = 20;
$rounds = 0;
while (strlen($result) < $size) {
$bytes = ($total > $hash_length)? $hash_length : $total;
$total -= $bytes;
for ($i=1; $i < 3; $i++) {
$t1 = microtime(true);
$seed = mt_rand();
for ($j=1; $j < 50; $j++) {
$seed = sha1($seed);
}
$t2 = microtime(true);
$entropy .= $t1 . $t2;
}
$div = (int) (($t2 - $t1) * 1000000);
if ($div <= 0) {
$div = 400;
}
$rounds = (int) ($msec_per_round * 50 / $div);
$iter = $bytes * (int) (ceil(8 / $bits_per_round));
for ($i = 0; $i < $iter; $i ++) {
$t1 = microtime();
$seed = sha1(mt_rand());
for ($j = 0; $j < $rounds; $j++) {
$seed = sha1($seed);
}
$t2 = microtime();
$entropy .= $t1 . $t2;
}
$result .= sha1($entropy, true);
}
return substr($result, 0, $size);
}

}
25 changes: 25 additions & 0 deletions test/RandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

namespace ZendTest\Math;

use Zend\Math;
use Zend\Math\Rand;
use RandomLib;

/**
* @category Zend
Expand Down Expand Up @@ -127,4 +129,27 @@ public function testGetStringBase64()
$this->assertTrue(preg_match('#^[0-9a-zA-Z+/]+$#', $rand) === 1);
}
}

public function testHashTimingSourceStrengthIsVeryLow()
{
$this->assertEquals(1, (string) Math\Source\HashTiming::getStrength());
}

public function testHashTimingSourceStrengthIsRandomWithCorrectLength()
{
$source = new Math\Source\HashTiming;
$rand = $source->generate(32);
$this->assertTrue(32 === strlen($rand));
$rand2 = $source->generate(32);
$this->assertNotEquals($rand, $rand2);
}

public function testAltGeneratorIsRandomWithCorrectLength()
{
$source = Math\Rand::getAlternativeGenerator();
$rand = $source->generate(32);
$this->assertTrue(32 === strlen($rand));
$rand2 = $source->generate(32);
$this->assertNotEquals($rand, $rand2);
}
}

0 comments on commit 9174cc0

Please sign in to comment.