diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index 37dc095f..062bc981 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -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), diff --git a/phpseclib/Math/BigInteger.php b/phpseclib/Math/BigInteger.php index 901421a0..44c7f677 100644 --- a/phpseclib/Math/BigInteger.php +++ b/phpseclib/Math/BigInteger.php @@ -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); diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 8164fb32..c889e6ab 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -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); diff --git a/tests/Unit/Math/BigInteger/TestCase.php b/tests/Unit/Math/BigInteger/TestCase.php index 8226c0b5..668a5378 100644 --- a/tests/Unit/Math/BigInteger/TestCase.php +++ b/tests/Unit/Math/BigInteger/TestCase.php @@ -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()); */