- speed up BigInteger.php

- added support for more public / private key formats (thanks, m4rc!)


git-svn-id: http://phpseclib.svn.sourceforge.net/svnroot/phpseclib/trunk@91 21d32557-59b3-4da0-833f-c5933fad653e
This commit is contained in:
Jim Wigginton 2010-02-26 03:40:26 +00:00
parent d574a6770e
commit 748983a824
3 changed files with 111 additions and 48 deletions

View File

@ -62,7 +62,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMIX Jim Wigginton * @copyright MMIX Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: RSA.php,v 1.10 2010-01-29 06:21:16 terrafrost Exp $ * @version $Id: RSA.php,v 1.11 2010-02-26 03:40:25 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -767,35 +767,80 @@ class Crypt_RSA {
implementation are part of the standard, as well. implementation are part of the standard, as well.
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
if (preg_match('#DEK-Info: DES-EDE3-CBC,(.+)#', $key, $matches)) { if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
$iv = pack('H*', trim($matches[1])); $iv = pack('H*', trim($matches[2]));
$symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
$symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
$ciphertext = base64_decode(preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key)); $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key);
$ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
if ($ciphertext === false) { if ($ciphertext === false) {
return false; $ciphertext = $key;
} }
if (!class_exists('Crypt_TripleDES')) { switch ($matches[1]) {
require_once('Crypt/TripleDES.php'); case 'DES-EDE3-CBC':
if (!class_exists('Crypt_TripleDES')) {
require_once('Crypt/TripleDES.php');
}
$crypto = new Crypt_TripleDES();
break;
case 'DES-CBC':
if (!class_exists('Crypt_DES')) {
require_once('Crypt/DES.php');
}
$crypto = new Crypt_DES();
break;
default:
return false;
} }
$des = new Crypt_TripleDES(); $crypto->setKey($symkey);
$des->setKey($symkey); $crypto->setIV($iv);
$des->setIV($iv); $decoded = $crypto->decrypt($ciphertext);
$key = $des->decrypt($ciphertext);
} else { } else {
$key = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $key)); $decoded = preg_replace('#-.+-|[\r\n]#', '', $key);
$decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
} }
if ($key === false) { if ($decoded !== false) {
$key = $decoded;
}
$components = array();
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false; return false;
} }
$private = false; $tag = ord($this->_string_shift($key));
$components = array(); if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
/* intended for keys for which OpenSSL's asn1parse returns the following:
0:d=0 hl=4 l= 290 cons: SEQUENCE
4:d=1 hl=2 l= 13 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
17:d=2 hl=2 l= 0 prim: NULL
19:d=1 hl=4 l= 271 prim: BIT STRING */
$this->_string_shift($key, $this->_decodeLength($key));
$this->_string_shift($key); // skip over the BIT STRING tag
$this->_decodeLength($key); // skip over the BIT STRING length
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
// unused bits in teh final subsequent octet. The number shall be in the range zero to seven."
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
$this->_string_shift($key);
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord($this->_string_shift($key));
}
if ($tag != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_SEQUENCE
$this->_decodeLength($key); // skip over the length of the above sequence
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
$length = $this->_decodeLength($key); $length = $this->_decodeLength($key);
$temp = $this->_string_shift($key, $length); $temp = $this->_string_shift($key, $length);
if (strlen($temp) != 1 || ord($temp) > 2) { if (strlen($temp) != 1 || ord($temp) > 2) {
@ -806,7 +851,9 @@ class Crypt_RSA {
return $components; return $components;
} }
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$length = $this->_decodeLength($key); $length = $this->_decodeLength($key);
$components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256); $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
$this->_string_shift($key); $this->_string_shift($key);
@ -831,10 +878,14 @@ class Crypt_RSA {
$length = $this->_decodeLength($key); $length = $this->_decodeLength($key);
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256)); $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256));
if (!empty($key)) { if (!empty($key)) {
$key = substr($key, 1); // skip over CRYPT_RSA_ASN1_SEQUENCE if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$this->_decodeLength($key); $this->_decodeLength($key);
while (!empty($key)) { while (!empty($key)) {
$key = substr($key, 1); // skip over CRYPT_RSA_ASN1_SEQUENCE if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
$this->_decodeLength($key); $this->_decodeLength($key);
$key = substr($key, 1); $key = substr($key, 1);
$length = $this->_decodeLength($key); $length = $this->_decodeLength($key);
@ -855,13 +906,25 @@ class Crypt_RSA {
return false; return false;
} }
$components = array(); $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
return $components; extract(unpack('Nlength', $this->_string_shift($key, 4)));
$publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
if ($cleanup && strlen($key)) {
extract(unpack('Nlength', $this->_string_shift($key, 4)));
return array(
'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256),
'publicExponent' => $modulus
);
} else {
return array(
'modulus' => $modulus,
'publicExponent' => $publicExponent
);
}
} }
} }

View File

@ -47,7 +47,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: TripleDES.php,v 1.12 2010-02-09 06:10:26 terrafrost Exp $ * @version $Id: TripleDES.php,v 1.13 2010-02-26 03:40:25 terrafrost Exp $
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -284,7 +284,7 @@ class Crypt_TripleDES {
$key = str_pad($key, 24, chr(0)); $key = str_pad($key, 24, chr(0));
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
// http://php.net/function.mcrypt-encrypt#47973 // http://php.net/function.mcrypt-encrypt#47973
$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
} }
$this->key = $key; $this->key = $key;
switch (true) { switch (true) {
@ -386,7 +386,7 @@ class Crypt_TripleDES {
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
if (!$this->continuousBuffer) { if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
} }
return $ciphertext; return $ciphertext;
@ -477,7 +477,7 @@ class Crypt_TripleDES {
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) { if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
} }
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;

View File

@ -67,7 +67,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVI Jim Wigginton * @copyright MMVI Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: BigInteger.php,v 1.29 2010-02-21 07:45:31 terrafrost Exp $ * @version $Id: BigInteger.php,v 1.30 2010-02-26 03:40:26 terrafrost Exp $
* @link http://pear.php.net/package/Math_BigInteger * @link http://pear.php.net/package/Math_BigInteger
*/ */
@ -860,7 +860,7 @@ class Math_BigInteger {
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum; $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
$temp = floor($sum / 0x4000000); $temp = (int) ($sum / 0x4000000);
$value[$i] = $sum - 0x4000000 * $temp; // eg. a faster alternative to fmod($sum, 0x4000000) $value[$i] = $sum - 0x4000000 * $temp; // eg. a faster alternative to fmod($sum, 0x4000000)
$value[$j] = $temp; $value[$j] = $temp;
@ -996,7 +996,7 @@ class Math_BigInteger {
$carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum; $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
$temp = floor($sum / 0x4000000); $temp = (int) ($sum / 0x4000000);
$x_value[$i] = $sum - 0x4000000 * $temp; $x_value[$i] = $sum - 0x4000000 * $temp;
$x_value[$j] = $temp; $x_value[$j] = $temp;
@ -1144,7 +1144,7 @@ class Math_BigInteger {
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = floor($temp / 0x4000000); $carry = (int) ($temp / 0x4000000);
$product_value[$j] = $temp - 0x4000000 * $carry; $product_value[$j] = $temp - 0x4000000 * $carry;
} }
@ -1157,7 +1157,7 @@ class Math_BigInteger {
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = floor($temp / 0x4000000); $carry = (int) ($temp / 0x4000000);
$product_value[$k] = $temp - 0x4000000 * $carry; $product_value[$k] = $temp - 0x4000000 * $carry;
} }
@ -1245,13 +1245,13 @@ class Math_BigInteger {
$i2 = $i << 1; $i2 = $i << 1;
$temp = $square_value[$i2] + $value[$i] * $value[$i]; $temp = $square_value[$i2] + $value[$i] * $value[$i];
$carry = floor($temp / 0x4000000); $carry = (int) ($temp / 0x4000000);
$square_value[$i2] = $temp - 0x4000000 * $carry; $square_value[$i2] = $temp - 0x4000000 * $carry;
// note how we start from $i+1 instead of 0 as we do in multiplication. // note how we start from $i+1 instead of 0 as we do in multiplication.
for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
$carry = floor($temp / 0x4000000); $carry = (int) ($temp / 0x4000000);
$square_value[$k] = $temp - 0x4000000 * $carry; $square_value[$k] = $temp - 0x4000000 * $carry;
} }
@ -1449,7 +1449,7 @@ class Math_BigInteger {
if ($x_window[0] == $y_window[0]) { if ($x_window[0] == $y_window[0]) {
$quotient_value[$q_index] = 0x3FFFFFF; $quotient_value[$q_index] = 0x3FFFFFF;
} else { } else {
$quotient_value[$q_index] = floor( $quotient_value[$q_index] = (int) (
($x_window[0] * 0x4000000 + $x_window[1]) ($x_window[0] * 0x4000000 + $x_window[1])
/ /
$y_window[0] $y_window[0]
@ -1519,7 +1519,7 @@ class Math_BigInteger {
for ($i = count($dividend) - 1; $i >= 0; --$i) { for ($i = count($dividend) - 1; $i >= 0; --$i) {
$temp = 0x4000000 * $carry + $dividend[$i]; $temp = 0x4000000 * $carry + $dividend[$i];
$result[$i] = floor($temp / $divisor); $result[$i] = (int) ($temp / $divisor);
$carry = $temp - $divisor * $result[$i]; $carry = $temp - $divisor * $result[$i];
} }
@ -2089,7 +2089,7 @@ class Math_BigInteger {
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = floor($temp / 0x4000000); $carry = (int) ($temp / 0x4000000);
$product_value[$j] = $temp - 0x4000000 * $carry; $product_value[$j] = $temp - 0x4000000 * $carry;
} }
@ -2105,7 +2105,7 @@ class Math_BigInteger {
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = floor($temp / 0x4000000); $carry = (int) ($temp / 0x4000000);
$product_value[$k] = $temp - 0x4000000 * $carry; $product_value[$k] = $temp - 0x4000000 * $carry;
} }
@ -2154,7 +2154,7 @@ class Math_BigInteger {
for ($i = 0; $i < $k; ++$i) { for ($i = 0; $i < $k; ++$i) {
$temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = $temp - 0x4000000 * floor($temp / 0x4000000); $temp = $temp - 0x4000000 * ((int) ($temp / 0x4000000));
$temp = $this->_regularMultiply(array($temp), $n); $temp = $this->_regularMultiply(array($temp), $n);
$temp = array_merge($this->_array_repeat(0, $i), $temp); $temp = array_merge($this->_array_repeat(0, $i), $temp);
$result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
@ -2206,9 +2206,9 @@ class Math_BigInteger {
$a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
for ($i = 0; $i < $n; ++$i) { for ($i = 0; $i < $n; ++$i) {
$temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
$temp = $temp - 0x4000000 * floor($temp / 0x4000000); $temp = $temp - 0x4000000 * ((int) ($temp / 0x4000000));
$temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = $temp - 0x4000000 * floor($temp / 0x4000000); $temp = $temp - 0x4000000 * ((int) ($temp / 0x4000000));
$temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
$a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
$a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
@ -3307,7 +3307,7 @@ class Math_BigInteger {
return; return;
} }
$num_digits = floor($shift / 26); $num_digits = (int) ($shift / 26);
$shift %= 26; $shift %= 26;
$shift = 1 << $shift; $shift = 1 << $shift;
@ -3315,7 +3315,7 @@ class Math_BigInteger {
for ($i = 0; $i < count($this->value); ++$i) { for ($i = 0; $i < count($this->value); ++$i) {
$temp = $this->value[$i] * $shift + $carry; $temp = $this->value[$i] * $shift + $carry;
$carry = floor($temp / 0x4000000); $carry = (int) ($temp / 0x4000000);
$this->value[$i] = $temp - $carry * 0x4000000; $this->value[$i] = $temp - $carry * 0x4000000;
} }
@ -3342,7 +3342,7 @@ class Math_BigInteger {
return; return;
} }
$num_digits = floor($shift / 26); $num_digits = (int) ($shift / 26);
$shift %= 26; $shift %= 26;
$carry_shift = 26 - $shift; $carry_shift = 26 - $shift;
$carry_mask = (1 << $shift) - 1; $carry_mask = (1 << $shift) - 1;