BigInteger: add randomRange / randomPrimeRange

...and redo random / randomPrime such that they take the byte size
as the parameter instead of the range.
This commit is contained in:
terrafrost 2016-09-17 19:48:51 -07:00
parent c17a2604a0
commit 8019baee62
4 changed files with 51 additions and 56 deletions

View File

@ -478,9 +478,8 @@ class RSA
} else {
$num_primes = 2;
}
extract(self::_generateMinMax($temp + $bits % $temp));
$finalMax = $max;
extract(self::_generateMinMax($temp));
$regSize = $temp;
$finalSize = $temp + $bits % $temp;
$n = clone self::$one;
if (!empty($partial)) {
@ -515,15 +514,8 @@ class RSA
}
}
if ($i == $num_primes) {
list($min, $temp) = $absoluteMin->divide($n);
if (!$temp->equals(self::$zero)) {
$min = $min->add(self::$one); // ie. ceil()
}
$primes[$i] = BigInteger::randomPrime($min, $finalMax, $timeout);
} else {
$primes[$i] = BigInteger::randomPrime($min, $max, $timeout);
}
$size = $i == $num_primes ? $finalSize : $regSize;
$primes[$i] = BigInteger::randomPrime($size, $timeout);
if ($primes[$i] === false) { // if we've reached the timeout
if (count($primes) > 1) {
@ -1067,32 +1059,6 @@ class RSA
return $key;
}
/**
* Generates the smallest and largest numbers requiring $bits bits
*
* @access private
* @param int $bits
* @return array
*/
static function _generateMinMax($bits)
{
$bytes = $bits >> 3;
$min = str_repeat(chr(0), $bytes);
$max = str_repeat(chr(0xFF), $bytes);
$msb = $bits & 7;
if ($msb) {
$min = chr(1 << ($msb - 1)) . $min;
$max = chr((1 << $msb) - 1) . $max;
} else {
$min[0] = chr(0x80);
}
return array(
'min' => new BigInteger($min, 256),
'max' => new BigInteger($max, 256)
);
}
/**
* Determines the private key format
*
@ -1284,7 +1250,7 @@ class RSA
}
}
$r = BigInteger::random(self::$one, $smallest->subtract(self::$one));
$r = BigInteger::randomRange(self::$one, $smallest->subtract(self::$one));
$m_i = array(
1 => $this->_blind($x, $r, 1),

View File

@ -3010,15 +3010,15 @@ class BigInteger
}
/**
* Generates a random BigInteger
* Generates a random number of a certain size
*
* Byte length is equal to $length. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not.
* Byte length is equal to $size. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not.
*
* @param int $length
* @param int $size
* @return \phpseclib\Math\BigInteger
* @access private
* @access public
*/
static function _random_number_helper($size)
static function random($size)
{
if (class_exists('\phpseclib\Crypt\Random')) {
$random = Random::string($size);
@ -3040,20 +3040,20 @@ class BigInteger
}
/**
* Generate a random number
* Generate a random number between a range
*
* Returns a random number between $min and $max where $min and $max
* can be defined using one of the two methods:
*
* BigInteger::random($min, $max)
* BigInteger::random($max, $min)
* BigInteger::randomRange($min, $max)
* BigInteger::randomRange($max, $min)
*
* @param \phpseclib\Math\BigInteger $arg1
* @param \phpseclib\Math\BigInteger $arg2
* @return \phpseclib\Math\BigInteger
* @access public
*/
static function random(BigInteger $min, BigInteger $max)
static function randomRange(BigInteger $min, BigInteger $max)
{
$compare = $max->compare($min);
@ -3090,7 +3090,7 @@ class BigInteger
http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
*/
$random_max = new static(chr(1) . str_repeat("\0", $size), 256);
$random = static::_random_number_helper($size);
$random = static::random($size);
list($max_multiple) = $random_max->divide($max);
$max_multiple = $max_multiple->multiply($max);
@ -3099,7 +3099,7 @@ class BigInteger
$random = $random->subtract($max_multiple);
$random_max = $random_max->subtract($max_multiple);
$random = $random->bitwise_leftShift(8);
$random = $random->add(self::_random_number_helper(1));
$random = $random->add(self::random(1));
$random_max = $random_max->bitwise_leftShift(8);
list($max_multiple) = $random_max->divide($max);
$max_multiple = $max_multiple->multiply($max);
@ -3110,7 +3110,36 @@ class BigInteger
}
/**
* Generate a random prime number.
* Generates a random prime number of a certain size
*
* Byte length is equal to $size
*
* @param int $size
* @param int $timeout
* @return \phpseclib\Math\BigInteger
* @access public
*/
static function randomPrime($size, $timeout = false)
{
$min = str_repeat(chr(0), $bytes);
$max = str_repeat(chr(0xFF), $bytes);
$msb = $bits & 7;
if ($msb) {
$min = chr(1 << ($msb - 1)) . $min;
$max = chr((1 << $msb) - 1) . $max;
} else {
$min[0] = chr(0x80);
}
return self::randomRangePrime(
new Math_BigInteger($min, 256),
new Math_BigInteger($max, 256),
$timeout
);
}
/**
* Generate a random prime number between a range
*
* If there's not a prime within the given range, false will be returned.
* If more than $timeout seconds have elapsed, give up and return false.
@ -3122,7 +3151,7 @@ class BigInteger
* @access public
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
*/
static function randomPrime(BigInteger $min, BigInteger $max, $timeout = false)
static function randomRangePrime(BigInteger $min, BigInteger $max, $timeout = false)
{
$compare = $max->compare($min);

View File

@ -1515,7 +1515,7 @@ class SSH2
$max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength
$max = $max->subtract($one);
$x = BigInteger::random($one, $max);
$x = BigInteger::randomRange($one, $max);
$e = $g->modPow($x, $prime);
$eBytes = $e->toBytes(true);

View File

@ -273,7 +273,7 @@ abstract class Unit_Math_BigInteger_TestCase extends PhpseclibTestCase
$min = $this->getInstance(0);
$max = $this->getInstance('18446744073709551616');
$rand1 = \phpseclib\Math\BigInteger::random($min, $max);
$rand1 = \phpseclib\Math\BigInteger::randomRange($min, $max);
// technically $rand1 can equal $min but with the $min and $max we've
// chosen it's just not that likely
$this->assertTrue($rand1->compare($min) > 0);
@ -315,8 +315,8 @@ abstract class Unit_Math_BigInteger_TestCase extends PhpseclibTestCase
Code for generation of $alicePrivate and $bobPrivate.
$one = $this->getInstance(1);
$max = $one->bitwise_leftShift(512)->subtract($one);
$alicePrivate = \phpseclib\Math\BigInteger::random($one, $max);
$bobPrivate = \phpseclib\Math\BigInteger::random($one, $max);
$alicePrivate = \phpseclib\Math\BigInteger::randomRange($one, $max);
$bobPrivate = \phpseclib\Math\BigInteger::randomRange($one, $max);
var_dump($alicePrivate->toHex(), $bobPrivate->toHex());
*/