diff --git a/Crypt/AES.php b/Crypt/AES.php index 832be25..a0cbc7b 100644 --- a/Crypt/AES.php +++ b/Crypt/AES.php @@ -7,6 +7,10 @@ * * PHP versions 4 and 5 * + * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually + * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of + * to save one include_once(). + * * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()} @@ -56,7 +60,7 @@ * @category Crypt * @package Crypt_AES * @author Jim Wigginton - * @copyright MMVIII Jim Wigginton + * @copyright 2008 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -107,20 +111,6 @@ define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - /** * Pure-PHP implementation of AES. * @@ -201,7 +191,7 @@ class Crypt_AES extends Crypt_Rijndael default: $this->key_size = 32; } - $this->_setupEngine(); + $this->_setEngine(); } } } diff --git a/Crypt/Base.php b/Crypt/Base.php index 2248ed4..9f32484 100644 --- a/Crypt/Base.php +++ b/Crypt/Base.php @@ -47,7 +47,7 @@ * @package Crypt_Base * @author Jim Wigginton * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -91,7 +91,6 @@ define('CRYPT_MODE_CFB', 3); define('CRYPT_MODE_OFB', 4); /** * Encrypt / decrypt using streaming mode. - * */ define('CRYPT_MODE_STREAM', 5); /**#@-*/ @@ -99,15 +98,20 @@ define('CRYPT_MODE_STREAM', 5); /**#@+ * @access private * @see Crypt_Base::Crypt_Base() + * @internal These constants are for internal use only */ /** * Base value for the internal implementation $engine switch */ -define('CRYPT_MODE_INTERNAL', 1); +define('CRYPT_ENGINE_INTERNAL', 1); /** * Base value for the mcrypt implementation $engine switch */ -define('CRYPT_MODE_MCRYPT', 2); +define('CRYPT_ENGINE_MCRYPT', 2); +/** + * Base value for the OpenSSL implementation $engine switch + */ +define('CRYPT_ENGINE_OPENSSL', 3); /**#@-*/ /** @@ -271,7 +275,7 @@ class Crypt_Base * Optimizing value while CFB-encrypting * * Only relevant if $continuousBuffer enabled - * and $engine == CRYPT_MODE_MCRYPT + * and $engine == CRYPT_ENGINE_MCRYPT * * It's faster to re-init $enmcrypt if * $buffer bytes > $cfb_init_len than @@ -323,15 +327,11 @@ class Crypt_Base * which will be determined automatically on __construct() * * Currently available $engines are: - * - CRYPT_MODE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) - * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required) - * - * In the pipeline... maybe. But currently not available: - * - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) - * - * If possible, CRYPT_MODE_MCRYPT will be used for each cipher. - * Otherwise CRYPT_MODE_INTERNAL + * - CRYPT_ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) + * - CRYPT_ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) + * - CRYPT_ENGINE_INTERNAL (slower, pure php-engine, no php-extension required) * + * @see Crypt_Base::_setEngine() * @see Crypt_Base::encrypt() * @see Crypt_Base::decrypt() * @var Integer @@ -339,10 +339,20 @@ class Crypt_Base */ var $engine; + /** + * Holds the preferred crypt engine + * + * @see Crypt_Base::_setEngine() + * @see Crypt_Base::setPreferredEngine() + * @var Integer + * @access private + */ + var $preferredEngine; + /** * The mcrypt specific name of the cipher * - * Only used if $engine == CRYPT_MODE_MCRYPT + * Only used if $engine == CRYPT_ENGINE_MCRYPT * * @link http://www.php.net/mcrypt_module_open * @link http://www.php.net/mcrypt_list_algorithms @@ -352,6 +362,29 @@ class Crypt_Base */ var $cipher_name_mcrypt; + /** + * The openssl specific name of the cipher + * + * Only used if $engine == CRYPT_ENGINE_OPENSSL + * + * @link http://www.php.net/openssl-get-cipher-methods + * @var String + * @access private + */ + var $cipher_name_openssl; + + /** + * The openssl specific name of the cipher in ECB mode + * + * If OpenSSL does not support the mode we're trying to use (CTR) + * it can still be emulated with ECB mode. + * + * @link http://www.php.net/openssl-get-cipher-methods + * @var String + * @access private + */ + var $cipher_name_openssl_ecb; + /** * The default password key_size used by setPassword() * @@ -397,7 +430,7 @@ class Crypt_Base * The name of the performance-optimized callback function * * Used by encrypt() / decrypt() - * only if $engine == CRYPT_MODE_INTERNAL + * only if $engine == CRYPT_ENGINE_INTERNAL * * @see Crypt_Base::encrypt() * @see Crypt_Base::decrypt() @@ -419,6 +452,24 @@ class Crypt_Base */ var $use_inline_crypt; + /** + * If OpenSSL can be used in ECB but not in CTR we can emulate CTR + * + * @see Crypt_Base::_openssl_ctr_process() + * @var Boolean + * @access private + */ + var $openssl_emulate_ctr = false; + + /** + * Determines what options are passed to openssl_encrypt/decrypt + * + * @see Crypt_Base::isValidEngine() + * @var mixed + * @access private + */ + var $openssl_options; + /** * Default Constructor. * @@ -445,37 +496,11 @@ class Crypt_Base */ function Crypt_Base($mode = CRYPT_MODE_CBC) { - $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE'; - - // Determining the availibility of mcrypt support for the cipher - if (!defined($const_crypt_mode)) { - switch (true) { - case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()): - define($const_crypt_mode, CRYPT_MODE_MCRYPT); - break; - default: - define($const_crypt_mode, CRYPT_MODE_INTERNAL); - } - } - - // Determining which internal $engine should be used. - // The fastes possible first. - switch (true) { - case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL - $this->engine = CRYPT_MODE_INTERNAL; - break; - case constant($const_crypt_mode) == CRYPT_MODE_MCRYPT: - $this->engine = CRYPT_MODE_MCRYPT; - break; - default: - $this->engine = CRYPT_MODE_INTERNAL; - } - // $mode dependent settings switch ($mode) { case CRYPT_MODE_ECB: $this->paddable = true; - $this->mode = $mode; + $this->mode = CRYPT_MODE_ECB; break; case CRYPT_MODE_CTR: case CRYPT_MODE_CFB: @@ -489,6 +514,8 @@ class Crypt_Base $this->mode = CRYPT_MODE_CBC; } + $this->_setEngine(); + // Determining whether inline crypting can be used by the cipher if ($this->use_inline_crypt !== false && function_exists('create_function')) { $this->use_inline_crypt = true; @@ -501,10 +528,9 @@ class Crypt_Base * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed * to be all zero's. * - * Note: Could, but not must, extend by the child Crypt_* class - * * @access public * @param String $iv + * @internal Can be overwritten by a sub class, but does not have to be */ function setIV($iv) { @@ -526,15 +552,15 @@ class Crypt_Base * * If the key is not explicitly set, it'll be assumed to be all null bytes. * - * Note: Could, but not must, extend by the child Crypt_* class - * * @access public * @param String $key + * @internal Could, but not must, extend by the child Crypt_* class */ function setKey($key) { $this->key = $key; $this->changed = true; + $this->_setEngine(); } /** @@ -546,13 +572,12 @@ class Crypt_Base * * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php * - * Note: Could, but not must, extend by the child Crypt_* class - * * @see Crypt/Hash.php * @param String $password * @param optional String $method * @return Boolean * @access public + * @internal Could, but not must, extend by the child Crypt_* class */ function setPassword($password, $method = 'pbkdf2') { @@ -645,16 +670,91 @@ class Crypt_Base * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that * length. * - * Note: Could, but not must, extend by the child Crypt_* class - * * @see Crypt_Base::decrypt() * @access public * @param String $plaintext - * @return String $cipertext + * @return String $ciphertext + * @internal Could, but not must, extend by the child Crypt_* class */ function encrypt($plaintext) { - if ($this->engine == CRYPT_MODE_MCRYPT) { + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + if ($this->engine === CRYPT_ENGINE_OPENSSL) { + if ($this->changed) { + $this->_clearBuffers(); + $this->changed = false; + } + switch ($this->mode) { + case CRYPT_MODE_STREAM: + return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options); + case CRYPT_MODE_ECB: + $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options); + return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result; + case CRYPT_MODE_CBC: + $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV); + if ($this->continuousBuffer) { + $this->encryptIV = substr($result, -$this->block_size); + } + return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result; + case CRYPT_MODE_CTR: + return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer); + case CRYPT_MODE_CFB: + // cfb loosely routines inspired by openssl's: + // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} + $ciphertext = ''; + if ($this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$this->enbuffer['pos']; + } else { + $iv = $this->encryptIV; + $pos = 0; + } + $len = strlen($plaintext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $this->block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + $plaintext = substr($plaintext, $i); + } + + $overflow = $len % $this->block_size; + + if ($overflow) { + $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); + $iv = $this->_string_pop($ciphertext, $this->block_size); + + $size = $len - $overflow; + $block = $iv ^ substr($plaintext, -$overflow); + $iv = substr_replace($iv, $block, 0, $overflow); + $ciphertext.= $block; + $pos = $overflow; + } elseif ($len) { + $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); + $iv = substr($ciphertext, -$this->block_size); + } + + return $ciphertext; + case CRYPT_MODE_OFB: + return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer); + } + } + + if ($this->engine === CRYPT_ENGINE_MCRYPT) { if ($this->changed) { $this->_setupMcrypt(); $this->changed = false; @@ -720,10 +820,6 @@ class Crypt_Base return $ciphertext; } - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); if (!$this->continuousBuffer) { @@ -741,9 +837,6 @@ class Crypt_Base $inline = $this->inline_crypt; return $inline('encrypt', $this, $plaintext); } - if ($this->paddable) { - $plaintext = $this->_pad($plaintext); - } $buffer = &$this->enbuffer; $block_size = $this->block_size; @@ -768,26 +861,28 @@ class Crypt_Base break; case CRYPT_MODE_CTR: $xor = $this->encryptIV; - if (strlen($buffer['encrypted'])) { + if (strlen($buffer['ciphertext'])) { for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { $block = substr($plaintext, $i, $block_size); - if (strlen($block) > strlen($buffer['encrypted'])) { - $buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $buffer['ciphertext'].= $this->_encryptBlock($xor); } - $key = $this->_stringShift($buffer['encrypted'], $block_size); + $this->_increment_str($xor); + $key = $this->_string_shift($buffer['ciphertext'], $block_size); $ciphertext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { $block = substr($plaintext, $i, $block_size); - $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $key = $this->_encryptBlock($xor); + $this->_increment_str($xor); $ciphertext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { - $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; } } break; @@ -842,7 +937,7 @@ class Crypt_Base $xor = $this->_encryptBlock($xor); $buffer['xor'].= $xor; } - $key = $this->_stringShift($buffer['xor'], $block_size); + $key = $this->_string_shift($buffer['xor'], $block_size); $ciphertext.= $block ^ $key; } } else { @@ -873,16 +968,101 @@ class Crypt_Base * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until * it is. * - * Note: Could, but not must, extend by the child Crypt_* class - * * @see Crypt_Base::encrypt() * @access public * @param String $ciphertext * @return String $plaintext + * @internal Could, but not must, extend by the child Crypt_* class */ function decrypt($ciphertext) { - if ($this->engine == CRYPT_MODE_MCRYPT) { + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}: + // "The data is padded with "\0" to make sure the length of the data is n * blocksize." + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); + } + + if ($this->engine === CRYPT_ENGINE_OPENSSL) { + if ($this->changed) { + $this->_clearBuffers(); + $this->changed = false; + } + switch ($this->mode) { + case CRYPT_MODE_STREAM: + $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options); + break; + case CRYPT_MODE_ECB: + if (!defined('OPENSSL_RAW_DATA')) { + $ciphetext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true); + } + $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options); + break; + case CRYPT_MODE_CBC: + if (!defined('OPENSSL_RAW_DATA')) { + $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size); + $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size); + } + $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV); + if ($this->continuousBuffer) { + $this->decryptIV = substr($ciphertext, -$this->block_size); + } + break; + case CRYPT_MODE_CTR: + $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer); + break; + case CRYPT_MODE_CFB: + // cfb loosely routines inspired by openssl's: + // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} + $plaintext = ''; + if ($this->continuousBuffer) { + $iv = &$this->decryptIV; + $pos = &$this->buffer['pos']; + } else { + $iv = $this->decryptIV; + $pos = 0; + } + $len = strlen($ciphertext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $this->block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize + $plaintext = substr($iv, $orig_pos) ^ $ciphertext; + $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); + $ciphertext = substr($ciphertext, $i); + } + $overflow = $len % $this->block_size; + if ($overflow) { + $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); + if ($len - $overflow) { + $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow); + } + $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); + $plaintext.= $iv ^ substr($ciphertext, -$overflow); + $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow); + $pos = $overflow; + } elseif ($len) { + $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv); + $iv = substr($ciphertext, -$this->block_size); + } + break; + case CRYPT_MODE_OFB: + $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + if ($this->engine === CRYPT_ENGINE_MCRYPT) { $block_size = $this->block_size; if ($this->changed) { $this->_setupMcrypt(); @@ -931,12 +1111,6 @@ class Crypt_Base return $plaintext; } - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}: - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); - } - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); if (!$this->continuousBuffer) { @@ -956,10 +1130,6 @@ class Crypt_Base } $block_size = $this->block_size; - if ($this->paddable) { - // we pad with chr(0) since that's what mcrypt_generic does [...] - $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0)); - } $buffer = &$this->debuffer; $plaintext = ''; @@ -986,15 +1156,17 @@ class Crypt_Base for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { $block = substr($ciphertext, $i, $block_size); if (strlen($block) > strlen($buffer['ciphertext'])) { - $buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $buffer['ciphertext'].= $this->_encryptBlock($xor); + $this->_increment_str($xor); } - $key = $this->_stringShift($buffer['ciphertext'], $block_size); + $key = $this->_string_shift($buffer['ciphertext'], $block_size); $plaintext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { $block = substr($ciphertext, $i, $block_size); - $key = $this->_encryptBlock($this->_generateXor($xor, $block_size)); + $key = $this->_encryptBlock($xor); + $this->_increment_str($xor); $plaintext.= $block ^ $key; } } @@ -1055,7 +1227,7 @@ class Crypt_Base $xor = $this->_encryptBlock($xor); $buffer['xor'].= $xor; } - $key = $this->_stringShift($buffer['xor'], $block_size); + $key = $this->_string_shift($buffer['xor'], $block_size); $plaintext.= $block ^ $key; } } else { @@ -1079,6 +1251,178 @@ class Crypt_Base return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } + /** + * OpenSSL CTR Processor + * + * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream + * for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt() + * and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this + * function will emulate CTR with ECB when necesary. + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @param String $plaintext + * @param String $encryptIV + * @param Array $buffer + * @return String + * @access private + */ + function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer) + { + $ciphertext = ''; + + $block_size = $this->block_size; + $key = $this->key; + + if ($this->openssl_emulate_ctr) { + $xor = $encryptIV; + if (strlen($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + if (strlen($block) > strlen($buffer['ciphertext'])) { + $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); + $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result; + $buffer['ciphertext'].= $result; + } + $this->_increment_str($xor); + $otp = $this->_string_shift($buffer['ciphertext'], $block_size); + $ciphertext.= $block ^ $otp; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); + $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp; + $this->_increment_str($xor); + $ciphertext.= $block ^ $otp; + } + } + if ($this->continuousBuffer) { + $encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; + } + } + + return $ciphertext; + } + + if (strlen($buffer['ciphertext'])) { + $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext)); + $plaintext = substr($plaintext, strlen($ciphertext)); + + if (!strlen($plaintext)) { + return $ciphertext; + } + } + + $overflow = strlen($plaintext) % $block_size; + if ($overflow) { + $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2 + $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); + $temp = $this->_string_pop($encrypted, $block_size); + $ciphertext.= $encrypted . ($plaintext2 ^ $temp); + if ($this->continuousBuffer) { + $buffer['ciphertext'] = substr($temp, $overflow); + $encryptIV = $temp; + } + } elseif (!strlen($buffer['ciphertext'])) { + $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); + $temp = $this->_string_pop($ciphertext, $block_size); + if ($this->continuousBuffer) { + $encryptIV = $temp; + } + } + if ($this->continuousBuffer) { + if (!defined('OPENSSL_RAW_DATA')) { + $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options); + } + $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); + if ($overflow) { + $this->_increment_str($encryptIV); + } + } + + return $ciphertext; + } + + /** + * OpenSSL OFB Processor + * + * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream + * for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt() + * and Crypt_Base::decrypt(). + * + * @see Crypt_Base::encrypt() + * @see Crypt_Base::decrypt() + * @param String $plaintext + * @param String $encryptIV + * @param Array $buffer + * @return String + * @access private + */ + function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer) + { + if (strlen($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $block_size = $this->block_size; + + $len = strlen($plaintext); + $key = $this->key; + $overflow = $len % $block_size; + + if (strlen($plaintext)) { + if ($overflow) { + $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); + $xor = $this->_string_pop($ciphertext, $block_size); + if ($this->continuousBuffer) { + $encryptIV = $xor; + } + $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow); + if ($this->continuousBuffer) { + $buffer['xor'] = $xor; + } + } else { + $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV); + if ($this->continuousBuffer) { + $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size); + } + } + } + + return $ciphertext; + } + + /** + * phpseclib <-> OpenSSL Mode Mapper + * + * May need to be overwritten by classes extending this one in some cases + * + * @return Integer + * @access private + */ + function _openssl_translate_mode() + { + switch ($this->mode) { + case CRYPT_MODE_ECB: + return 'ecb'; + case CRYPT_MODE_CBC: + return 'cbc'; + case CRYPT_MODE_CTR: + return 'ctr'; + case CRYPT_MODE_CFB: + return 'cfb'; + case CRYPT_MODE_OFB: + return 'ofb'; + } + } + /** * Pad "packets". * @@ -1144,10 +1488,9 @@ class Crypt_Base * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), * however, they are also less intuitive and more likely to cause you problems. * - * Note: Could, but not must, extend by the child Crypt_* class - * * @see Crypt_Base::disableContinuousBuffer() * @access public + * @internal Could, but not must, extend by the child Crypt_* class */ function enableContinuousBuffer() { @@ -1156,6 +1499,8 @@ class Crypt_Base } $this->continuousBuffer = true; + + $this->_setEngine(); } /** @@ -1163,10 +1508,9 @@ class Crypt_Base * * The default behavior. * - * Note: Could, but not must, extend by the child Crypt_* class - * * @see Crypt_Base::enableContinuousBuffer() * @access public + * @internal Could, but not must, extend by the child Crypt_* class */ function disableContinuousBuffer() { @@ -1179,16 +1523,159 @@ class Crypt_Base $this->continuousBuffer = false; $this->changed = true; + + $this->_setEngine(); + } + + /** + * Test for engine validity + * + * @see Crypt_Base::Crypt_Base() + * @param Integer $engine + * @access public + * @return Boolean + */ + function isValidEngine($engine) + { + switch ($engine) { + case CRYPT_ENGINE_OPENSSL: + if ($this->mode == CRYPT_MODE_STREAM && $this->continuousBuffer) { + return false; + } + $this->openssl_emulate_ctr = false; + $result = $this->cipher_name_openssl && + extension_loaded('openssl') && + // PHP 5.3.0 - 5.3.2 did not let you set IV's + version_compare(PHP_VERSION, '5.3.3', '>='); + if (!$result) { + return false; + } + + // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer + // $options openssl_encrypt expected a boolean $raw_data. + if (!defined('OPENSSL_RAW_DATA')) { + $this->openssl_options = true; + } else { + $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING; + } + + $methods = openssl_get_cipher_methods(); + if (in_array($this->cipher_name_openssl, $methods)) { + return true; + } + // not all of openssl's symmetric cipher's support ctr. for those + // that don't we'll emulate it + switch ($this->mode) { + case CRYPT_MODE_CTR: + if (in_array($this->cipher_name_openssl_ecb, $methods)) { + $this->openssl_emulate_ctr = true; + return true; + } + } + return false; + case CRYPT_ENGINE_MCRYPT: + return $this->cipher_name_mcrypt && + extension_loaded('mcrypt') && + in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()); + case CRYPT_ENGINE_INTERNAL: + return true; + } + + return false; + } + + /** + * Sets the preferred crypt engine + * + * Currently, $engine could be: + * + * - CRYPT_ENGINE_OPENSSL [very fast] + * + * - CRYPT_ENGINE_MCRYPT [fast] + * + * - CRYPT_ENGINE_INTERNAL [slow] + * + * If the preferred crypt engine is not available the fastest available one will be used + * + * @see Crypt_Base::Crypt_Base() + * @param Integer $engine + * @access public + */ + function setPreferredEngine($engine) + { + switch ($engine) { + //case CRYPT_ENGINE_OPENSSL: + case CRYPT_ENGINE_MCRYPT: + case CRYPT_ENGINE_INTERNAL: + $this->preferredEngine = $engine; + break; + default: + $this->preferredEngine = CRYPT_ENGINE_OPENSSL; + } + + $this->_setEngine(); + } + + /** + * Returns the engine currently being utilized + * + * @see Crypt_Base::_setEngine() + * @access public + */ + function getEngine() + { + return $this->engine; + } + + /** + * Sets the engine as appropriate + * + * @see Crypt_Base::Crypt_Base() + * @access private + */ + function _setEngine() + { + $this->engine = null; + + $candidateEngines = array( + $this->preferredEngine, + CRYPT_ENGINE_OPENSSL, + CRYPT_ENGINE_MCRYPT + ); + foreach ($candidateEngines as $engine) { + if ($this->isValidEngine($engine)) { + $this->engine = $engine; + break; + } + } + if (!$this->engine) { + $this->engine = CRYPT_ENGINE_INTERNAL; + } + + if ($this->engine != CRYPT_ENGINE_MCRYPT && $this->enmcrypt) { + // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, + // (re)open them with the module named in $this->cipher_name_mcrypt + mcrypt_module_close($this->enmcrypt); + mcrypt_module_close($this->demcrypt); + $this->enmcrypt = null; + $this->demcrypt = null; + + if ($this->ecb) { + mcrypt_module_close($this->ecb); + $this->ecb = null; + } + } + + $this->changed = true; } /** * Encrypts a block * - * Note: Must extend by the child Crypt_* class - * * @access private * @param String $in * @return String + * @internal Must be extended by the child Crypt_* class */ function _encryptBlock($in) { @@ -1198,11 +1685,10 @@ class Crypt_Base /** * Decrypts a block * - * Note: Must extend by the child Crypt_* class - * * @access private * @param String $in * @return String + * @internal Must be extended by the child Crypt_* class */ function _decryptBlock($in) { @@ -1212,12 +1698,11 @@ class Crypt_Base /** * Setup the key (expansion) * - * Only used if $engine == CRYPT_MODE_INTERNAL - * - * Note: Must extend by the child Crypt_* class + * Only used if $engine == CRYPT_ENGINE_INTERNAL * * @see Crypt_Base::_setup() * @access private + * @internal Must be extended by the child Crypt_* class */ function _setupKey() { @@ -1225,10 +1710,10 @@ class Crypt_Base } /** - * Setup the CRYPT_MODE_INTERNAL $engine + * Setup the CRYPT_ENGINE_INTERNAL $engine * * (re)init, if necessary, the internal cipher $engine and flush all $buffers - * Used (only) if $engine == CRYPT_MODE_INTERNAL + * Used (only) if $engine == CRYPT_ENGINE_INTERNAL * * _setup() will be called each time if $changed === true * typically this happens when using one or more of following public methods: @@ -1241,14 +1726,12 @@ class Crypt_Base * * - First run of encrypt() / decrypt() with no init-settings * - * Internally: _setup() is called always before(!) en/decryption. - * - * Note: Could, but not must, extend by the child Crypt_* class - * * @see setKey() * @see setIV() * @see disableContinuousBuffer() * @access private + * @internal _setup() is always called before en/decryption. + * @internal Could, but not must, extend by the child Crypt_* class */ function _setup() { @@ -1261,10 +1744,10 @@ class Crypt_Base } /** - * Setup the CRYPT_MODE_MCRYPT $engine + * Setup the CRYPT_ENGINE_MCRYPT $engine * * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers - * Used (only) if $engine = CRYPT_MODE_MCRYPT + * Used (only) if $engine = CRYPT_ENGINE_MCRYPT * * _setupMcrypt() will be called each time if $changed === true * typically this happens when using one or more of following public methods: @@ -1277,13 +1760,11 @@ class Crypt_Base * * - First run of encrypt() / decrypt() * - * - * Note: Could, but not must, extend by the child Crypt_* class - * * @see setKey() * @see setIV() * @see disableContinuousBuffer() * @access private + * @internal Could, but not must, extend by the child Crypt_* class */ function _setupMcrypt() { @@ -1383,14 +1864,12 @@ class Crypt_Base * after disableContinuousBuffer() or on cipher $engine (re)init * ie after setKey() or setIV() * - * Note: Could, but not must, extend by the child Crypt_* class - * * @access public + * @internal Could, but not must, extend by the child Crypt_* class */ function _clearBuffers() { - $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); - $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); + $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); // mcrypt's handling of invalid's $iv: // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size); @@ -1407,7 +1886,7 @@ class Crypt_Base * @access private * @return String */ - function _stringShift(&$string, $index = 1) + function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); @@ -1415,43 +1894,57 @@ class Crypt_Base } /** - * Generate CTR XOR encryption key + * String Pop * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. + * Inspired by array_pop + * + * @param String $string + * @param optional Integer $index + * @access private + * @return String + */ + function _string_pop(&$string, $index = 1) + { + $substr = substr($string, -$index); + $string = substr($string, 0, -$index); + return $substr; + } + + /** + * Increment the current string * * @see Crypt_Base::decrypt() * @see Crypt_Base::encrypt() - * @param String $iv - * @param Integer $length + * @param String $var * @access private - * @return String $xor */ - function _generateXor(&$iv, $length) + function _increment_str(&$var) { - $xor = ''; - $block_size = $this->block_size; - $num_blocks = floor(($length + ($block_size - 1)) / $block_size); - for ($i = 0; $i < $num_blocks; $i++) { - $xor.= $iv; - for ($j = 4; $j <= $block_size; $j+= 4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } + for ($i = 4; $i <= strlen($var); $i+= 4) { + $temp = substr($var, -$i, 4); + switch ($temp) { + case "\xFF\xFF\xFF\xFF": + $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4); + break; + case "\x7F\xFF\xFF\xFF": + $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4); + return; + default: + $temp = unpack('Nnum', $temp); + $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4); + return; } } - return $xor; + $remainder = strlen($var) % 4; + + if ($remainder == 0) { + return; + } + + $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT)); + $temp = substr(pack('N', $temp['num'] + 1), -$remainder); + $var = substr_replace($var, $temp, 0, $remainder); } /** @@ -1464,7 +1957,7 @@ class Crypt_Base * * _setupInlineCrypt() would be called only if: * - * - $engine == CRYPT_MODE_INTERNAL and + * - $engine == CRYPT_ENGINE_INTERNAL and * * - $use_inline_crypt === true * @@ -1512,11 +2005,10 @@ class Crypt_Base * @see Crypt_Base::encrypt() * @see Crypt_Base::decrypt() * @access private + * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() */ function _setupInlineCrypt() { - // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() - // If, for any reason, an extending Crypt_Base() Crypt_* class // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class, @@ -1656,7 +2148,6 @@ class Crypt_Base case CRYPT_MODE_ECB: $encrypt = $init_encrypt . ' $_ciphertext = ""; - $_text = $self->_pad($_text); $_plaintext_len = strlen($_text); for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { @@ -1688,23 +2179,24 @@ class Crypt_Base $_plaintext_len = strlen($_text); $_xor = $self->encryptIV; $_buffer = &$self->enbuffer; - - if (strlen($_buffer["encrypted"])) { + if (strlen($_buffer["ciphertext"])) { for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); - if (strlen($_block) > strlen($_buffer["encrypted"])) { - $in = $self->_generateXor($_xor, '.$block_size.'); + if (strlen($_block) > strlen($_buffer["ciphertext"])) { + $in = $_xor; '.$encrypt_block.' - $_buffer["encrypted"].= $in; + $self->_increment_str($_xor); + $_buffer["ciphertext"].= $in; } - $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.'); + $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.'); $_ciphertext.= $_block ^ $_key; } } else { for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); - $in = $self->_generateXor($_xor, '.$block_size.'); + $in = $_xor; '.$encrypt_block.' + $self->_increment_str($_xor); $_key = $in; $_ciphertext.= $_block ^ $_key; } @@ -1712,7 +2204,7 @@ class Crypt_Base if ($self->continuousBuffer) { $self->encryptIV = $_xor; if ($_start = $_plaintext_len % '.$block_size.') { - $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"]; + $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; } } @@ -1729,18 +2221,20 @@ class Crypt_Base for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); if (strlen($_block) > strlen($_buffer["ciphertext"])) { - $in = $self->_generateXor($_xor, '.$block_size.'); + $in = $_xor; '.$encrypt_block.' + $self->_increment_str($_xor); $_buffer["ciphertext"].= $in; } - $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.'); + $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.'); $_plaintext.= $_block ^ $_key; } } else { for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); - $in = $self->_generateXor($_xor, '.$block_size.'); + $in = $_xor; '.$encrypt_block.' + $self->_increment_str($_xor); $_key = $in; $_plaintext.= $_block ^ $_key; } @@ -1870,7 +2364,7 @@ class Crypt_Base $_xor = $in; $_buffer["xor"].= $_xor; } - $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_key = $self->_string_shift($_buffer["xor"], '.$block_size.'); $_ciphertext.= $_block ^ $_key; } } else { @@ -1906,7 +2400,7 @@ class Crypt_Base $_xor = $in; $_buffer["xor"].= $_xor; } - $_key = $self->_stringShift($_buffer["xor"], '.$block_size.'); + $_key = $self->_string_shift($_buffer["xor"], '.$block_size.'); $_plaintext.= $_block ^ $_key; } } else { @@ -1943,7 +2437,6 @@ class Crypt_Base default: $encrypt = $init_encrypt . ' $_ciphertext = ""; - $_text = $self->_pad($_text); $_plaintext_len = strlen($_text); $in = $self->encryptIV; @@ -2001,11 +2494,46 @@ class Crypt_Base * for which $mode the lambda function was created. * * @access private - * @return &Array + * @return Array &$functions */ function &_getLambdaFunctions() { static $functions = array(); return $functions; } + + /** + * Generates a digest from $bytes + * + * @see _setupInlineCrypt() + * @access private + * @param $bytes + * @return String + */ + function _hashInlineCryptFunction($bytes) + { + if (!defined('CRYPT_BASE_WHIRLPOOL_AVAILABLE')) { + define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos()))); + } + + $result = ''; + $hash = $bytes; + + switch (true) { + case CRYPT_BASE_WHIRLPOOL_AVAILABLE: + foreach (str_split($bytes, 64) as $t) { + $hash = hash('whirlpool', $hash, true); + $result .= $t ^ $hash; + } + return $result . hash('whirlpool', $hash, true); + default: + $len = strlen($bytes); + for ($i = 0; $i < $len; $i+=20) { + $t = substr($bytes, $i, 20); + $hash = pack('H*', sha1($hash)); + $result .= $t ^ $hash; + } + return $result . pack('H*', sha1($hash)); + } + } } diff --git a/Crypt/Blowfish.php b/Crypt/Blowfish.php index 7d4987c..6661b16 100644 --- a/Crypt/Blowfish.php +++ b/Crypt/Blowfish.php @@ -48,7 +48,7 @@ * @package Crypt_Blowfish * @author Jim Wigginton * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -101,20 +101,6 @@ define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB); define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_BLOWFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - /** * Pure-PHP implementation of Blowfish. * @@ -174,7 +160,7 @@ class Crypt_Blowfish extends Crypt_Base /** * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each * - * S-Box 1 + * S-Box 0 * * @access private * @var array @@ -340,7 +326,7 @@ class Crypt_Blowfish extends Crypt_Base /** * P-Array consists of 18 32-bit subkeys * - * @var array $parray + * @var array * @access private */ var $parray = array( @@ -354,7 +340,7 @@ class Crypt_Blowfish extends Crypt_Base * * Holds the expanded key [p] and the key-depended s-boxes [sb] * - * @var array $bctx + * @var array * @access private */ var $bctx; @@ -395,6 +381,29 @@ class Crypt_Blowfish extends Crypt_Base parent::setKey($key); } + /** + * Test for engine validity + * + * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() + * + * @see Crypt_Base::isValidEngine() + * @param Integer $engine + * @access public + * @return Boolean + */ + function isValidEngine($engine) + { + if ($engine == CRYPT_ENGINE_OPENSSL) { + if (strlen($this->key) != 16) { + return false; + } + $this->cipher_name_openssl_ecb = 'bf-ecb'; + $this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode(); + } + + return parent::isValidEngine($engine); + } + /** * Setup the key (expansion) * @@ -472,17 +481,17 @@ class Crypt_Blowfish extends Crypt_Base $r = $in[2]; for ($i = 0; $i < 16; $i+= 2) { - $l^= $p[$i]; - $r^= ($sb_0[$l >> 24 & 0xff] + - $sb_1[$l >> 16 & 0xff] ^ - $sb_2[$l >> 8 & 0xff]) + - $sb_3[$l & 0xff]; + $l^= $p[$i]; + $r^= ($sb_0[$l >> 24 & 0xff] + + $sb_1[$l >> 16 & 0xff] ^ + $sb_2[$l >> 8 & 0xff]) + + $sb_3[$l & 0xff]; - $r^= $p[$i + 1]; - $l^= ($sb_0[$r >> 24 & 0xff] + - $sb_1[$r >> 16 & 0xff] ^ - $sb_2[$r >> 8 & 0xff]) + - $sb_3[$r & 0xff]; + $r^= $p[$i + 1]; + $l^= ($sb_0[$r >> 24 & 0xff] + + $sb_1[$r >> 16 & 0xff] ^ + $sb_2[$r >> 8 & 0xff]) + + $sb_3[$r & 0xff]; } return pack("N*", $r ^ $p[17], $l ^ $p[16]); } @@ -519,7 +528,6 @@ class Crypt_Blowfish extends Crypt_Base $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]; } - return pack("N*", $r ^ $p[0], $l ^ $p[1]); } @@ -534,15 +542,14 @@ class Crypt_Blowfish extends Crypt_Base $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions(); // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. + // (Currently, for Crypt_Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit) // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one. - $gen_hi_opt_code = (bool)( count($lambda_functions) < 10); + $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); - switch (true) { - case $gen_hi_opt_code: - $code_hash = md5(str_pad("Crypt_Blowfish, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - $code_hash = "Crypt_Blowfish, {$this->mode}"; + // Generation of a unique hash for our generated code + $code_hash = "Crypt_Blowfish, {$this->mode}"; + if ($gen_hi_opt_code) { + $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); } if (!isset($lambda_functions[$code_hash])) { diff --git a/Crypt/DES.php b/Crypt/DES.php index f8e6a83..cc7530a 100644 --- a/Crypt/DES.php +++ b/Crypt/DES.php @@ -53,7 +53,7 @@ * @category Crypt * @package Crypt_DES * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -121,20 +121,6 @@ define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB); define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_DES_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - /** * Pure-PHP implementation of DES. * @@ -191,6 +177,21 @@ class Crypt_DES extends Crypt_Base */ var $cipher_name_mcrypt = 'des'; + /** + * The OpenSSL names of the cipher / modes + * + * @see Crypt_Base::openssl_mode_names + * @var Array + * @access private + */ + var $openssl_mode_names = array( + CRYPT_MODE_ECB => 'des-ecb', + CRYPT_MODE_CBC => 'des-cbc', + CRYPT_MODE_CFB => 'des-cfb', + CRYPT_MODE_OFB => 'des-ofb' + // CRYPT_MODE_CTR is undefined for DES + ); + /** * Optimizing value while CFB-encrypting * @@ -661,6 +662,28 @@ class Crypt_DES extends Crypt_Base 0x00000820, 0x00020020, 0x08000000, 0x08020800 ); + /** + * Test for engine validity + * + * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() + * + * @see Crypt_Base::isValidEngine() + * @param Integer $engine + * @access public + * @return Boolean + */ + function isValidEngine($engine) + { + if ($this->key_size_max == 8) { + if ($engine == CRYPT_ENGINE_OPENSSL) { + $this->cipher_name_openssl_ecb = 'des-ecb'; + $this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode(); + } + } + + return parent::isValidEngine($engine); + } + /** * Sets the key. * @@ -1358,21 +1381,20 @@ class Crypt_DES extends Crypt_Base $des_rounds = $this->des_rounds; // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. + // (Currently, for Crypt_DES, one generated $lambda_function cost on php5.5@32bit ~135kb unfreeable mem and ~230kb on php5.5@64bit) + // (Currently, for Crypt_TripleDES, one generated $lambda_function cost on php5.5@32bit ~240kb unfreeable mem and ~340kb on php5.5@64bit) // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); // Generation of a uniqe hash for our generated code - switch (true) { - case $gen_hi_opt_code: - // For hi-optimized code, we create for each combination of - // $mode, $des_rounds and $this->key its own encrypt/decrypt function. - $code_hash = md5(str_pad("Crypt_DES, $des_rounds, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - // After max 10 hi-optimized functions, we create generic - // (still very fast.. but not ultra) functions for each $mode/$des_rounds - // Currently 2 * 5 generic functions will be then max. possible. - $code_hash = "Crypt_DES, $des_rounds, {$this->mode}"; + $code_hash = "Crypt_DES, $des_rounds, {$this->mode}"; + if ($gen_hi_opt_code) { + // For hi-optimized code, we create for each combination of + // $mode, $des_rounds and $this->key its own encrypt/decrypt function. + // After max 10 hi-optimized functions, we create generic + // (still very fast.. but not ultra) functions for each $mode/$des_rounds + // Currently 2 * 5 generic functions will be then max. possible. + $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); } // Is there a re-usable $lambda_functions in there? If not, we have to create it. @@ -1427,7 +1449,6 @@ class Crypt_DES extends Crypt_Base // Creating code for en- and decryption. $crypt_block = array(); foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) { - /* Do the initial IP permutation. */ $crypt_block[$c] = ' $in = unpack("N*", $in); diff --git a/Crypt/Hash.php b/Crypt/Hash.php index d6e81e8..f6b25df 100644 --- a/Crypt/Hash.php +++ b/Crypt/Hash.php @@ -49,7 +49,7 @@ * @category Crypt * @package Crypt_Hash * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -153,7 +153,7 @@ class Crypt_Hash */ function Crypt_Hash($hash = 'sha1') { - if ( !defined('CRYPT_HASH_MODE') ) { + if (!defined('CRYPT_HASH_MODE')) { switch (true) { case extension_loaded('hash'): define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); @@ -242,7 +242,7 @@ class Crypt_Hash $mode = CRYPT_HASH_MODE; } - switch ( $mode ) { + switch ($mode) { case CRYPT_HASH_MODE_MHASH: switch ($hash) { case 'md5': @@ -276,26 +276,26 @@ class Crypt_Hash switch ($hash) { case 'md2': - $this->b = 16; - $this->hash = array($this, '_md2'); - break; + $this->b = 16; + $this->hash = array($this, '_md2'); + break; case 'md5': - $this->b = 64; - $this->hash = array($this, '_md5'); - break; + $this->b = 64; + $this->hash = array($this, '_md5'); + break; case 'sha256': - $this->b = 64; - $this->hash = array($this, '_sha256'); - break; + $this->b = 64; + $this->hash = array($this, '_sha256'); + break; case 'sha384': case 'sha512': - $this->b = 128; - $this->hash = array($this, '_sha512'); - break; + $this->b = 128; + $this->hash = array($this, '_sha512'); + break; case 'sha1': default: - $this->b = 64; - $this->hash = array($this, '_sha1'); + $this->b = 64; + $this->hash = array($this, '_sha1'); } $this->ipad = str_repeat(chr(0x36), $this->b); @@ -314,7 +314,7 @@ class Crypt_Hash $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; if (!empty($this->key) || is_string($this->key)) { - switch ( $mode ) { + switch ($mode) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text, $this->key); break; @@ -337,7 +337,7 @@ class Crypt_Hash $output = call_user_func($this->hash, $output); // step 7 } } else { - switch ( $mode ) { + switch ($mode) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text); break; @@ -511,12 +511,14 @@ class Crypt_Hash // Extend the sixteen 32-bit words into sixty-four 32-bit words for ($i = 16; $i < 64; $i++) { + // @codingStandardsIgnoreStart $s0 = $this->_rightRotate($w[$i - 15], 7) ^ $this->_rightRotate($w[$i - 15], 18) ^ $this->_rightShift( $w[$i - 15], 3); $s1 = $this->_rightRotate($w[$i - 2], 17) ^ $this->_rightRotate($w[$i - 2], 19) ^ $this->_rightShift( $w[$i - 2], 10); + // @codingStandardsIgnoreEnd $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); } diff --git a/Crypt/RC2.php b/Crypt/RC2.php index 96c9f18..ddf8f2d 100644 --- a/Crypt/RC2.php +++ b/Crypt/RC2.php @@ -99,20 +99,6 @@ define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB); define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ -/**#@+ - * @access private - * @see Crypt_RC2::Crypt_RC2() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RC2_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - /** * Pure-PHP implementation of RC2. * @@ -138,7 +124,19 @@ class Crypt_RC2 extends Crypt_Base * @var String * @access private */ - var $key = "\0"; + var $key; + + /** + * The Original (unpadded) Key + * + * @see Crypt_Base::key + * @see setKey() + * @see encrypt() + * @see decrypt() + * @var String + * @access private + */ + var $orig_key; /** * The default password key_size used by setPassword() @@ -189,6 +187,17 @@ class Crypt_RC2 extends Crypt_Base */ var $default_key_length = 1024; + /** + * The key length in bits. + * + * @see Crypt_RC2::isValidEnine() + * @see Crypt_RC2::setKey() + * @var Integer + * @access private + * @internal Should be in range [1..1024]. + */ + var $current_key_length; + /** * The Key Schedule * @@ -341,7 +350,30 @@ class Crypt_RC2 extends Crypt_Base function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC) { parent::Crypt_Base($mode); - $this->setKey(''); + } + + /** + * Test for engine validity + * + * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() + * + * @see Crypt_Base::Crypt_Base() + * @param Integer $engine + * @access public + * @return Boolean + */ + function isValidEngine($engine) + { + switch ($engine) { + case CRYPT_ENGINE_OPENSSL: + if ($this->current_key_length != 128 || strlen($this->orig_key) != 16) { + return false; + } + $this->cipher_name_openssl_ecb = 'rc2-ecb'; + $this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode(); + } + + return parent::isValidEngine($engine); } /** @@ -375,15 +407,18 @@ class Crypt_RC2 extends Crypt_Base * @see Crypt_Base::setKey() * @access public * @param String $key - * @param Integer $t1 optional Effective key length in bits. + * @param Integer $t1 optional Effective key length in bits. */ function setKey($key, $t1 = 0) { + $this->orig_key = $key; + if ($t1 <= 0) { $t1 = $this->default_key_length; - } else if ($t1 > 1024) { + } elseif ($t1 > 1024) { $t1 = 1024; } + $this->current_key_length = $t1; // Key byte count should be 1..128. $key = strlen($key) ? substr($key, 0, 128) : "\x00"; $t = strlen($key); @@ -416,6 +451,52 @@ class Crypt_RC2 extends Crypt_Base parent::setKey(call_user_func_array('pack', $l)); } + /** + * Encrypts a message. + * + * Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code + * + * @see decrypt() + * @access public + * @param String $plaintext + * @return String $ciphertext + */ + function encrypt($plaintext) + { + if ($this->engine == CRYPT_ENGINE_OPENSSL) { + $temp = $this->key; + $this->key = $this->orig_key; + $result = parent::encrypt($plaintext); + $this->key = $temp; + return $result; + } + + return parent::encrypt($plaintext); + } + + /** + * Decrypts a message. + * + * Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code + * + * @see encrypt() + * @access public + * @param String $ciphertext + * @return String $plaintext + */ + function decrypt($ciphertext) + { + if ($this->engine == CRYPT_ENGINE_OPENSSL) { + $temp = $this->key; + $this->key = $this->orig_key; + $result = parent::decrypt($ciphertext); + $this->key = $temp; + return $result; + } + + return parent::encrypt($ciphertext); + } + /** * Encrypts a block * @@ -506,6 +587,21 @@ class Crypt_RC2 extends Crypt_Base return pack('vvvv', $r0, $r1, $r2, $r3); } + /** + * Setup the CRYPT_ENGINE_MCRYPT $engine + * + * @see Crypt_Base::_setupMcrypt() + * @access private + */ + function _setupMcrypt() + { + if (!isset($this->key)) { + $this->setKey(''); + } + + parent::_setupMcrypt(); + } + /** * Creates the key schedule * @@ -514,6 +610,10 @@ class Crypt_RC2 extends Crypt_Base */ function _setupKey() { + if (!isset($this->key)) { + $this->setKey(''); + } + // Key has already been expanded in Crypt_RC2::setKey(): // Only the first value must be altered. $l = unpack('Ca/Cb/v*', $this->key); @@ -536,14 +636,14 @@ class Crypt_RC2 extends Crypt_Base // The first 10 generated $lambda_functions will use the $keys hardcoded as integers // for the mixing rounds, for better inline crypt performance [~20% faster]. // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10. - $keys = $this->keys; - if (count($lambda_functions) >= 10) { - foreach ($this->keys as $k => $v) { - $keys[$k] = '$keys[' . $k . ']'; - } - } + // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit) + $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); - $code_hash = md5(str_pad("Crypt_RC2, {$this->mode}, ", 32, "\0") . implode(',', $keys)); + // Generation of a uniqe hash for our generated code + $code_hash = "Crypt_RC2, {$this->mode}"; + if ($gen_hi_opt_code) { + $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); + } // Is there a re-usable $lambda_functions in there? // If not, we have to create it. @@ -551,6 +651,16 @@ class Crypt_RC2 extends Crypt_Base // Init code for both, encrypt and decrypt. $init_crypt = '$keys = $self->keys;'; + switch (true) { + case $gen_hi_opt_code: + $keys = $this->keys; + default: + $keys = array(); + foreach ($this->keys as $k => $v) { + $keys[$k] = '$keys[' . $k . ']'; + } + } + // $in is the current 8 bytes block which has to be en/decrypt $encrypt_block = $decrypt_block = ' $in = unpack("v4", $in); diff --git a/Crypt/RC4.php b/Crypt/RC4.php index 24ae0a9..f6cf890 100644 --- a/Crypt/RC4.php +++ b/Crypt/RC4.php @@ -55,7 +55,7 @@ * @category Crypt * @package Crypt_RC4 * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -69,20 +69,6 @@ if (!class_exists('Crypt_Base')) { include_once 'Base.php'; } -/**#@+ - * @access private - * @see Crypt_RC4::Crypt_RC4() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - /**#@+ * @access private * @see Crypt_RC4::_crypt() @@ -181,6 +167,38 @@ class Crypt_RC4 extends Crypt_Base parent::Crypt_Base(CRYPT_MODE_STREAM); } + /** + * Test for engine validity + * + * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() + * + * @see Crypt_Base::Crypt_Base() + * @param Integer $engine + * @access public + * @return Boolean + */ + function isValidEngine($engine) + { + switch ($engine) { + case CRYPT_ENGINE_OPENSSL: + switch (strlen($this->key)) { + case 5: + $this->cipher_name_openssl = 'rc4-40'; + break; + case 8: + $this->cipher_name_openssl = 'rc4-64'; + break; + case 16: + $this->cipher_name_openssl = 'rc4'; + break; + default: + return false; + } + } + + return parent::isValidEngine($engine); + } + /** * Dummy function. * @@ -230,7 +248,7 @@ class Crypt_RC4 extends Crypt_Base */ function encrypt($plaintext) { - if ($this->engine == CRYPT_MODE_MCRYPT) { + if ($this->engine != CRYPT_ENGINE_INTERNAL) { return parent::encrypt($plaintext); } return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); @@ -250,7 +268,7 @@ class Crypt_RC4 extends Crypt_Base */ function decrypt($ciphertext) { - if ($this->engine == CRYPT_MODE_MCRYPT) { + if ($this->engine != CRYPT_ENGINE_INTERNAL) { return parent::decrypt($ciphertext); } return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); diff --git a/Crypt/RSA.php b/Crypt/RSA.php index 823044b..008f14e 100644 --- a/Crypt/RSA.php +++ b/Crypt/RSA.php @@ -62,7 +62,7 @@ * @category Crypt * @package Crypt_RSA * @author Jim Wigginton - * @copyright MMIX Jim Wigginton + * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -107,6 +107,13 @@ define('CRYPT_RSA_ENCRYPTION_OAEP', 1); * compatibility with protocols (like SSH-1) written before OAEP's introduction. */ define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); +/** + * Do not use any padding + * + * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy + * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc. + */ +define('CRYPT_RSA_ENCRYPTION_NONE', 3); /**#@-*/ /**#@+ @@ -492,7 +499,7 @@ class Crypt_RSA $this->configFile = CRYPT_RSA_OPENSSL_CONFIG; - if ( !defined('CRYPT_RSA_MODE') ) { + if (!defined('CRYPT_RSA_MODE')) { switch (true) { // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger @@ -515,9 +522,16 @@ class Crypt_RSA $versions = array(); if (!empty($matches[1])) { - for ($i = 0; $i < count($matches[1]); $i++) { - $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); - } + for ($i = 0; $i < count($matches[1]); $i++) { + $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + + // Remove letter part in OpenSSL version + if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { + $versions[$matches[1][$i]] = $fullVersion; + } else { + $versions[$matches[1][$i]] = $m[0]; + } + } } // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ @@ -578,7 +592,7 @@ class Crypt_RSA } // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum - if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) { + if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) { $config = array(); if (isset($this->configFile)) { $config['config'] = $this->configFile; @@ -592,7 +606,8 @@ class Crypt_RSA $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); // clear the buffer of error strings stemming from a minimalistic openssl.cnf - while (openssl_error_string() !== false); + while (openssl_error_string() !== false) { + } return array( 'privatekey' => $privatekey, @@ -782,19 +797,39 @@ class Crypt_RSA $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none'; $key.= $encryption; $key.= "\r\nComment: " . $this->comment . "\r\n"; - $public = pack('Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus'] + $public = pack( + 'Na*Na*Na*', + strlen('ssh-rsa'), + 'ssh-rsa', + strlen($raw['publicExponent']), + $raw['publicExponent'], + strlen($raw['modulus']), + $raw['modulus'] ); - $source = pack('Na*Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, - strlen($this->comment), $this->comment, strlen($public), $public + $source = pack( + 'Na*Na*Na*Na*', + strlen('ssh-rsa'), + 'ssh-rsa', + strlen($encryption), + $encryption, + strlen($this->comment), + $this->comment, + strlen($public), + $public ); $public = base64_encode($public); $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; $key.= chunk_split($public, 64); - $private = pack('Na*Na*Na*Na*', - strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'], - strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient'] + $private = pack( + 'Na*Na*Na*Na*', + strlen($raw['privateExponent']), + $raw['privateExponent'], + strlen($raw['prime1']), + $raw['prime1'], + strlen($raw['prime2']), + $raw['prime2'], + strlen($raw['coefficient']), + $raw['coefficient'] ); if (empty($this->password) && !is_string($this->password)) { $source.= pack('Na*', strlen($private), $private); @@ -861,8 +896,14 @@ class Crypt_RSA if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) { $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA - $RSAPrivateKey = pack('Ca*a*Ca*a*', - CRYPT_RSA_ASN1_INTEGER, "\01\00", $rsaOID, 4, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey + $RSAPrivateKey = pack( + 'Ca*a*Ca*a*', + CRYPT_RSA_ASN1_INTEGER, + "\01\00", + $rsaOID, + 4, + $this->_encodeLength(strlen($RSAPrivateKey)), + $RSAPrivateKey ); $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); if (!empty($this->password) || is_string($this->password)) { @@ -876,20 +917,35 @@ class Crypt_RSA $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey); - $parameters = pack('Ca*a*Ca*N', - CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($salt)), $salt, - CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(4), $iterationCount + $parameters = pack( + 'Ca*a*Ca*N', + CRYPT_RSA_ASN1_OCTETSTRING, + $this->_encodeLength(strlen($salt)), + $salt, + CRYPT_RSA_ASN1_INTEGER, + $this->_encodeLength(4), + $iterationCount ); $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03"; - $encryptionAlgorithm = pack('Ca*a*Ca*a*', - CRYPT_RSA_ASN1_OBJECT, $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), $pbeWithMD5AndDES_CBC, - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($parameters)), $parameters + $encryptionAlgorithm = pack( + 'Ca*a*Ca*a*', + CRYPT_RSA_ASN1_OBJECT, + $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), + $pbeWithMD5AndDES_CBC, + CRYPT_RSA_ASN1_SEQUENCE, + $this->_encodeLength(strlen($parameters)), + $parameters ); - $RSAPrivateKey = pack('Ca*a*Ca*a*', - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($encryptionAlgorithm)), $encryptionAlgorithm, - CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey + $RSAPrivateKey = pack( + 'Ca*a*Ca*a*', + CRYPT_RSA_ASN1_SEQUENCE, + $this->_encodeLength(strlen($encryptionAlgorithm)), + $encryptionAlgorithm, + CRYPT_RSA_ASN1_OCTETSTRING, + $this->_encodeLength(strlen($RSAPrivateKey)), + $RSAPrivateKey ); $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); @@ -976,9 +1032,12 @@ class Crypt_RSA 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent) ); - $RSAPublicKey = pack('Ca*a*a*', - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), - $components['modulus'], $components['publicExponent'] + $RSAPublicKey = pack( + 'Ca*a*a*', + CRYPT_RSA_ASN1_SEQUENCE, + $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), + $components['modulus'], + $components['publicExponent'] ); if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) { @@ -991,8 +1050,11 @@ class Crypt_RSA $RSAPublicKey = chr(0) . $RSAPublicKey; $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey; - $RSAPublicKey = pack('Ca*a*', - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey + $RSAPublicKey = pack( + 'Ca*a*', + CRYPT_RSA_ASN1_SEQUENCE, + $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), + $rsaOID . $RSAPublicKey ); $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . @@ -1765,6 +1827,41 @@ class Crypt_RSA return $temp; } + /** + * Returns the public key's fingerprint + * + * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is + * no public key currently loaded, false is returned. + * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716) + * + * @access public + * @param String $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned + * for invalid values. + */ + public function getPublicKeyFingerprint($algorithm = 'md5') + { + if (empty($this->modulus) || empty($this->publicExponent)) { + return false; + } + + $modulus = $this->modulus->toBytes(true); + $publicExponent = $this->publicExponent->toBytes(true); + + $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); + + switch ($algorithm) { + case 'sha256': + $hash = new Crypt_Hash('sha256'); + $base = base64_encode($hash->hash($RSAPublicKey)); + return substr($base, 0, strlen($base) - 1); + case 'md5': + return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1); + default: + return false; + } + + } + /** * Returns the private key * @@ -1878,7 +1975,7 @@ class Crypt_RSA function _decodeLength(&$string) { $length = ord($this->_string_shift($string)); - if ( $length & 0x80 ) { // definite length, long form + if ($length & 0x80) { // definite length, long form $length&= 0x7F; $temp = $this->_string_shift($string, $length); list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)); @@ -2401,6 +2498,22 @@ class Crypt_RSA return substr($m, 1); } + /** + * Raw Encryption / Decryption + * + * Doesn't use padding and is not recommended. + * + * @access private + * @param String $m + * @return String + */ + function _raw_encrypt($m) + { + $temp = $this->_os2ip($m); + $temp = $this->_rsaep($temp); + return $this->_i2osp($temp, $this->k); + } + /** * RSAES-PKCS1-V1_5-ENCRYPT * @@ -2524,7 +2637,7 @@ class Crypt_RSA // be output. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) - $sLen = $this->sLen == false ? $this->hLen : $this->sLen; + $sLen = $this->sLen === false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { @@ -2562,7 +2675,7 @@ class Crypt_RSA // be output. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8); - $sLen = $this->sLen == false ? $this->hLen : $this->sLen; + $sLen = $this->sLen === false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { @@ -2847,6 +2960,13 @@ class Crypt_RSA function encrypt($plaintext) { switch ($this->encryptionMode) { + case CRYPT_RSA_ENCRYPTION_NONE: + $plaintext = str_split($plaintext, $this->k); + $ciphertext = ''; + foreach ($plaintext as $m) { + $ciphertext.= $this->_raw_encrypt($m); + } + return $ciphertext; case CRYPT_RSA_ENCRYPTION_PKCS1: $length = $this->k - 11; if ($length <= 0) { @@ -2895,6 +3015,9 @@ class Crypt_RSA $plaintext = ''; switch ($this->encryptionMode) { + case CRYPT_RSA_ENCRYPTION_NONE: + $decrypt = '_raw_encrypt'; + break; case CRYPT_RSA_ENCRYPTION_PKCS1: $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; break; diff --git a/Crypt/Random.php b/Crypt/Random.php index 5a3d28c..113371c 100644 --- a/Crypt/Random.php +++ b/Crypt/Random.php @@ -38,7 +38,7 @@ * @category Crypt * @package Crypt_Random * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -171,9 +171,9 @@ if (!function_exists('crypt_random_string')) { ini_set('session.use_cookies', $old_use_cookies); session_cache_limiter($old_session_cache_limiter); } else { - if ($_OLD_SESSION !== false) { - $_SESSION = $_OLD_SESSION; - unset($_OLD_SESSION); + if ($_OLD_SESSION !== false) { + $_SESSION = $_OLD_SESSION; + unset($_OLD_SESSION); } else { unset($_SESSION); } diff --git a/Crypt/Rijndael.php b/Crypt/Rijndael.php index 3631972..0eab58d 100644 --- a/Crypt/Rijndael.php +++ b/Crypt/Rijndael.php @@ -65,7 +65,7 @@ * @category Crypt * @package Crypt_Rijndael * @author Jim Wigginton - * @copyright MMVIII Jim Wigginton + * @copyright 2008 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -118,20 +118,6 @@ define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB); define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - /** * Pure-PHP implementation of Rijndael. * @@ -170,7 +156,7 @@ class Crypt_Rijndael extends Crypt_Base * * @see Crypt_Base::cipher_name_mcrypt * @see Crypt_Base::engine - * @see _setupEngine() + * @see isValidEngine() * @var String * @access private */ @@ -223,7 +209,6 @@ class Crypt_Rijndael extends Crypt_Base * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. - * */ var $Nb = 4; @@ -276,404 +261,32 @@ class Crypt_Rijndael extends Crypt_Base var $kl; /** - * Precomputed mixColumns table + * Default Constructor. * - * According to (section 5.2.1), - * precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so - * those are the names we'll use. + * Determines whether or not the mcrypt extension should be used. * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private + * $mode could be: + * + * - CRYPT_RIJNDAEL_MODE_ECB + * + * - CRYPT_RIJNDAEL_MODE_CBC + * + * - CRYPT_RIJNDAEL_MODE_CTR + * + * - CRYPT_RIJNDAEL_MODE_CFB + * + * - CRYPT_RIJNDAEL_MODE_OFB + * + * If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. + * + * @see Crypt_Base::Crypt_Base() + * @param optional Integer $mode + * @access public */ - var $t0 = array( - 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, - 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, - 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, - 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, - 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, - 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, - 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, - 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, - 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, - 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, - 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, - 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, - 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, - 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, - 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, - 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, - 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, - 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, - 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, - 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, - 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, - 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, - 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, - 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, - 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, - 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, - 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, - 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, - 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, - 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, - 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, - 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A - ); - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $t1 = array( - 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, - 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, - 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, - 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, - 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, - 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, - 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, - 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, - 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, - 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, - 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, - 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, - 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, - 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, - 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, - 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, - 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, - 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, - 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, - 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, - 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, - 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, - 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, - 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, - 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, - 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, - 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, - 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, - 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, - 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, - 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, - 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616 - ); - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $t2 = array( - 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, - 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, - 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, - 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, - 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, - 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, - 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, - 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, - 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, - 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, - 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, - 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, - 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, - 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, - 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, - 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, - 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, - 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, - 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, - 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, - 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, - 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, - 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, - 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, - 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, - 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, - 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, - 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, - 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, - 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, - 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, - 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16 - ); - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $t3 = array( - 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, - 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, - 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, - 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, - 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, - 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, - 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, - 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, - 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, - 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, - 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, - 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, - 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, - 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, - 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, - 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, - 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, - 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, - 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, - 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, - 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, - 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, - 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, - 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, - 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, - 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, - 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, - 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, - 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, - 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, - 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, - 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt0 = array( - 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393, - 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, - 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6, - 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844, - 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, - 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94, - 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A, - 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, - 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A, - 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051, - 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, - 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB, - 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E, - 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, - 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16, - 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8, - 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, - 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120, - 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0, - 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, - 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4, - 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5, - 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, - 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6, - 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0, - 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, - 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F, - 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713, - 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, - 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86, - 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541, - 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742 - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt1 = array( - 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303, - 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3, - 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9, - 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8, - 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A, - 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B, - 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB, - 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682, - 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE, - 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10, - 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015, - 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE, - 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72, - 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E, - 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A, - 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9, - 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E, - 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611, - 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3, - 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390, - 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF, - 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF, - 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB, - 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8, - 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266, - 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6, - 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551, - 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647, - 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1, - 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB, - 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95, - 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857 - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt2 = array( - 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3, - 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562, - 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3, - 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9, - 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE, - 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908, - 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655, - 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16, - 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6, - 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E, - 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050, - 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8, - 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A, - 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436, - 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12, - 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E, - 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB, - 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6, - 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1, - 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233, - 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD, - 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3, - 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B, - 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15, - 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2, - 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791, - 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665, - 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6, - 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47, - 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844, - 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D, - 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8 - ); - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael:_encryptBlock() - * @see Crypt_Rijndael:_decryptBlock() - * @var Array - * @access private - */ - var $dt3 = array( - 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, - 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, - 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, - 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, - 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, - 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, - 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, - 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, - 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, - 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, - 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, - 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, - 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, - 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, - 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, - 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, - 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, - 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, - 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, - 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, - 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, - 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, - 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, - 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, - 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, - 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, - 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, - 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, - 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, - 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, - 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, - 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 - ); - - /** - * The SubByte S-Box - * - * @see Crypt_Rijndael::_encryptBlock() - * @var Array - * @access private - */ - var $sbox = array( - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 - ); - - /** - * The inverse SubByte S-Box - * - * @see Crypt_Rijndael::_decryptBlock() - * @var Array - * @access private - */ - var $isbox = array( - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D - ); + function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) + { + parent::Crypt_Base($mode); + } /** * Sets the key. @@ -694,8 +307,6 @@ class Crypt_Rijndael extends Crypt_Base */ function setKey($key) { - parent::setKey($key); - if (!$this->explicit_key_length) { $length = strlen($key); switch (true) { @@ -714,8 +325,8 @@ class Crypt_Rijndael extends Crypt_Base default: $this->key_size = 32; } - $this->_setupEngine(); } + parent::setKey($key); } /** @@ -759,7 +370,7 @@ class Crypt_Rijndael extends Crypt_Base $this->explicit_key_length = true; $this->changed = true; - $this->_setupEngine(); + $this->_setEngine(); } /** @@ -776,74 +387,48 @@ class Crypt_Rijndael extends Crypt_Base $length >>= 5; if ($length > 8) { $length = 8; - } else if ($length < 4) { + } elseif ($length < 4) { $length = 4; } $this->Nb = $length; $this->block_size = $length << 2; $this->changed = true; - $this->_setupEngine(); + $this->_setEngine(); } /** - * Setup the fastest possible $engine + * Test for engine validity * - * Determines if the mcrypt (MODE_MCRYPT) $engine available - * and usable for the current $block_size and $key_size. + * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() * - * If not, the slower MODE_INTERNAL $engine will be set. - * - * @see setKey() - * @see setKeyLength() - * @see setBlockLength() - * @access private + * @see Crypt_Base::Crypt_Base() + * @param Integer $engine + * @access public + * @return Boolean */ - function _setupEngine() + function isValidEngine($engine) { - if (constant('CRYPT_' . $this->const_namespace . '_MODE') == CRYPT_MODE_INTERNAL) { - // No mcrypt support at all for rijndael - return; - } - - // The required mcrypt module name for the current $block_size of rijndael - $cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); - - // Determining the availibility/usability of $cipher_name_mcrypt - switch (true) { - case $this->key_size % 8: // mcrypt is not usable for 160/224-bit keys, only for 128/192/256-bit keys - case !in_array($cipher_name_mcrypt, mcrypt_list_algorithms()): // $cipher_name_mcrypt is not available for the current $block_size - $engine = CRYPT_MODE_INTERNAL; + switch ($engine) { + case CRYPT_ENGINE_OPENSSL: + if ($this->block_size != 16) { + return false; + } + $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_size << 3) . '-ecb'; + $this->cipher_name_openssl = 'aes-' . ($this->key_size << 3) . '-' . $this->_openssl_translate_mode(); break; - default: - $engine = CRYPT_MODE_MCRYPT; + case CRYPT_ENGINE_MCRYPT: + $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); + if ($this->key_size % 8) { // is it a 160/224-bit key? + // mcrypt is not usable for them, only for 128/192/256-bit keys + return false; + } } - if ($this->engine == $engine && $this->cipher_name_mcrypt == $cipher_name_mcrypt) { - // allready set, so we not unnecessary close $this->enmcrypt/demcrypt/ecb - return; - } - - // Set the $engine - $this->engine = $engine; - $this->cipher_name_mcrypt = $cipher_name_mcrypt; - - if ($this->enmcrypt) { - // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, - // (re)open them with the module named in $this->cipher_name_mcrypt - mcrypt_module_close($this->enmcrypt); - mcrypt_module_close($this->demcrypt); - $this->enmcrypt = null; - $this->demcrypt = null; - - if ($this->ecb) { - mcrypt_module_close($this->ecb); - $this->ecb = null; - } - } + return parent::isValidEngine($engine); } /** - * Setup the CRYPT_MODE_MCRYPT $engine + * Setup the CRYPT_ENGINE_MCRYPT $engine * * @see Crypt_Base::_setupMcrypt() * @access private @@ -863,16 +448,15 @@ class Crypt_Rijndael extends Crypt_Base */ function _encryptBlock($in) { - static $t0, $t1, $t2, $t3, $sbox; - if (!$t0) { - for ($i = 0; $i < 256; ++$i) { - $t0[] = (int)$this->t0[$i]; - $t1[] = (int)$this->t1[$i]; - $t2[] = (int)$this->t2[$i]; - $t3[] = (int)$this->t3[$i]; - $sbox[] = (int)$this->sbox[$i]; - } + static $tables; + if (empty($tables)) { + $tables = &$this->_getTables(); } + $t0 = $tables[0]; + $t1 = $tables[1]; + $t2 = $tables[2]; + $t3 = $tables[3]; + $sbox = $tables[4]; $state = array(); $words = unpack('N*', $in); @@ -883,9 +467,9 @@ class Crypt_Rijndael extends Crypt_Base $Nr = $this->Nr; // addRoundKey - $i = -1; + $wc = $Nb - 1; foreach ($words as $word) { - $state[] = $word ^ $w[0][++$i]; + $state[] = $word ^ $w[++$wc]; } // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - @@ -908,7 +492,7 @@ class Crypt_Rijndael extends Crypt_Base $t1[$state[$j] >> 16 & 0x000000FF] ^ $t2[$state[$k] >> 8 & 0x000000FF] ^ $t3[$state[$l] & 0x000000FF] ^ - $w[$round][$i]; + $w[++$wc]; ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; @@ -935,7 +519,7 @@ class Crypt_Rijndael extends Crypt_Base ($state[$j] & 0x00FF0000) ^ ($state[$k] & 0x0000FF00) ^ ($state[$l] & 0x000000FF) ^ - $w[$Nr][$i]; + $w[$i]; ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; @@ -965,16 +549,15 @@ class Crypt_Rijndael extends Crypt_Base */ function _decryptBlock($in) { - static $dt0, $dt1, $dt2, $dt3, $isbox; - if (!$dt0) { - for ($i = 0; $i < 256; ++$i) { - $dt0[] = (int)$this->dt0[$i]; - $dt1[] = (int)$this->dt1[$i]; - $dt2[] = (int)$this->dt2[$i]; - $dt3[] = (int)$this->dt3[$i]; - $isbox[] = (int)$this->isbox[$i]; - } + static $invtables; + if (empty($invtables)) { + $invtables = &$this->_getInvTables(); } + $dt0 = $invtables[0]; + $dt1 = $invtables[1]; + $dt2 = $invtables[2]; + $dt3 = $invtables[3]; + $isbox = $invtables[4]; $state = array(); $words = unpack('N*', $in); @@ -985,9 +568,9 @@ class Crypt_Rijndael extends Crypt_Base $Nr = $this->Nr; // addRoundKey - $i = -1; + $wc = $Nb - 1; foreach ($words as $word) { - $state[] = $word ^ $dw[$Nr][++$i]; + $state[] = $word ^ $dw[++$wc]; } $temp = array(); @@ -1002,7 +585,7 @@ class Crypt_Rijndael extends Crypt_Base $dt1[$state[$j] >> 16 & 0x000000FF] ^ $dt2[$state[$k] >> 8 & 0x000000FF] ^ $dt3[$state[$l] & 0x000000FF] ^ - $dw[$round][$i]; + $dw[++$wc]; ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; @@ -1023,10 +606,10 @@ class Crypt_Rijndael extends Crypt_Base ($state[$k] & 0x0000FF00) | ($state[$l] & 0x000000FF); - $temp[$i] = $dw[0][$i] ^ ($isbox[$word & 0x000000FF] | - ($isbox[$word >> 8 & 0x000000FF] << 8) | - ($isbox[$word >> 16 & 0x000000FF] << 16) | - ($isbox[$word >> 24 & 0x000000FF] << 24)); + $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] | + ($isbox[$word >> 8 & 0x000000FF] << 8) | + ($isbox[$word >> 16 & 0x000000FF] << 16) | + ($isbox[$word >> 24 & 0x000000FF] << 24)); ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; @@ -1107,7 +690,7 @@ class Crypt_Rijndael extends Crypt_Base // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; - } else if ($this->Nk > 6 && $i % $this->Nk == 4) { + } elseif ($this->Nk > 6 && $i % $this->Nk == 4) { $temp = $this->_subWord($temp); } $w[$i] = $w[$i - $this->Nk] ^ $temp; @@ -1120,6 +703,7 @@ class Crypt_Rijndael extends Crypt_Base // 1. Apply the Key Expansion. // 2. Apply InvMixColumn to all Round Keys except the first and the last one." // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" + list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables(); $temp = $this->w = $this->dw = array(); for ($i = $row = $col = 0; $i < $length; $i++, $col++) { if ($col == $this->Nb) { @@ -1130,10 +714,10 @@ class Crypt_Rijndael extends Crypt_Base $j = 0; while ($j < $this->Nb) { $dw = $this->_subWord($this->w[$row][$j]); - $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^ - $this->dt1[$dw >> 16 & 0x000000FF] ^ - $this->dt2[$dw >> 8 & 0x000000FF] ^ - $this->dt3[$dw & 0x000000FF]; + $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^ + $dt1[$dw >> 16 & 0x000000FF] ^ + $dt2[$dw >> 8 & 0x000000FF] ^ + $dt3[$dw & 0x000000FF]; $j++; } $this->dw[$row] = $temp; @@ -1147,20 +731,18 @@ class Crypt_Rijndael extends Crypt_Base $this->dw[$row] = $this->w[$row]; - // In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending) - if ($this->use_inline_crypt) { - $this->dw = array_reverse($this->dw); - $w = array_pop($this->w); - $dw = array_pop($this->dw); - foreach ($this->w as $r => $wr) { - foreach ($wr as $c => $wc) { - $w[] = $wc; - $dw[] = $this->dw[$r][$c]; - } + // Converting to 1-dim key arrays (both ascending) + $this->dw = array_reverse($this->dw); + $w = array_pop($this->w); + $dw = array_pop($this->dw); + foreach ($this->w as $r => $wr) { + foreach ($wr as $c => $wc) { + $w[] = $wc; + $dw[] = $this->dw[$r][$c]; } - $this->w = $w; - $this->dw = $dw; } + $this->w = $w; + $this->dw = $dw; } /** @@ -1171,7 +753,10 @@ class Crypt_Rijndael extends Crypt_Base */ function _subWord($word) { - $sbox = $this->sbox; + static $sbox; + if (empty($sbox)) { + list(,,,, $sbox) = $this->_getTables(); + } return $sbox[$word & 0x000000FF] | ($sbox[$word >> 8 & 0x000000FF] << 8) | @@ -1179,6 +764,179 @@ class Crypt_Rijndael extends Crypt_Base ($sbox[$word >> 24 & 0x000000FF] << 24); } + /** + * Provides the mixColumns and sboxes tables + * + * @see Crypt_Rijndael:_encryptBlock() + * @see Crypt_Rijndael:_setupInlineCrypt() + * @see Crypt_Rijndael:_subWord() + * @access private + * @return Array &$tables + */ + function &_getTables() + { + static $tables; + if (empty($tables)) { + // according to (section 5.2.1), + // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so + // those are the names we'll use. + $t3 = array_map('intval', array( + // with array_map('intval', ...) we ensure we have only int's and not + // some slower floats converted by php automatically on high values + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, + 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, + 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, + 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, + 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, + 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, + 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, + 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, + 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, + 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, + 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, + 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, + 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, + 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, + 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, + 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, + 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, + 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C + )); + + foreach ($t3 as $t3i) { + $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF); + $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF); + $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF); + } + + $tables = array( + // The Precomputed mixColumns tables t0 - t3 + $t0, + $t1, + $t2, + $t3, + // The SubByte S-Box + array( + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + ) + ); + } + return $tables; + } + + /** + * Provides the inverse mixColumns and inverse sboxes tables + * + * @see Crypt_Rijndael:_decryptBlock() + * @see Crypt_Rijndael:_setupInlineCrypt() + * @see Crypt_Rijndael:_setupKey() + * @access private + * @return Array &$tables + */ + function &_getInvTables() + { + static $tables; + if (empty($tables)) { + $dt3 = array_map('intval', array( + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, + 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, + 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, + 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, + 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, + 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, + 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, + 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, + 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, + 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, + 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, + 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, + 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, + 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, + 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, + 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, + 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, + 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, + 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, + 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, + 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, + 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 + )); + + foreach ($dt3 as $dt3i) { + $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF); + $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF); + $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF); + }; + + $tables = array( + // The Precomputed inverse mixColumns tables dt0 - dt3 + $dt0, + $dt1, + $dt2, + $dt3, + // The inverse SubByte S-Box + array( + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D + ) + ); + } + return $tables; + } + /** * Setup the performance-optimized function for de/encrypt() * @@ -1193,42 +951,50 @@ class Crypt_Rijndael extends Crypt_Base $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); - // The first 10 generated $lambda_functions will use the key-words hardcoded for better performance. - // For memory reason we limit those ultra-optimized functions. - // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array. - if (count($lambda_functions) < 10) { - $w = $this->w; - $dw = $this->dw; - $init_encrypt = ''; - $init_decrypt = ''; - } else { - for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { - $w[] = '$w[' . $i . ']'; - $dw[] = '$dw[' . $i . ']'; - } - $init_encrypt = '$w = $self->w;'; - $init_decrypt = '$dw = $self->dw;'; + // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. + // (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit) + // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one. + $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); + + // Generation of a uniqe hash for our generated code + $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}"; + if ($gen_hi_opt_code) { + $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); } - $code_hash = md5(str_pad("Crypt_Rijndael, {$this->mode}, {$this->block_size}, ", 32, "\0") . implode(',', $w)); - if (!isset($lambda_functions[$code_hash])) { + switch (true) { + case $gen_hi_opt_code: + // The hi-optimized $lambda_functions will use the key-words hardcoded for better performance. + $w = $this->w; + $dw = $this->dw; + $init_encrypt = ''; + $init_decrypt = ''; + break; + default: + for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { + $w[] = '$w[' . $i . ']'; + $dw[] = '$dw[' . $i . ']'; + } + $init_encrypt = '$w = $self->w;'; + $init_decrypt = '$dw = $self->dw;'; + } + $Nr = $this->Nr; $Nb = $this->Nb; $c = $this->c; // Generating encrypt code: $init_encrypt.= ' - static $t0, $t1, $t2, $t3, $sbox; - if (!$t0) { - for ($i = 0; $i < 256; ++$i) { - $t0[$i] = (int)$self->t0[$i]; - $t1[$i] = (int)$self->t1[$i]; - $t2[$i] = (int)$self->t2[$i]; - $t3[$i] = (int)$self->t3[$i]; - $sbox[$i] = (int)$self->sbox[$i]; - } + static $tables; + if (empty($tables)) { + $tables = &$self->_getTables(); } + $t0 = $tables[0]; + $t1 = $tables[1]; + $t2 = $tables[2]; + $t3 = $tables[3]; + $sbox = $tables[4]; '; $s = 'e'; @@ -1267,26 +1033,25 @@ class Crypt_Rijndael extends Crypt_Base $encrypt_block .= '$in = pack("N*"'."\n"; for ($i = 0; $i < $Nb; ++$i) { $encrypt_block.= ', - ($'.$e.$i .' & 0xFF000000) ^ - ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^ - ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^ - ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^ + ($'.$e.$i .' & '.((int)0xFF000000).') ^ + ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^ + ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^ + ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^ '.$w[$i]."\n"; } $encrypt_block .= ');'; // Generating decrypt code: $init_decrypt.= ' - static $dt0, $dt1, $dt2, $dt3, $isbox; - if (!$dt0) { - for ($i = 0; $i < 256; ++$i) { - $dt0[$i] = (int)$self->dt0[$i]; - $dt1[$i] = (int)$self->dt1[$i]; - $dt2[$i] = (int)$self->dt2[$i]; - $dt3[$i] = (int)$self->dt3[$i]; - $isbox[$i] = (int)$self->isbox[$i]; - } + static $invtables; + if (empty($invtables)) { + $invtables = &$self->_getInvTables(); } + $dt0 = $invtables[0]; + $dt1 = $invtables[1]; + $dt2 = $invtables[2]; + $dt3 = $invtables[3]; + $isbox = $invtables[4]; '; $s = 'e'; @@ -1325,10 +1090,10 @@ class Crypt_Rijndael extends Crypt_Base $decrypt_block .= '$in = pack("N*"'."\n"; for ($i = 0; $i < $Nb; ++$i) { $decrypt_block.= ', - ($'.$e.$i. ' & 0xFF000000) ^ - ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^ - ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^ - ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^ + ($'.$e.$i. ' & '.((int)0xFF000000).') ^ + ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^ + ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^ + ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^ '.$dw[$i]."\n"; } $decrypt_block .= ');'; diff --git a/Crypt/TripleDES.php b/Crypt/TripleDES.php index 175b3ac..f8e66d4 100644 --- a/Crypt/TripleDES.php +++ b/Crypt/TripleDES.php @@ -47,7 +47,7 @@ * @category Crypt * @package Crypt_TripleDES * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -59,19 +59,31 @@ if (!class_exists('Crypt_DES')) { include_once 'DES.php'; } +/**#@+ + * @access public + * @see Crypt_TripleDES::Crypt_TripleDES() + */ /** * Encrypt / decrypt using inner chaining * * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3). */ +define('CRYPT_MODE_3CBC', -2); +/** + * BC version of the above. + */ define('CRYPT_DES_MODE_3CBC', -2); - /** * Encrypt / decrypt using outer chaining * * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. */ -define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); +define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC); +/** + * BC version of the above. + */ +define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3); +/**#@-*/ /** * Pure-PHP implementation of Triple DES. @@ -186,20 +198,20 @@ class Crypt_TripleDES extends Crypt_DES * @param optional Integer $mode * @access public */ - function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) + function Crypt_TripleDES($mode = CRYPT_MODE_CBC) { switch ($mode) { // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC // and additional flag us internally as 3CBC case CRYPT_DES_MODE_3CBC: - parent::Crypt_Base(CRYPT_DES_MODE_CBC); + parent::Crypt_Base(CRYPT_MODE_CBC); $this->mode_3cbc = true; // This three $des'es will do the 3CBC work (if $key > 64bits) $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), + new Crypt_DES(CRYPT_MODE_CBC), + new Crypt_DES(CRYPT_MODE_CBC), + new Crypt_DES(CRYPT_MODE_CBC), ); // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects @@ -213,6 +225,27 @@ class Crypt_TripleDES extends Crypt_DES } } + /** + * Test for engine validity + * + * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() + * + * @see Crypt_Base::Crypt_Base() + * @param Integer $engine + * @access public + * @return Boolean + */ + function isValidEngine($engine) + { + if ($engine == CRYPT_ENGINE_OPENSSL) { + $this->cipher_name_openssl_ecb = 'des-ede3'; + $mode = $this->_openssl_translate_mode(); + $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode; + } + + return parent::isValidEngine($engine); + } + /** * Sets the initialization vector. (optional) * @@ -255,7 +288,7 @@ class Crypt_TripleDES extends Crypt_DES $key = str_pad(substr($key, 0, 24), 24, chr(0)); // 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 - //$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); } else { $key = str_pad($key, 8, chr(0)); } @@ -283,7 +316,7 @@ class Crypt_TripleDES extends Crypt_DES function encrypt($plaintext) { // parent::en/decrypt() is able to do all the work for all modes and keylengths, - // except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits + // except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits // if the key is smaller then 8, do what we'd normally do if ($this->mode_3cbc && strlen($this->key) > 8) { @@ -425,4 +458,24 @@ class Crypt_TripleDES extends Crypt_DES // setup our key parent::_setupKey(); } + + /** + * Sets the internal crypt engine + * + * @see Crypt_Base::Crypt_Base() + * @see Crypt_Base::setPreferredEngine() + * @param Integer $engine + * @access public + * @return Integer + */ + function setPreferredEngine($engine) + { + if ($this->mode_3cbc) { + $this->des[0]->setPreferredEngine($engine); + $this->des[1]->setPreferredEngine($engine); + $this->des[2]->setPreferredEngine($engine); + } + + return parent::setPreferredEngine($engine); + } } diff --git a/Crypt/Twofish.php b/Crypt/Twofish.php index 4099a01..e1aee53 100644 --- a/Crypt/Twofish.php +++ b/Crypt/Twofish.php @@ -48,7 +48,7 @@ * @package Crypt_Twofish * @author Jim Wigginton * @author Hans-Juergen Petrich - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -101,20 +101,6 @@ define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB); define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB); /**#@-*/ -/**#@+ - * @access private - * @see Crypt_Base::Crypt_Base() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_TWOFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT); -/**#@-*/ - /** * Pure-PHP implementation of Twofish. * @@ -618,7 +604,9 @@ class Crypt_Twofish extends Crypt_Base $u^= 0x7fffffff & ($t >> 1); // Add the modular polynomial on underflow. - if ($t & 0x01) $u^= 0xa6 ; + if ($t & 0x01) { + $u^= 0xa6 ; + } // Remove t * (a + 1/a) * (x^3 + x). $B^= ($u << 24) | ($u << 8); @@ -754,21 +742,19 @@ class Crypt_Twofish extends Crypt_Base $lambda_functions =& Crypt_Twofish::_getLambdaFunctions(); // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one. + // (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit) $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); - switch (true) { - case $gen_hi_opt_code: - $code_hash = md5(str_pad("Crypt_Twofish, {$this->mode}, ", 32, "\0") . $this->key); - break; - default: - $code_hash = "Crypt_Twofish, {$this->mode}"; + // Generation of a uniqe hash for our generated code + $code_hash = "Crypt_Twofish, {$this->mode}"; + if ($gen_hi_opt_code) { + $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); } if (!isset($lambda_functions[$code_hash])) { switch (true) { case $gen_hi_opt_code: $K = $this->K; - $init_crypt = ' static $S0, $S1, $S2, $S3; if (!$S0) { @@ -786,7 +772,6 @@ class Crypt_Twofish extends Crypt_Base for ($i = 0; $i < 40; ++$i) { $K[] = '$K_' . $i; } - $init_crypt = ' $S0 = $self->S0; $S1 = $self->S1; diff --git a/File/ANSI.php b/File/ANSI.php index ef2ccbe..2435d32 100644 --- a/File/ANSI.php +++ b/File/ANSI.php @@ -31,7 +31,7 @@ * @category File * @package File_ANSI * @author Jim Wigginton - * @copyright MMXII Jim Wigginton + * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -117,6 +117,22 @@ class File_ANSI */ var $old_y; + /** + * An empty attribute cell + * + * @var Object + * @access private + */ + var $base_attr_cell; + + /** + * The current attribute cell + * + * @var Object + * @access private + */ + var $attr_cell; + /** * An empty attribute row * @@ -141,62 +157,6 @@ class File_ANSI */ var $attrs; - /** - * The current foreground color - * - * @var String - * @access private - */ - var $foreground; - - /** - * The current background color - * - * @var String - * @access private - */ - var $background; - - /** - * Bold flag - * - * @var Boolean - * @access private - */ - var $bold; - - /** - * Underline flag - * - * @var Boolean - * @access private - */ - var $underline; - - /** - * Blink flag - * - * @var Boolean - * @access private - */ - var $blink; - - /** - * Reverse flag - * - * @var Boolean - * @access private - */ - var $reverse; - - /** - * Color flag - * - * @var Boolean - * @access private - */ - var $color; - /** * Current ANSI code * @@ -205,6 +165,14 @@ class File_ANSI */ var $ansi; + /** + * Tokenization + * + * @var Array + * @access private + */ + var $tokenization; + /** * Default Constructor. * @@ -213,6 +181,16 @@ class File_ANSI */ function File_ANSI() { + $attr_cell = new stdClass(); + $attr_cell->bold = false; + $attr_cell->underline = false; + $attr_cell->blink = false; + $attr_cell->background = 'black'; + $attr_cell->foreground = 'white'; + $attr_cell->reverse = false; + $this->base_attr_cell = clone($attr_cell); + $this->attr_cell = clone($attr_cell); + $this->setHistory(200); $this->setDimensions(80, 24); } @@ -232,17 +210,9 @@ class File_ANSI $this->max_y = $y - 1; $this->x = $this->y = 0; $this->history = $this->history_attrs = array(); - $this->attr_row = array_fill(0, $this->max_x + 1, ''); + $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell); $this->screen = array_fill(0, $this->max_y + 1, ''); $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row); - $this->foreground = 'white'; - $this->background = 'black'; - $this->bold = false; - $this->underline = false; - $this->blink = false; - $this->reverse = false; - $this->color = false; - $this->ansi = ''; } @@ -278,6 +248,7 @@ class File_ANSI */ function appendString($source) { + $this->tokenization = array(''); for ($i = 0; $i < strlen($source); $i++) { if (strlen($this->ansi)) { $this->ansi.= $source[$i]; @@ -294,6 +265,8 @@ class File_ANSI default: continue 2; } + $this->tokenization[] = $this->ansi; + $this->tokenization[] = ''; // http://ascii-table.com/ansi-escape-sequences-vt-100.php switch ($this->ansi) { case "\x1B[H": // Move cursor to upper left corner @@ -315,7 +288,7 @@ class File_ANSI case "\x1B[K": // Clear screen from cursor right $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x); - array_splice($this->attrs[$this->y], $this->x + 1); + array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell)); break; case "\x1B[2K": // Clear entire line $this->screen[$this->y] = str_repeat(' ', $this->x); @@ -323,6 +296,7 @@ class File_ANSI break; case "\x1B[?1h": // set cursor key to application case "\x1B[?25h": // show the cursor + case "\x1B(B": // set united states g0 character set break; case "\x1BE": // Move to next line $this->_newLine(); @@ -330,6 +304,10 @@ class File_ANSI break; default: switch (true) { + case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines + $this->old_y = $this->y; + $this->y+= $match[1]; + break; case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h $this->old_x = $this->x; $this->old_y = $this->y; @@ -338,65 +316,44 @@ class File_ANSI break; case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines $this->old_x = $this->x; - $x = $match[1] - 1; + $this->x+= $match[1]; + break; + case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines + $this->old_x = $this->x; + $this->x-= $match[1]; break; case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window break; case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes + $attr_cell = &$this->attr_cell; $mods = explode(';', $match[1]); foreach ($mods as $mod) { switch ($mod) { case 0: // Turn off character attributes - $this->attrs[$this->y][$this->x] = ''; - - if ($this->bold) $this->attrs[$this->y][$this->x].= ''; - if ($this->underline) $this->attrs[$this->y][$this->x].= ''; - if ($this->blink) $this->attrs[$this->y][$this->x].= ''; - if ($this->color) $this->attrs[$this->y][$this->x].= ''; - - if ($this->reverse) { - $temp = $this->background; - $this->background = $this->foreground; - $this->foreground = $temp; - } - - $this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false; + $attr_cell = clone($this->base_attr_cell); break; case 1: // Turn bold mode on - if (!$this->bold) { - $this->attrs[$this->y][$this->x] = ''; - $this->bold = true; - } + $attr_cell->bold = true; break; case 4: // Turn underline mode on - if (!$this->underline) { - $this->attrs[$this->y][$this->x] = ''; - $this->underline = true; - } + $attr_cell->underline = true; break; case 5: // Turn blinking mode on - if (!$this->blink) { - $this->attrs[$this->y][$this->x] = ''; - $this->blink = true; - } + $attr_cell->blink = true; break; case 7: // Turn reverse video on - $this->reverse = !$this->reverse; - $temp = $this->background; - $this->background = $this->foreground; - $this->foreground = $temp; - $this->attrs[$this->y][$this->x] = ''; - if ($this->color) { - $this->attrs[$this->y][$this->x] = '' . $this->attrs[$this->y][$this->x]; - } - $this->color = true; + $attr_cell->reverse = !$attr_cell->reverse; + $temp = $attr_cell->background; + $attr_cell->background = $attr_cell->foreground; + $attr_cell->foreground = $temp; break; default: // set colors - //$front = $this->reverse ? &$this->background : &$this->foreground; - $front = &$this->{ $this->reverse ? 'background' : 'foreground' }; - //$back = $this->reverse ? &$this->foreground : &$this->background; - $back = &$this->{ $this->reverse ? 'foreground' : 'background' }; + //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground; + $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' }; + //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background; + $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' }; switch ($mod) { + // @codingStandardsIgnoreStart case 30: $front = 'black'; break; case 31: $front = 'red'; break; case 32: $front = 'green'; break; @@ -414,30 +371,25 @@ class File_ANSI case 45: $back = 'magenta'; break; case 46: $back = 'cyan'; break; case 47: $back = 'white'; break; + // @codingStandardsIgnoreEnd default: - user_error('Unsupported attribute: ' . $mod); + //user_error('Unsupported attribute: ' . $mod); $this->ansi = ''; break 2; } - - unset($temp); - $this->attrs[$this->y][$this->x] = ''; - if ($this->color) { - $this->attrs[$this->y][$this->x] = '' . $this->attrs[$this->y][$this->x]; - } - $this->color = true; } } break; default: - user_error("{$this->ansi} unsupported\r\n"); + //user_error("{$this->ansi} is unsupported\r\n"); } } $this->ansi = ''; continue; } + $this->tokenization[count($this->tokenization) - 1].= $source[$i]; switch ($source[$i]) { case "\r": $this->x = 0; @@ -445,12 +397,32 @@ class File_ANSI case "\n": $this->_newLine(); break; + case "\x08": // backspace + if ($this->x) { + $this->x--; + $this->attrs[$this->y][$this->x] = clone($this->base_attr_cell); + $this->screen[$this->y] = substr_replace( + $this->screen[$this->y], + $source[$i], + $this->x, + 1 + ); + } + break; case "\x0F": // shift break; case "\x1B": // start ANSI escape code + $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1); + //if (!strlen($this->tokenization[count($this->tokenization) - 1])) { + // array_pop($this->tokenization); + //} $this->ansi.= "\x1B"; break; default: + $this->attrs[$this->y][$this->x] = clone($this->attr_cell); + if ($this->x > strlen($this->screen[$this->y])) { + $this->screen[$this->y] = str_repeat(' ', $this->x); + } $this->screen[$this->y] = substr_replace( $this->screen[$this->y], $source[$i], @@ -498,6 +470,63 @@ class File_ANSI $this->y++; } + /** + * Returns the current coordinate without preformating + * + * @access private + * @return String + */ + function _processCoordinate($last_attr, $cur_attr, $char) + { + $output = ''; + + if ($last_attr != $cur_attr) { + $close = $open = ''; + if ($last_attr->foreground != $cur_attr->foreground) { + if ($cur_attr->foreground != 'white') { + $open.= ''; + } + if ($last_attr->foreground != 'white') { + $close = '' . $close; + } + } + if ($last_attr->background != $cur_attr->background) { + if ($cur_attr->background != 'black') { + $open.= ''; + } + if ($last_attr->background != 'black') { + $close = '' . $close; + } + } + if ($last_attr->bold != $cur_attr->bold) { + if ($cur_attr->bold) { + $open.= ''; + } else { + $close = '' . $close; + } + } + if ($last_attr->underline != $cur_attr->underline) { + if ($cur_attr->underline) { + $open.= ''; + } else { + $close = '' . $close; + } + } + if ($last_attr->blink != $cur_attr->blink) { + if ($cur_attr->blink) { + $open.= ''; + } else { + $close = '' . $close; + } + } + $output.= $close . $open; + } + + $output.= htmlspecialchars($char); + + return $output; + } + /** * Returns the current screen without preformating * @@ -507,17 +536,18 @@ class File_ANSI function _getScreen() { $output = ''; + $last_attr = $this->base_attr_cell; for ($i = 0; $i <= $this->max_y; $i++) { - for ($j = 0; $j <= $this->max_x + 1; $j++) { - if (isset($this->attrs[$i][$j])) { - $output.= $this->attrs[$i][$j]; - } - if (isset($this->screen[$i][$j])) { - $output.= htmlspecialchars($this->screen[$i][$j]); - } + for ($j = 0; $j <= $this->max_x; $j++) { + $cur_attr = $this->attrs[$i][$j]; + $output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : ''); + $last_attr = $this->attrs[$i][$j]; } $output.= "\r\n"; } + $output = substr($output, 0, -2); + // close any remaining open tags + $output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, ''); return rtrim($output); } @@ -529,7 +559,7 @@ class File_ANSI */ function getScreen() { - return '
' . $this->_getScreen() . '
'; + return '
' . $this->_getScreen() . '
'; } /** @@ -541,19 +571,20 @@ class File_ANSI function getHistory() { $scrollback = ''; + $last_attr = $this->base_attr_cell; for ($i = 0; $i < count($this->history); $i++) { for ($j = 0; $j <= $this->max_x + 1; $j++) { - if (isset($this->history_attrs[$i][$j])) { - $scrollback.= $this->history_attrs[$i][$j]; - } - if (isset($this->history[$i][$j])) { - $scrollback.= htmlspecialchars($this->history[$i][$j]); - } + $cur_attr = $this->history_attrs[$i][$j]; + $scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : ''); + $last_attr = $this->history_attrs[$i][$j]; } $scrollback.= "\r\n"; } + $base_attr_cell = $this->base_attr_cell; + $this->base_attr_cell = $last_attr; $scrollback.= $this->_getScreen(); + $this->base_attr_cell = $base_attr_cell; - return '
' . $scrollback . '
'; + return '
' . $scrollback . '
'; } } diff --git a/File/ASN1.php b/File/ASN1.php index c12a8d2..95fc101 100644 --- a/File/ASN1.php +++ b/File/ASN1.php @@ -34,7 +34,7 @@ * @category File * @package File_ASN1 * @author Jim Wigginton - * @copyright MMXII Jim Wigginton + * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -306,17 +306,17 @@ class File_ASN1 $tag <<= 7; $tag |= ord($this->_string_shift($encoded)) & 0x7F; $start++; - } while ( $loop ); + } while ($loop); } // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13 $length = ord($this->_string_shift($encoded)); $start++; - if ( $length == 0x80 ) { // indefinite length + if ($length == 0x80) { // indefinite length // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all // immediately available." -- paragraph 8.1.3.2.c $length = strlen($encoded); - } elseif ( $length & 0x80 ) { // definite length, long form + } elseif ($length & 0x80) { // definite length, long form // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only // support it up to four. $length&= 0x7F; @@ -329,6 +329,10 @@ class File_ASN1 $current+= array('headerlength' => 2); } + if ($length > strlen($encoded)) { + return false; + } + $content = $this->_string_shift($encoded, $length); // at this point $length can be overwritten. it's only accurate for definite length things as is @@ -347,19 +351,38 @@ class File_ASN1 case FILE_ASN1_CLASS_APPLICATION: case FILE_ASN1_CLASS_PRIVATE: case FILE_ASN1_CLASS_CONTEXT_SPECIFIC: - $newcontent = $this->_decode_ber($content, $start); - $length = $newcontent['length']; - if (substr($content, $length, 2) == "\0\0") { - $length+= 2; + if (!$constructed) { + return array( + 'type' => $class, + 'constant' => $tag, + 'content' => $content, + 'length' => $length + $start - $current['start'] + ); } - $start+= $length; + $newcontent = array(); + $remainingLength = $length; + while ($remainingLength > 0) { + $temp = $this->_decode_ber($content, $start); + $length = $temp['length']; + // end-of-content octets - see paragraph 8.1.5 + if (substr($content, $length, 2) == "\0\0") { + $length+= 2; + $start+= $length; + $newcontent[] = $temp; + break; + } + $start+= $length; + $remainingLength-= $length; + $newcontent[] = $temp; + $this->_string_shift($content, $length); + } return array( 'type' => $class, 'constant' => $tag, // the array encapsulation is for BC with the old format - 'content' => array($newcontent), + 'content' => $newcontent, // the only time when $content['headerlength'] isn't defined is when the length is indefinite. // the absence of $content['headerlength'] is how we know if something is indefinite or not. // technically, it could be defined to be 2 and then another indicator could be used but whatever. @@ -874,7 +897,7 @@ class File_ASN1 } foreach ($mapping['children'] as $key => $child) { - if (!isset($source[$key])) { + if (!array_key_exists($key, $source)) { if (!isset($child['optional'])) { return false; } @@ -1065,7 +1088,7 @@ class File_ASN1 if ($outtype !== false) { return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special); } - } + } $filters = $this->filters; foreach ($loc as $part) { diff --git a/File/X509.php b/File/X509.php index 1d07f67..24e223b 100644 --- a/File/X509.php +++ b/File/X509.php @@ -37,7 +37,7 @@ * @category File * @package File_X509 * @author Jim Wigginton - * @copyright MMXII Jim Wigginton + * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -1505,6 +1505,16 @@ class File_X509 case 'rsaEncryption': $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))); + /* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier." + -- https://tools.ietf.org/html/rfc3279#section-2.3.1 + + given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank, + it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever. + */ + $cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null; + // https://tools.ietf.org/html/rfc3279#section-2.2.1 + $cert['signatureAlgorithm']['parameters'] = null; + $cert['tbsCertificate']['signature']['parameters'] = null; } } @@ -1589,7 +1599,7 @@ class File_X509 } } } - } elseif ($map) { + } else { $value = base64_encode($value); } } @@ -1612,6 +1622,10 @@ class File_X509 if (is_array($extensions)) { $size = count($extensions); for ($i = 0; $i < $size; $i++) { + if (is_object($extensions[$i]) && strtolower(get_class($extensions[$i])) == 'file_asn1_element') { + continue; + } + $id = $extensions[$i]['extnId']; $value = &$extensions[$i]['extnValue']; @@ -2509,7 +2523,7 @@ class File_X509 $asn1->loadFilters($filters); $result = ''; foreach ($dn['rdnSequence'] as $rdn) { - foreach ($rdn as $i=>$attr) { + foreach ($rdn as $i => $attr) { $attr = &$rdn[$i]; if (is_array($attr['value'])) { foreach ($attr['value'] as $type => $v) { @@ -2576,7 +2590,7 @@ class File_X509 break; default: $delim = '/'; - $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '='; + $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '='; } if (!$start) { @@ -2733,7 +2747,7 @@ class File_X509 break; } } - foreach ($chain as $key=>$value) { + foreach ($chain as $key => $value) { $chain[$key] = new File_X509(); $chain[$key]->loadX509($value); } @@ -2917,7 +2931,7 @@ class File_X509 switch (true) { case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')): - case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']); + case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']): break; default: switch ($algorithm) { @@ -3044,7 +3058,7 @@ class File_X509 $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm'); switch (true) { case !$algorithm: - case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']); + case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']): break; default: switch ($algorithm) { @@ -3198,9 +3212,9 @@ class File_X509 { $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this if ($year < 2050) { - return array('utcTime' => $date); + return array('utcTime' => $date); } else { - return array('generalTime' => $date); + return array('generalTime' => $date); } } @@ -3254,7 +3268,7 @@ class File_X509 if (isset($subject->domains)) { $this->removeExtension('id-ce-subjectAltName'); } - } else if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) { + } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) { return false; } else { if (!isset($subject->publicKey)) { @@ -3263,7 +3277,21 @@ class File_X509 $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year')); - $serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new Math_BigInteger(); + if (!empty($this->serialNumber)) { + $serialNumber = $this->serialNumber; + } else { + if (!function_exists('crypt_random_string')) { + include_once 'Crypt/Random.php'; + } + /* "The serial number MUST be a positive integer" + "Conforming CAs MUST NOT use serialNumber values longer than 20 octets." + -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2 + + for the integer to be positive the leading bit needs to be 0 hence the + application of a bitmap + */ + $serialNumber = new Math_BigInteger(crypt_random_string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256); + } $this->currentCert = array( 'tbsCertificate' => @@ -3279,8 +3307,8 @@ class File_X509 'subject' => $subject->dn, 'subjectPublicKeyInfo' => $subjectPublicKey ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later + 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), + 'signature' => false // this is going to be overwritten later ); // Copy extensions from CSR. @@ -3301,8 +3329,7 @@ class File_X509 // ) //), 'keyIdentifier' => $issuer->currentKeyIdentifier - ) - ); + )); //$extensions = &$this->currentCert['tbsCertificate']['extensions']; //if (isset($issuer->serialNumber)) { // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; @@ -3345,7 +3372,8 @@ class File_X509 $keyUsage = array(); } - $this->setExtension('id-ce-keyUsage', + $this->setExtension( + 'id-ce-keyUsage', array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign')))) ); @@ -3354,8 +3382,11 @@ class File_X509 $basicConstraints = array(); } - $this->setExtension('id-ce-basicConstraints', - array_unique(array_merge(array('cA' => true), $basicConstraints)), true); + $this->setExtension( + 'id-ce-basicConstraints', + array_unique(array_merge(array('cA' => true), $basicConstraints)), + true + ); if (!isset($subject->currentKeyIdentifier)) { $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false); @@ -3415,8 +3446,8 @@ class File_X509 'subject' => $this->dn, 'subjectPKInfo' => $publicKey ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later + 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), + 'signature' => false // this is going to be overwritten later ); } @@ -3480,8 +3511,8 @@ class File_X509 // crypt_random_string(8) & str_repeat("\x7F", 8) 'challenge' => !empty($this->challenge) ? $this->challenge : '' ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later + 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), + 'signature' => false // this is going to be overwritten later ); } @@ -3533,8 +3564,8 @@ class File_X509 'issuer' => false, // this is going to be overwritten later 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate() ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later + 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), + 'signature' => false // this is going to be overwritten later ); } @@ -3552,6 +3583,11 @@ class File_X509 $crlNumber = $this->serialNumber; } else { $crlNumber = $this->getExtension('id-ce-cRLNumber'); + // "The CRL number is a non-critical CRL extension that conveys a + // monotonically increasing sequence number for a given CRL scope and + // CRL issuer. This extension allows users to easily determine when a + // particular CRL supersedes another CRL." + // -- https://tools.ietf.org/html/rfc5280#section-5.2.3 $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null; } @@ -3590,8 +3626,7 @@ class File_X509 // ) //), 'keyIdentifier' => $issuer->currentKeyIdentifier - ) - ); + )); //$extensions = &$tbsCertList['crlExtensions']; //if (isset($issuer->serialNumber)) { // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; @@ -4124,7 +4159,7 @@ class File_X509 case $disposition == FILE_X509_ATTR_APPEND: $last = $key; break; - case $disposition >= $n; + case $disposition >= $n: $disposition -= $n; break; default: @@ -4382,7 +4417,6 @@ class File_X509 if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) { - if (!empty($date)) { $rclist[$i]['revocationDate'] = $this->_timeField($date); } @@ -4500,7 +4534,7 @@ class File_X509 if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) { if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); + return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); } } diff --git a/Math/BigInteger.php b/Math/BigInteger.php index 3894ae1..cc1e182 100644 --- a/Math/BigInteger.php +++ b/Math/BigInteger.php @@ -63,7 +63,7 @@ * @category Math * @package Math_BigInteger * @author Jim Wigginton - * @copyright MMVI Jim Wigginton + * @copyright 2006 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ @@ -253,7 +253,7 @@ class Math_BigInteger */ function Math_BigInteger($x = 0, $base = 10) { - if ( !defined('MATH_BIGINTEGER_MODE') ) { + if (!defined('MATH_BIGINTEGER_MODE')) { switch (true) { case extension_loaded('gmp'): define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP); @@ -278,7 +278,14 @@ class Math_BigInteger $versions = array(); if (!empty($matches[1])) { for ($i = 0; $i < count($matches[1]); $i++) { - $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); + + // Remove letter part in OpenSSL version + if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { + $versions[$matches[1][$i]] = $fullVersion; + } else { + $versions[$matches[1][$i]] = $m[0]; + } } } @@ -327,11 +334,14 @@ class Math_BigInteger } } - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: - if (is_resource($x) && get_resource_type($x) == 'GMP integer') { - $this->value = $x; - return; + switch (true) { + case is_resource($x) && get_resource_type($x) == 'GMP integer': + // PHP 5.6 switched GMP from using resources to objects + case is_object($x) && get_class($x) == 'GMP': + $this->value = $x; + return; } $this->value = gmp_init(0); break; @@ -354,8 +364,8 @@ class Math_BigInteger $x = ~$x; $this->is_negative = true; } - case 256: - switch ( MATH_BIGINTEGER_MODE ) { + case 256: + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $sign = $this->is_negative ? '-' : ''; $this->value = gmp_init($sign . '0x' . bin2hex($x)); @@ -391,7 +401,7 @@ class Math_BigInteger $this->value = $temp->value; } break; - case 16: + case 16: case -16: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; @@ -406,7 +416,7 @@ class Math_BigInteger $x = bin2hex(~pack('H*', $x)); } - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = $this->is_negative ? '-0x' . $x : '0x' . $x; $this->value = gmp_init($temp); @@ -429,14 +439,14 @@ class Math_BigInteger $this->value = $temp->value; } break; - case 10: + case 10: case -10: // (?value = gmp_init($x); break; @@ -466,7 +476,7 @@ class Math_BigInteger $this->value = $temp->value; } break; - case 2: // base-2 support originally implemented by Lluis Pamies - thanks! + case 2: // base-2 support originally implemented by Lluis Pamies - thanks! case -2: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; @@ -541,7 +551,7 @@ class Math_BigInteger return $comparison < 0 ? ~$bytes : $bytes; } - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (gmp_cmp($this->value, gmp_init(0)) == 0) { return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; @@ -682,7 +692,7 @@ class Math_BigInteger */ function toString() { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_strval($this->value); case MATH_BIGINTEGER_MODE_BCMATH: @@ -839,7 +849,7 @@ class Math_BigInteger */ function add($y) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_add($this->value, $y->value); @@ -881,7 +891,7 @@ class Math_BigInteger MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => $y_negative ); - } else if ($y_size == 0) { + } elseif ($y_size == 0) { return array( MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative @@ -889,8 +899,8 @@ class Math_BigInteger } // subtract, if appropriate - if ( $x_negative != $y_negative ) { - if ( $x_value == $y_value ) { + if ($x_negative != $y_negative) { + if ($x_value == $y_value) { return array( MATH_BIGINTEGER_VALUE => array(), MATH_BIGINTEGER_SIGN => false @@ -912,7 +922,7 @@ class Math_BigInteger $value = $x_value; } - $value[] = 0; // just in case the carry adds an extra digit + $value[count($value)] = 0; // just in case the carry adds an extra digit $carry = 0; for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { @@ -970,7 +980,7 @@ class Math_BigInteger */ function subtract($y) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_sub($this->value, $y->value); @@ -1012,7 +1022,7 @@ class Math_BigInteger MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => !$y_negative ); - } else if ($y_size == 0) { + } elseif ($y_size == 0) { return array( MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative @@ -1020,7 +1030,7 @@ class Math_BigInteger } // add, if appropriate (ie. -$x - +$y or +$x - -$y) - if ( $x_negative != $y_negative ) { + if ($x_negative != $y_negative) { $temp = $this->_add($x_value, false, $y_value, false); $temp[MATH_BIGINTEGER_SIGN] = $x_negative; @@ -1029,7 +1039,7 @@ class Math_BigInteger $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative); - if ( !$diff ) { + if (!$diff) { return array( MATH_BIGINTEGER_VALUE => array(), MATH_BIGINTEGER_SIGN => false @@ -1037,7 +1047,7 @@ class Math_BigInteger } // switch $x and $y around, if appropriate. - if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) { + if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; @@ -1105,7 +1115,7 @@ class Math_BigInteger */ function multiply($x) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_mul($this->value, $x->value); @@ -1149,7 +1159,7 @@ class Math_BigInteger $x_length = count($x_value); $y_length = count($y_value); - if ( !$x_length || !$y_length ) { // a 0 is being multiplied + if (!$x_length || !$y_length) { // a 0 is being multiplied return array( MATH_BIGINTEGER_VALUE => array(), MATH_BIGINTEGER_SIGN => false @@ -1179,11 +1189,11 @@ class Math_BigInteger $x_length = count($x_value); $y_length = count($y_value); - if ( !$x_length || !$y_length ) { // a 0 is being multiplied + if (!$x_length || !$y_length) { // a 0 is being multiplied return array(); } - if ( $x_length < $y_length ) { + if ($x_length < $y_length) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; @@ -1296,7 +1306,7 @@ class Math_BigInteger */ function _baseSquare($value) { - if ( empty($value) ) { + if (empty($value)) { return array(); } $square_value = $this->_array_repeat(0, 2 * count($value)); @@ -1392,7 +1402,7 @@ class Math_BigInteger */ function divide($y) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $quotient = new Math_BigInteger(); $remainder = new Math_BigInteger(); @@ -1429,7 +1439,7 @@ class Math_BigInteger } static $zero; - if ( !isset($zero) ) { + if (!isset($zero)) { $zero = new Math_BigInteger(); } @@ -1443,16 +1453,16 @@ class Math_BigInteger $diff = $x->compare($y); - if ( !$diff ) { + if (!$diff) { $temp = new Math_BigInteger(); $temp->value = array(1); $temp->is_negative = $x_sign != $y_sign; return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger())); } - if ( $diff < 0 ) { + if ($diff < 0) { // if $x is negative, "add" $y. - if ( $x_sign ) { + if ($x_sign) { $x = $y->subtract($x); } return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x)); @@ -1486,7 +1496,7 @@ class Math_BigInteger // $temp = $y << ($x_max - $y_max-1) in base 2**26 $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value); - while ( $x->compare($temp) >= 0 ) { + while ($x->compare($temp) >= 0) { // calculate the "common residue" ++$quotient_value[$x_max - $y_max]; $x = $x->subtract($temp); @@ -1522,7 +1532,7 @@ class Math_BigInteger $rhs_value = array($x_window[2], $x_window[1], $x_window[0]); - while ( $lhs->compare($rhs) > 0 ) { + while ($lhs->compare($rhs) > 0) { --$quotient_value[$q_index]; $lhs->value = array($quotient_value[$q_index]); @@ -1553,7 +1563,7 @@ class Math_BigInteger $quotient->is_negative = $x_sign != $y_sign; // calculate the "common residue", if appropriate - if ( $x_sign ) { + if ($x_sign) { $y->_rshift($shift); $x = $y->subtract($x); } @@ -1642,7 +1652,7 @@ class Math_BigInteger return $this->_normalize($temp->modPow($e, $n)); } - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) { + if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP) { $temp = new Math_BigInteger(); $temp->value = gmp_powm($this->value, $e->value, $n->value); @@ -1665,17 +1675,23 @@ class Math_BigInteger 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent']) ); - $RSAPublicKey = pack('Ca*a*a*', - 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])), - $components['modulus'], $components['publicExponent'] + $RSAPublicKey = pack( + 'Ca*a*a*', + 48, + $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])), + $components['modulus'], + $components['publicExponent'] ); $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $RSAPublicKey = chr(0) . $RSAPublicKey; $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey; - $encapsulated = pack('Ca*a*', - 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey + $encapsulated = pack( + 'Ca*a*', + 48, + $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), + $rsaOID . $RSAPublicKey ); $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . @@ -1689,25 +1705,25 @@ class Math_BigInteger } } - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $temp = new Math_BigInteger(); $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); return $this->_normalize($temp); } - if ( empty($e->value) ) { + if (empty($e->value)) { $temp = new Math_BigInteger(); $temp->value = array(1); return $this->_normalize($temp); } - if ( $e->value == array(1) ) { + if ($e->value == array(1)) { list(, $temp) = $this->divide($n); return $this->_normalize($temp); } - if ( $e->value == array(2) ) { + if ($e->value == array(2)) { $temp = new Math_BigInteger(); $temp->value = $this->_square($this->value); list(, $temp) = $temp->divide($n); @@ -1722,14 +1738,14 @@ class Math_BigInteger // made uncallable // is the modulo odd? - if ( $n->value[0] & 1 ) { + if ($n->value[0] & 1) { return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); } // if it's not, it's even // find the lowest set bit (eg. the max pow of 2 that divides $n) for ($i = 0; $i < count($n->value); ++$i) { - if ( $n->value[$i] ) { + if ($n->value[$i]) { $temp = decbin($n->value[$i]); $j = strlen($temp) - strrpos($temp, '1') - 1; $j+= 26 * $i; @@ -1807,7 +1823,8 @@ class Math_BigInteger // calculate the appropriate window size. // $window_size == 3 if $window_ranges is between 25 and 81, for example. - for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); + for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i) { + } $n_value = $n->value; @@ -1827,13 +1844,13 @@ class Math_BigInteger $result = array(1); $result = $this->_prepareReduce($result, $n_value, $mode); - for ($i = 0; $i < $e_length; ) { - if ( !$e_bits[$i] ) { + for ($i = 0; $i < $e_length;) { + if (!$e_bits[$i]) { $result = $this->_squareReduce($result, $n_value, $mode); ++$i; } else { for ($j = $window_size - 1; $j > 0; --$j) { - if ( !empty($e_bits[$i + $j]) ) { + if (!empty($e_bits[$i + $j])) { break; } } @@ -2017,7 +2034,7 @@ class Math_BigInteger // n = 2 * m.length - if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m; @@ -2106,7 +2123,7 @@ class Math_BigInteger return $temp->value; } - if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $n; $lhs = new Math_BigInteger(); @@ -2134,7 +2151,7 @@ class Math_BigInteger if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { $corrector_value = $this->_array_repeat(0, $n_length + 1); - $corrector_value[] = 1; + $corrector_value[count($corrector_value)] = 1; $result = $this->_add($result, false, $corrector_value, false); $result = $result[MATH_BIGINTEGER_VALUE]; } @@ -2167,14 +2184,14 @@ class Math_BigInteger $x_length = count($x_value); $y_length = count($y_value); - if ( !$x_length || !$y_length ) { // a 0 is being multiplied + if (!$x_length || !$y_length) { // a 0 is being multiplied return array( MATH_BIGINTEGER_VALUE => array(), MATH_BIGINTEGER_SIGN => false ); } - if ( $x_length < $y_length ) { + if ($x_length < $y_length) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; @@ -2248,7 +2265,7 @@ class Math_BigInteger MATH_BIGINTEGER_DATA => array() ); - if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $x; $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n); @@ -2304,7 +2321,7 @@ class Math_BigInteger MATH_BIGINTEGER_DATA => array() ); - if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m; $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m); @@ -2419,7 +2436,7 @@ class Math_BigInteger */ function modInverse($n) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_invert($this->value, $n->value); @@ -2485,7 +2502,7 @@ class Math_BigInteger */ function extendedGCD($n) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: extract(gmp_gcdext($this->value, $n->value)); @@ -2535,7 +2552,7 @@ class Math_BigInteger $g = new Math_BigInteger(); $g->value = array(1); - while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) { + while (!(($x->value[0] & 1)|| ($y->value[0] & 1))) { $x->_rshift(1); $y->_rshift(1); $g->_lshift(1); @@ -2552,10 +2569,10 @@ class Math_BigInteger $a->value = $d->value = $g->value = array(1); $b->value = $c->value = array(); - while ( !empty($u->value) ) { - while ( !($u->value[0] & 1) ) { + while (!empty($u->value)) { + while (!($u->value[0] & 1)) { $u->_rshift(1); - if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) { + if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) { $a = $a->add($y); $b = $b->subtract($x); } @@ -2563,9 +2580,9 @@ class Math_BigInteger $b->_rshift(1); } - while ( !($v->value[0] & 1) ) { + while (!($v->value[0] & 1)) { $v->_rshift(1); - if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) { + if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) { $c = $c->add($y); $d = $d->subtract($x); } @@ -2630,7 +2647,7 @@ class Math_BigInteger { $temp = new Math_BigInteger(); - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp->value = gmp_abs($this->value); break; @@ -2664,7 +2681,7 @@ class Math_BigInteger */ function compare($y) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_cmp($this->value, $y->value); case MATH_BIGINTEGER_MODE_BCMATH: @@ -2687,13 +2704,13 @@ class Math_BigInteger */ function _compare($x_value, $x_negative, $y_value, $y_negative) { - if ( $x_negative != $y_negative ) { + if ($x_negative != $y_negative) { return ( !$x_negative && $y_negative ) ? 1 : -1; } $result = $x_negative ? -1 : 1; - if ( count($x_value) != count($y_value) ) { + if (count($x_value) != count($y_value)) { return ( count($x_value) > count($y_value) ) ? $result : -$result; } $size = max(count($x_value), count($y_value)); @@ -2722,7 +2739,7 @@ class Math_BigInteger */ function equals($x) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_cmp($this->value, $x->value) == 0; default: @@ -2742,7 +2759,7 @@ class Math_BigInteger function setPrecision($bits) { $this->precision = $bits; - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) { + if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH) { $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256); } else { $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0)); @@ -2762,7 +2779,7 @@ class Math_BigInteger */ function bitwise_and($x) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_and($this->value, $x->value); @@ -2803,7 +2820,7 @@ class Math_BigInteger */ function bitwise_or($x) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_or($this->value, $x->value); @@ -2843,7 +2860,7 @@ class Math_BigInteger */ function bitwise_xor($x) { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_xor($this->value, $x->value); @@ -2923,7 +2940,7 @@ class Math_BigInteger { $temp = new Math_BigInteger(); - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: static $two; @@ -2961,7 +2978,7 @@ class Math_BigInteger { $temp = new Math_BigInteger(); - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: static $two; @@ -3000,7 +3017,7 @@ class Math_BigInteger if ($this->precision > 0) { $precision = $this->precision; - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $mask = $this->bitmask->subtract(new Math_BigInteger(1)); $mask = $mask->toBytes(); } else { @@ -3008,7 +3025,8 @@ class Math_BigInteger } } else { $temp = ord($bits[0]); - for ($i = 0; $temp >> $i; ++$i); + for ($i = 0; $temp >> $i; ++$i) { + } $precision = 8 * strlen($bits) - 8 + $i; $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); } @@ -3119,7 +3137,7 @@ class Math_BigInteger if (!$compare) { return $this->_normalize($min); - } else if ($compare < 0) { + } elseif ($compare < 0) { // if $min is bigger then $max, swap $min and $max $temp = $max; $max = $min; @@ -3200,7 +3218,7 @@ class Math_BigInteger if (!$compare) { return $min->isPrime() ? $min : false; - } else if ($compare < 0) { + } elseif ($compare < 0) { // if $min is bigger then $max, swap $min and $max $temp = $max; $max = $min; @@ -3218,7 +3236,7 @@ class Math_BigInteger $x = $this->random($min, $max); // gmp_nextprime() requires PHP 5 >= 5.2.0 per . - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { + if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime')) { $p = new Math_BigInteger(); $p->value = gmp_nextprime($x->value); @@ -3284,7 +3302,7 @@ class Math_BigInteger */ function _make_odd() { - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: gmp_setbit($this->value, 0); break; @@ -3336,7 +3354,7 @@ class Math_BigInteger // ie. gmp_testbit($this, 0) // ie. isEven() or !isOdd() - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_prob_prime($this->value, $t) != 0; case MATH_BIGINTEGER_MODE_BCMATH: @@ -3373,7 +3391,7 @@ class Math_BigInteger 953, 967, 971, 977, 983, 991, 997 ); - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { + if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { for ($i = 0; $i < count($primes); ++$i) { $primes[$i] = new Math_BigInteger($primes[$i]); } @@ -3389,7 +3407,7 @@ class Math_BigInteger } // see HAC 4.4.1 "Random search for probable primes" - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { + if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { foreach ($primes as $prime) { list(, $r) = $this->divide($prime); if ($r->equals($zero)) { @@ -3413,7 +3431,7 @@ class Math_BigInteger $r = $n_1->copy(); $r_value = $r->value; // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { + if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $s = 0; // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier while ($r->value[strlen($r->value) - 1] % 2 == 0) { @@ -3423,7 +3441,8 @@ class Math_BigInteger } else { for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { $temp = ~$r_value[$i] & 0xFFFFFF; - for ($j = 1; ($temp >> $j) & 1; ++$j); + for ($j = 1; ($temp >> $j) & 1; ++$j) { + } if ($j != 25) { break; } @@ -3462,7 +3481,7 @@ class Math_BigInteger */ function _lshift($shift) { - if ( $shift == 0 ) { + if ($shift == 0) { return; } @@ -3478,8 +3497,8 @@ class Math_BigInteger $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL); } - if ( $carry ) { - $this->value[] = $carry; + if ($carry) { + $this->value[count($this->value)] = $carry; } while ($num_digits--) { @@ -3506,7 +3525,7 @@ class Math_BigInteger $carry_shift = MATH_BIGINTEGER_BASE - $shift; $carry_mask = (1 << $shift) - 1; - if ( $num_digits ) { + if ($num_digits) { $this->value = array_slice($this->value, $num_digits); } @@ -3536,7 +3555,7 @@ class Math_BigInteger $result->precision = $this->precision; $result->bitmask = $this->bitmask; - switch ( MATH_BIGINTEGER_MODE ) { + switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (!empty($result->bitmask->value)) { $result->value = gmp_and($result->value, $result->bitmask->value); @@ -3553,7 +3572,7 @@ class Math_BigInteger $value = &$result->value; - if ( !count($value) ) { + if (!count($value)) { return $result; } @@ -3583,7 +3602,7 @@ class Math_BigInteger function _trim($value) { for ($i = count($value) - 1; $i >= 0; --$i) { - if ( $value[$i] ) { + if ($value[$i]) { break; } unset($value[$i]); diff --git a/Net/SCP.php b/Net/SCP.php index 2668164..faebc4b 100644 --- a/Net/SCP.php +++ b/Net/SCP.php @@ -17,7 +17,7 @@ * if (!$ssh->login('username', 'password')) { * exit('bad login'); * } - + * * $scp = new Net_SCP($ssh); * $scp->put('abcd', str_repeat('x', 1024*1024)); * ?> @@ -44,7 +44,7 @@ * @category Net * @package Net_SCP * @author Jim Wigginton - * @copyright MMX Jim Wigginton + * @copyright 2010 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -129,7 +129,7 @@ class Net_SCP } switch (strtolower(get_class($ssh))) { - case'net_ssh2': + case 'net_ssh2': $this->mode = NET_SCP_SSH2; break; case 'net_ssh1': @@ -170,7 +170,7 @@ class Net_SCP return false; } - if (!$this->ssh->exec('scp -t "' . $remote_file . '"', false)) { // -t = to + if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to return false; } @@ -195,7 +195,6 @@ class Net_SCP $fp = @fopen($data, 'rb'); if (!$fp) { - fclose($fp); return false; } $size = filesize($data); @@ -245,7 +244,7 @@ class Net_SCP return false; } - if (!$this->ssh->exec('scp -f "' . $remote_file . '"', false)) { // -f = from + if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from return false; } @@ -304,7 +303,7 @@ class Net_SCP case NET_SCP_SSH1: $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data); $this->ssh->_send_binary_packet($data); - } + } } /** @@ -340,7 +339,7 @@ class Net_SCP return false; } } - } + } } /** @@ -356,6 +355,6 @@ class Net_SCP break; case NET_SCP_SSH1: $this->ssh->disconnect(); - } + } } } diff --git a/Net/SFTP.php b/Net/SFTP.php index c2045ae..1c042cd 100644 --- a/Net/SFTP.php +++ b/Net/SFTP.php @@ -48,7 +48,7 @@ * @category Net * @package Net_SFTP * @author Jim Wigginton - * @copyright MMIX Jim Wigginton + * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -102,6 +102,11 @@ define('NET_SFTP_LOCAL_FILE', 1); */ // this value isn't really used anymore but i'm keeping it reserved for historical reasons define('NET_SFTP_STRING', 2); +/** + * Reads data from callback: + * function callback($length) returns string to proceed, null for EOF + */ +define('NET_SFTP_CALLBACK', 16); /** * Resumes an upload */ @@ -429,8 +434,15 @@ class Net_SFTP extends Net_SSH2 $this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size; - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000); + $packet = pack( + 'CNa*N3', + NET_SSH2_MSG_CHANNEL_OPEN, + strlen('session'), + 'session', + NET_SFTP_CHANNEL, + $this->window_size, + 0x4000 + ); if (!$this->_send_binary_packet($packet)) { return false; @@ -443,8 +455,16 @@ class Net_SFTP extends Net_SSH2 return false; } - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('subsystem'), 'subsystem', 1, strlen('sftp'), 'sftp'); + $packet = pack( + 'CNNa*CNa*', + NET_SSH2_MSG_CHANNEL_REQUEST, + $this->server_channels[NET_SFTP_CHANNEL], + strlen('subsystem'), + 'subsystem', + 1, + strlen('sftp'), + 'sftp' + ); if (!$this->_send_binary_packet($packet)) { return false; } @@ -459,8 +479,16 @@ class Net_SFTP extends Net_SSH2 "exec sftp-server"; // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does // is redundant - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('exec'), 'exec', 1, strlen($command), $command); + $packet = pack( + 'CNNa*CNa*', + NET_SSH2_MSG_CHANNEL_REQUEST, + $this->server_channels[NET_SFTP_CHANNEL], + strlen('exec'), + 'exec', + 1, + strlen($command), + $command + ); if (!$this->_send_binary_packet($packet)) { return false; } @@ -801,7 +829,7 @@ class Net_SFTP extends Net_SSH2 static $depth = 0; - foreach ($files as $key=>$value) { + foreach ($files as $key => $value) { if ($depth != 0 && $key == '..') { unset($files[$key]); continue; @@ -896,7 +924,7 @@ class Net_SFTP extends Net_SSH2 } else { $temp = $dir . '/' . $shortname; } - $this->_update_stat_cache($temp, (object) $attributes); + $this->_update_stat_cache($temp, (object) array('lstat' => $attributes)); } // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the // final SSH_FXP_STATUS packet should tell us that, already. @@ -1057,16 +1085,34 @@ class Net_SFTP extends Net_SSH2 */ function _update_stat_cache($path, $value) { + if ($this->use_stat_cache === false) { + return; + } + // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/')) $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $temp = &$this->stat_cache; $max = count($dirs) - 1; - foreach ($dirs as $i=>$dir) { + foreach ($dirs as $i => $dir) { + // if $temp is an object that means one of two things. + // 1. a file was deleted and changed to a directory behind phpseclib's back + // 2. it's a symlink. when lstat is done it's unclear what it's a symlink to + if (is_object($temp)) { + $temp = array(); + } if (!isset($temp[$dir])) { $temp[$dir] = array(); } if ($i === $max) { + if (is_object($temp[$dir])) { + if (!isset($value->stat) && isset($temp[$dir]->stat)) { + $value->stat = $temp[$dir]->stat; + } + if (!isset($value->lstat) && isset($temp[$dir]->lstat)) { + $value->lstat = $temp[$dir]->lstat; + } + } $temp[$dir] = $value; break; } @@ -1087,7 +1133,7 @@ class Net_SFTP extends Net_SSH2 $temp = &$this->stat_cache; $max = count($dirs) - 1; - foreach ($dirs as $i=>$dir) { + foreach ($dirs as $i => $dir) { if ($i === $max) { unset($temp[$dir]); return true; @@ -1144,11 +1190,11 @@ class Net_SFTP extends Net_SSH2 if ($this->use_stat_cache) { $result = $this->_query_stat_cache($filename); - if (is_array($result) && isset($result['.'])) { - return (array) $result['.']; + if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) { + return $result['.']->stat; } - if (is_object($result)) { - return (array) $result; + if (is_object($result) && isset($result->stat)) { + return $result->stat; } } @@ -1161,7 +1207,7 @@ class Net_SFTP extends Net_SSH2 if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } - $this->_update_stat_cache($filename, (object) $stat); + $this->_update_stat_cache($filename, (object) array('stat' => $stat)); return $stat; } @@ -1174,7 +1220,7 @@ class Net_SFTP extends Net_SSH2 if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } - $this->_update_stat_cache($filename, (object) $stat); + $this->_update_stat_cache($filename, (object) array('stat' => $stat)); return $stat; } @@ -1201,11 +1247,11 @@ class Net_SFTP extends Net_SSH2 if ($this->use_stat_cache) { $result = $this->_query_stat_cache($filename); - if (is_array($result) && isset($result['.'])) { - return (array) $result['.']; + if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) { + return $result['.']->lstat; } - if (is_object($result)) { - return (array) $result; + if (is_object($result) && isset($result->lstat)) { + return $result->lstat; } } @@ -1218,7 +1264,7 @@ class Net_SFTP extends Net_SSH2 if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } - $this->_update_stat_cache($filename, (object) $lstat); + $this->_update_stat_cache($filename, (object) array('lstat' => $lstat)); return $lstat; } @@ -1226,7 +1272,7 @@ class Net_SFTP extends Net_SSH2 if ($lstat != $stat) { $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK)); - $this->_update_stat_cache($filename, (object) $lstat); + $this->_update_stat_cache($filename, (object) array('lstat' => $lstat)); return $stat; } @@ -1239,7 +1285,7 @@ class Net_SFTP extends Net_SSH2 if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } - $this->_update_stat_cache($filename, (object) $lstat); + $this->_update_stat_cache($filename, (object) array('lstat' => $lstat)); return $lstat; } @@ -1517,7 +1563,7 @@ class Net_SFTP extends Net_SSH2 } unset($entries['.'], $entries['..']); - foreach ($entries as $filename=>$props) { + foreach ($entries as $filename => $props) { if (!isset($props['type'])) { return false; } @@ -1759,6 +1805,10 @@ class Net_SFTP extends Net_SSH2 * * If $data is a resource then it'll be used as a resource instead. * + * + * Setting $mode to NET_SFTP_CALLBACK will use $data as callback function, which gets only one parameter -- number + * of bytes to return, and returns a string if there is some data or null if there is no more data + * * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * care of that, yourself. * @@ -1784,11 +1834,12 @@ class Net_SFTP extends Net_SSH2 * @param optional Integer $mode * @param optional Integer $start * @param optional Integer $local_start + * @param optional callable|null $progressCallback * @return Boolean * @access public * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode(). */ - function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1) + function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1, $progressCallback = null) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; @@ -1836,7 +1887,15 @@ class Net_SFTP extends Net_SSH2 } // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 + $dataCallback = false; switch (true) { + case $mode & NET_SFTP_CALLBACK: + if (!is_callable($data)) { + user_error("\$data should be is_callable if you set NET_SFTP_CALLBACK flag"); + } + $dataCallback = $data; + // do nothing + break; case is_resource($data): $mode = $mode & ~NET_SFTP_LOCAL_FILE; $fp = $data; @@ -1863,6 +1922,8 @@ class Net_SFTP extends Net_SSH2 } else { fseek($fp, $offset); } + } elseif ($dataCallback) { + $size = 0; } else { $size = strlen($data); } @@ -1874,8 +1935,15 @@ class Net_SFTP extends Net_SSH2 // make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header" $sftp_packet_size-= strlen($handle) + 25; $i = 0; - while ($sent < $size) { - $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); + while ($dataCallback || ($sent < $size)) { + if ($dataCallback) { + $temp = call_user_func($dataCallback, $sftp_packet_size); + if (is_null($temp)) { + break; + } + } else { + $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); + } $subtemp = $offset + $sent; $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { @@ -1885,6 +1953,9 @@ class Net_SFTP extends Net_SSH2 return false; } $sent+= strlen($temp); + if (is_callable($progressCallback)) { + call_user_func($progressCallback, $sent); + } $i++; @@ -2166,7 +2237,7 @@ class Net_SFTP extends Net_SSH2 } unset($entries['.'], $entries['..']); - foreach ($entries as $filename=>$props) { + foreach ($entries as $filename => $props) { if (!isset($props['type'])) { return false; } @@ -2180,6 +2251,7 @@ class Net_SFTP extends Net_SSH2 if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) { return false; } + $this->_remove_from_stat_cache($temp); $i++; @@ -2190,12 +2262,12 @@ class Net_SFTP extends Net_SSH2 $i = 0; } } - $this->_remove_from_stat_cache($path); } if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) { return false; } + $this->_remove_from_stat_cache($path); $i++; @@ -2273,7 +2345,7 @@ class Net_SFTP extends Net_SSH2 */ function is_link($path) { - $result = $this->_get_stat_cache_prop($path, 'type'); + $result = $this->_get_lstat_cache_prop($path, 'type'); if ($result === false) { return false; } @@ -2367,13 +2439,20 @@ class Net_SFTP extends Net_SSH2 } switch ($type) { - case NET_SFTP_BLOCK_DEVICE: return 'block'; - case NET_SFTP_TYPE_CHAR_DEVICE: return 'char'; - case NET_SFTP_TYPE_DIRECTORY: return 'dir'; - case NET_SFTP_TYPE_FIFO: return 'fifo'; - case NET_SFTP_TYPE_REGULAR: return 'file'; - case NET_SFTP_TYPE_SYMLINK: return 'link'; - default: return false; + case NET_SFTP_TYPE_BLOCK_DEVICE: + return 'block'; + case NET_SFTP_TYPE_CHAR_DEVICE: + return 'char'; + case NET_SFTP_TYPE_DIRECTORY: + return 'dir'; + case NET_SFTP_TYPE_FIFO: + return 'fifo'; + case NET_SFTP_TYPE_REGULAR: + return 'file'; + case NET_SFTP_TYPE_SYMLINK: + return 'link'; + default: + return false; } } @@ -2388,18 +2467,48 @@ class Net_SFTP extends Net_SSH2 * @access private */ function _get_stat_cache_prop($path, $prop) + { + return $this->_get_xstat_cache_prop($path, $prop, 'stat'); + } + + /** + * Return an lstat properity + * + * Uses cache if appropriate. + * + * @param String $path + * @param String $prop + * @return Mixed + * @access private + */ + function _get_lstat_cache_prop($path, $prop) + { + return $this->_get_xstat_cache_prop($path, $prop, 'lstat'); + } + + /** + * Return a stat or lstat properity + * + * Uses cache if appropriate. + * + * @param String $path + * @param String $prop + * @return Mixed + * @access private + */ + function _get_xstat_cache_prop($path, $prop, $type) { if ($this->use_stat_cache) { $path = $this->_realpath($path); $result = $this->_query_stat_cache($path); - if (is_object($result) && isset($result->$prop)) { - return $result->$prop; + if (is_object($result) && isset($result->$type)) { + return $result->{$type}[$prop]; } } - $result = $this->stat($path); + $result = $this->$type($path); if ($result === false || !isset($result[$prop])) { return false; @@ -2473,14 +2582,13 @@ class Net_SFTP extends Net_SSH2 foreach ($this->attributes as $key => $value) { switch ($flags & $key) { case NET_SFTP_ATTR_SIZE: // 0x00000001 - // size is represented by a 64-bit integer, so we perhaps ought to be doing the following: - // $attr['size'] = new Math_BigInteger($this->_string_shift($response, 8), 256); - // of course, you shouldn't be using Net_SFTP to transfer files that are in excess of 4GB - // (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than - // 4GB as being 4GB. - extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8))); - $attr['size'] = $upper ? 4294967296 * $upper : 0; - $attr['size']+= $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; + // The size attribute is defined as an unsigned 64-bit integer. + // The following will use floats on 32-bit platforms, if necessary. + // As can be seen in the BigInteger class, floats are generally + // IEEE 754 binary64 "double precision" on such platforms and + // as such can represent integers of at least 2^50 without loss + // of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB. + $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8))); break; case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8)); @@ -2540,7 +2648,7 @@ class Net_SFTP extends Net_SSH2 case 0020000: // character special return NET_SFTP_TYPE_CHAR_DEVICE; case 0060000: // block special - return NET_SFTP_BLOCK_DEVICE; + return NET_SFTP_TYPE_BLOCK_DEVICE; case 0140000: // socket return NET_SFTP_TYPE_SOCKET; case 0160000: // whiteout @@ -2603,7 +2711,7 @@ class Net_SFTP extends Net_SSH2 { $packet = $this->request_id !== false ? pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) : - pack('NCa*', strlen($data) + 1, $type, $data); + pack('NCa*', strlen($data) + 1, $type, $data); $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 $result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet); diff --git a/Net/SFTP/Stream.php b/Net/SFTP/Stream.php index 0c84ab4..107560f 100644 --- a/Net/SFTP/Stream.php +++ b/Net/SFTP/Stream.php @@ -28,7 +28,7 @@ * @category Net * @package Net_SFTP_Stream * @author Jim Wigginton - * @copyright MMXIII Jim Wigginton + * @copyright 2013 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -48,7 +48,6 @@ class Net_SFTP_Stream * Rather than re-create the connection we re-use instances if possible * * @var Array - * @access static */ static $instances; @@ -281,14 +280,17 @@ class Net_SFTP_Stream if ($this->size === false) { if ($this->mode[0] == 'r') { return false; + } else { + $this->sftp->touch($path); + $this->size = 0; } } else { switch ($this->mode[0]) { case 'x': return false; case 'w': - case 'c': $this->sftp->truncate($path, 0); + $this->size = 0; } } @@ -512,7 +514,7 @@ class Net_SFTP_Stream $path_from = $this->_parse_path($path_from); $path_to = parse_url($path_to); - if ($path_from == false) { + if ($path_from === false) { return false; } diff --git a/Net/SSH1.php b/Net/SSH1.php index 35e6d5e..ad0ee79 100644 --- a/Net/SSH1.php +++ b/Net/SSH1.php @@ -59,7 +59,7 @@ * @category Net * @package Net_SSH1 * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -621,7 +621,7 @@ class Net_SSH1 // get a list of the supported ciphers extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); - foreach ($this->supported_ciphers as $mask=>$name) { + foreach ($this->supported_ciphers as $mask => $name) { if (($supported_ciphers_mask & (1 << $mask)) == 0) { unset($this->supported_ciphers[$mask]); } @@ -629,7 +629,7 @@ class Net_SSH1 // get a list of the supported authentications extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); - foreach ($this->supported_authentications as $mask=>$name) { + foreach ($this->supported_authentications as $mask => $name) { if (($supported_authentications_mask & (1 << $mask)) == 0) { unset($this->supported_authentications[$mask]); } @@ -691,7 +691,7 @@ class Net_SSH1 $this->crypto = new Crypt_DES(); $this->crypto->disablePadding(); $this->crypto->enableContinuousBuffer(); - $this->crypto->setKey(substr($session_key, 0, 8)); + $this->crypto->setKey(substr($session_key, 0, 8)); break; case NET_SSH1_CIPHER_3DES: if (!class_exists('Crypt_TripleDES')) { @@ -760,7 +760,7 @@ class Net_SSH1 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) { $this->bitmap |= NET_SSH1_MASK_LOGIN; return true; - } else if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) { + } elseif ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) { user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE'); return false; } @@ -786,7 +786,7 @@ class Net_SSH1 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) { $this->bitmap |= NET_SSH1_MASK_LOGIN; return true; - } else if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) { + } elseif ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) { return false; } else { user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE'); @@ -1128,6 +1128,7 @@ class Net_SSH1 $padding_length = 8 - ($temp['length'] & 7); $length = $temp['length'] + $padding_length; + $raw = ''; while ($length > 0) { $temp = fread($this->fsock, $length); @@ -1298,7 +1299,7 @@ class Net_SSH1 $crc = 0x00000000; $length = strlen($data); - for ($i=0;$i<$length;$i++) { + for ($i=0; $i<$length; $i++) { // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example, // yields 0xFF800000 - not 0x00800000. The following link elaborates: @@ -1397,7 +1398,7 @@ class Net_SSH1 { $args = func_get_args(); foreach ($args as $arg) { - foreach ($arg as $key=>$value) { + foreach ($arg as $key => $value) { if (!defined($value)) { define($value, $key); } else { diff --git a/Net/SSH2.php b/Net/SSH2.php index e3947d5..258fb8e 100644 --- a/Net/SSH2.php +++ b/Net/SSH2.php @@ -61,7 +61,7 @@ * @category Net * @package Net_SSH2 * @author Jim Wigginton - * @copyright MMVII Jim Wigginton + * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -77,7 +77,7 @@ define('NET_SSH2_MASK_CONNECTED', 0x00000002); define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004); define('NET_SSH2_MASK_LOGIN', 0x00000008); define('NET_SSH2_MASK_SHELL', 0x00000010); -define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000020); +define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020); /**#@-*/ /**#@+ @@ -99,6 +99,7 @@ define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000020); define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100 define('NET_SSH2_CHANNEL_SHELL', 1); define('NET_SSH2_CHANNEL_SUBSYSTEM', 2); +define('NET_SSH2_CHANNEL_AGENT_FORWARD', 3); /**#@-*/ /**#@+ @@ -205,6 +206,33 @@ class Net_SSH2 */ var $kex_algorithms = false; + /** + * Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods + * + * @see Net_SSH2::_key_exchange() + * @var Integer + * @access private + */ + var $kex_dh_group_size_min = 1536; + + /** + * Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods + * + * @see Net_SSH2::_key_exchange() + * @var Integer + * @access private + */ + var $kex_dh_group_size_preferred = 2048; + + /** + * Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods + * + * @see Net_SSH2::_key_exchange() + * @var Integer + * @access private + */ + var $kex_dh_group_size_max = 4096; + /** * Server Host Key Algorithms * @@ -803,21 +831,6 @@ class Net_SSH2 */ var $port; - /** - * Timeout for initial connection - * - * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like - * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor, - * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be - * 10 seconds. It is used by fsockopen() and the initial stream_select in that function. - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_connect() - * @var Integer - * @access private - */ - var $connectionTimeout; - /** * Number of columns for terminal window size * @@ -840,6 +853,24 @@ class Net_SSH2 */ var $windowRows = 24; + /** + * Crypto Engine + * + * @see Net_SSH2::setCryptoEngine() + * @see Net_SSH2::_key_exchange() + * @var Integer + * @access private + */ + var $crypto_engine = false; + + /** + * A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario + * + * @var System_SSH_Agent + * @access private + */ + var $agent; + /** * Default Constructor. * @@ -866,6 +897,11 @@ class Net_SSH2 include_once 'Crypt/Hash.php'; } + // include Crypt_Base so constants can be defined for setCryptoEngine() + if (!class_exists('Crypt_Base')) { + include_once 'Crypt/Base.php'; + } + $this->message_numbers = array( 1 => 'NET_SSH2_MSG_DISCONNECT', 2 => 'NET_SSH2_MSG_IGNORE', @@ -933,12 +969,32 @@ class Net_SSH2 array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'), array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'), array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', - 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE') + 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'), + // RFC 4419 - diffie-hellman-group-exchange-sha{1,256} + array(30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD', + 31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP', + 32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT', + 33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY', + 34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST') ); $this->host = $host; $this->port = $port; - $this->connectionTimeout = $timeout; + $this->timeout = $timeout; + } + + /** + * Set Crypto Engine Mode + * + * Possible $engine values: + * CRYPT_MODE_INTERNAL, CRYPT_MODE_MCRYPT + * + * @param Integer $engine + * @access private + */ + function setCryptoEngine($engine) + { + $this->crypto_engine = $engine; } /** @@ -955,36 +1011,24 @@ class Net_SSH2 $this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR; - $timeout = $this->connectionTimeout; + $this->curTimeout = $this->timeout; + $host = $this->host . ':' . $this->port; $this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $timeout); + $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout); if (!$this->fsock) { user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); return false; } $elapsed = strtok(microtime(), ' ') + strtok('') - $start; - $timeout-= $elapsed; + $this->curTimeout-= $elapsed; - if ($timeout <= 0) { - user_error(rtrim("Cannot connect to $host. Timeout error")); - return false; - } - - $read = array($this->fsock); - $write = $except = null; - - $sec = floor($timeout); - $usec = 1000000 * ($timeout - $sec); - - // on windows this returns a "Warning: Invalid CRT parameters detected" error - // the !count() is done as a workaround for - if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { - user_error(rtrim("Cannot connect to $host. Banner timeout")); + if ($this->curTimeout <= 0) { + $this->is_timeout = true; return false; } @@ -1002,6 +1046,27 @@ class Net_SSH2 $extra.= $temp; $temp = ''; } + + if ($this->curTimeout) { + if ($this->curTimeout < 0) { + $this->is_timeout = true; + return false; + } + $read = array($this->fsock); + $write = $except = null; + $start = strtok(microtime(), ' ') + strtok(''); + $sec = floor($this->curTimeout); + $usec = 1000000 * ($this->curTimeout - $sec); + // on windows this returns a "Warning: Invalid CRT parameters detected" error + // the !count() is done as a workaround for + if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { + $this->is_timeout = true; + return false; + } + $elapsed = strtok(microtime(), ' ') + strtok('') - $start; + $this->curTimeout-= $elapsed; + } + $temp.= fgets($this->fsock, 255); } @@ -1062,7 +1127,9 @@ class Net_SSH2 $identifier = 'SSH-2.0-phpseclib_0.3'; $ext = array(); - if (extension_loaded('mcrypt')) { + if (extension_loaded('openssl')) { + $ext[] = 'openssl'; + } elseif (extension_loaded('mcrypt')) { $ext[] = 'mcrypt'; } @@ -1089,7 +1156,9 @@ class Net_SSH2 { static $kex_algorithms = array( 'diffie-hellman-group1-sha1', // REQUIRED - 'diffie-hellman-group14-sha1' // REQUIRED + 'diffie-hellman-group14-sha1', // REQUIRED + 'diffie-hellman-group-exchange-sha1', // RFC 4419 + 'diffie-hellman-group-exchange-sha256', // RFC 4419 ); static $server_host_key_algorithms = array( @@ -1104,7 +1173,7 @@ class Net_SSH2 'arcfour256', 'arcfour128', - //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key + //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key // CTR modes from : 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key @@ -1132,9 +1201,18 @@ class Net_SSH2 '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode '3des-cbc', // REQUIRED three-key 3DES in CBC mode - //'none' // OPTIONAL no encryption; NOT RECOMMENDED + //'none' // OPTIONAL no encryption; NOT RECOMMENDED ); + if (extension_loaded('openssl') && !extension_loaded('mcrypt')) { + // OpenSSL does not support arcfour256 in any capacity and arcfour128 / arcfour support is limited to + // instances that do not use continuous buffers + $encryption_algorithms = array_diff( + $encryption_algorithms, + array('arcfour256', 'arcfour128', 'arcfour') + ); + } + if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) { $encryption_algorithms = array_diff( $encryption_algorithms, @@ -1245,14 +1323,32 @@ class Net_SSH2 $first_kex_packet_follows = $first_kex_packet_follows != 0; // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place. - $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', - NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, - strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), - $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, - strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), - $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, - strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', - 0, 0 + $kexinit_payload_client = pack( + 'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', + NET_SSH2_MSG_KEXINIT, + $client_cookie, + strlen($str_kex_algorithms), + $str_kex_algorithms, + strlen($str_server_host_key_algorithms), + $str_server_host_key_algorithms, + strlen($encryption_algorithms_client_to_server), + $encryption_algorithms_client_to_server, + strlen($encryption_algorithms_server_to_client), + $encryption_algorithms_server_to_client, + strlen($mac_algorithms_client_to_server), + $mac_algorithms_client_to_server, + strlen($mac_algorithms_server_to_client), + $mac_algorithms_server_to_client, + strlen($compression_algorithms_client_to_server), + $compression_algorithms_client_to_server, + strlen($compression_algorithms_server_to_client), + $compression_algorithms_server_to_client, + 0, + '', + 0, + '', + 0, + 0 ); if (!$this->_send_binary_packet($kexinit_payload_client)) { @@ -1261,7 +1357,8 @@ class Net_SSH2 // here ends the second place. // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange - for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++); + for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++) { + } if ($i == count($encryption_algorithms)) { user_error('No compatible server to client encryption algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); @@ -1303,11 +1400,12 @@ class Net_SSH2 case 'arcfour256': $decryptKeyLength = 32; // eg. 128 / 8 break; - case 'none'; + case 'none': $decryptKeyLength = 0; } - for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++); + for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++) { + } if ($i == count($encryption_algorithms)) { user_error('No compatible client to server encryption algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); @@ -1347,47 +1445,105 @@ class Net_SSH2 case 'arcfour256': $encryptKeyLength = 32; break; - case 'none'; + case 'none': $encryptKeyLength = 0; } $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength; // through diffie-hellman key exchange a symmetric key is obtained - for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++); + for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); + $i++) { + } if ($i == count($kex_algorithms)) { user_error('No compatible key exchange algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } - switch ($kex_algorithms[$i]) { - // see http://tools.ietf.org/html/rfc2409#section-6.2 and - // http://tools.ietf.org/html/rfc2412, appendex E - case 'diffie-hellman-group1-sha1': - $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; - break; - // see http://tools.ietf.org/html/rfc3526#section-3 - case 'diffie-hellman-group14-sha1': - $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . - '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . - '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . - 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . - '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; - break; + if (strpos($kex_algorithms[$i], 'diffie-hellman-group-exchange') === 0) { + $dh_group_sizes_packed = pack( + 'NNN', + $this->kex_dh_group_size_min, + $this->kex_dh_group_size_preferred, + $this->kex_dh_group_size_max + ); + $packet = pack( + 'Ca*', + NET_SSH2_MSG_KEXDH_GEX_REQUEST, + $dh_group_sizes_packed + ); + if (!$this->_send_binary_packet($packet)) { + return false; + } + + $response = $this->_get_binary_packet(); + if ($response === false) { + user_error('Connection closed by server'); + return false; + } + extract(unpack('Ctype', $this->_string_shift($response, 1))); + if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) { + user_error('Expected SSH_MSG_KEX_DH_GEX_GROUP'); + return false; + } + + extract(unpack('NprimeLength', $this->_string_shift($response, 4))); + $primeBytes = $this->_string_shift($response, $primeLength); + $prime = new Math_BigInteger($primeBytes, -256); + + extract(unpack('NgLength', $this->_string_shift($response, 4))); + $gBytes = $this->_string_shift($response, $gLength); + $g = new Math_BigInteger($gBytes, -256); + + $exchange_hash_rfc4419 = pack( + 'a*Na*Na*', + $dh_group_sizes_packed, + $primeLength, + $primeBytes, + $gLength, + $gBytes + ); + + $clientKexInitMessage = NET_SSH2_MSG_KEXDH_GEX_INIT; + $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_GEX_REPLY; + } else { + switch ($kex_algorithms[$i]) { + // see http://tools.ietf.org/html/rfc2409#section-6.2 and + // http://tools.ietf.org/html/rfc2412, appendex E + case 'diffie-hellman-group1-sha1': + $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; + break; + // see http://tools.ietf.org/html/rfc3526#section-3 + case 'diffie-hellman-group14-sha1': + $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . + '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . + '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . + 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . + '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; + break; + } + // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1 + // the generator field element is 2 (decimal) and the hash function is sha1. + $g = new Math_BigInteger(2); + $prime = new Math_BigInteger($prime, 16); + $exchange_hash_rfc4419 = ''; + $clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT; + $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY; } - // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1 - // the generator field element is 2 (decimal) and the hash function is sha1. - $g = new Math_BigInteger(2); - $prime = new Math_BigInteger($prime, 16); - $kexHash = new Crypt_Hash('sha1'); - //$q = $p->bitwise_rightShift(1); + switch ($kex_algorithms[$i]) { + case 'diffie-hellman-group-exchange-sha256': + $kexHash = new Crypt_Hash('sha256'); + break; + default: + $kexHash = new Crypt_Hash('sha1'); + } /* To increase the speed of the key exchange, both client and server may reduce the size of their private exponents. It should be at least @@ -1405,7 +1561,7 @@ class Net_SSH2 $e = $g->modPow($x, $prime); $eBytes = $e->toBytes(true); - $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes); + $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes); if (!$this->_send_binary_packet($data)) { user_error('Connection closed by server'); @@ -1419,7 +1575,7 @@ class Net_SSH2 } extract(unpack('Ctype', $this->_string_shift($response, 1))); - if ($type != NET_SSH2_MSG_KEXDH_REPLY) { + if ($type != $serverKexReplyMessage) { user_error('Expected SSH_MSG_KEXDH_REPLY'); return false; } @@ -1443,11 +1599,25 @@ class Net_SSH2 $key = $f->modPow($x, $prime); $keyBytes = $key->toBytes(true); - $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', - strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, - strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), - $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), - $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes + $this->exchange_hash = pack( + 'Na*Na*Na*Na*Na*a*Na*Na*Na*', + strlen($this->identifier), + $this->identifier, + strlen($this->server_identifier), + $this->server_identifier, + strlen($kexinit_payload_client), + $kexinit_payload_client, + strlen($kexinit_payload_server), + $kexinit_payload_server, + strlen($this->server_public_host_key), + $this->server_public_host_key, + $exchange_hash_rfc4419, + strlen($eBytes), + $eBytes, + strlen($fBytes), + $fBytes, + strlen($keyBytes), + $keyBytes ); $this->exchange_hash = $kexHash->hash($this->exchange_hash); @@ -1456,7 +1626,8 @@ class Net_SSH2 $this->session_id = $this->exchange_hash; } - for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++); + for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++) { + } if ($i == count($server_host_key_algorithms)) { user_error('No compatible server host key algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); @@ -1467,7 +1638,8 @@ class Net_SSH2 return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } - $packet = pack('C', + $packet = pack( + 'C', NET_SSH2_MSG_NEWKEYS ); @@ -1563,7 +1735,7 @@ class Net_SSH2 } $this->encrypt = new Crypt_RC4(); break; - case 'none'; + case 'none': //$this->encrypt = new Crypt_Null(); } @@ -1639,13 +1811,16 @@ class Net_SSH2 } $this->decrypt = new Crypt_RC4(); break; - case 'none'; + case 'none': //$this->decrypt = new Crypt_Null(); } $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); if ($this->encrypt) { + if ($this->crypto_engine) { + $this->encrypt->setEngine($this->crypto_engine); + } $this->encrypt->enableContinuousBuffer(); $this->encrypt->disablePadding(); @@ -1663,6 +1838,9 @@ class Net_SSH2 } if ($this->decrypt) { + if ($this->crypto_engine) { + $this->decrypt->setEngine($this->crypto_engine); + } $this->decrypt->enableContinuousBuffer(); $this->decrypt->disablePadding(); @@ -1693,7 +1871,8 @@ class Net_SSH2 $this->decrypt->decrypt(str_repeat("\0", 1536)); } - for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++); + for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++) { + } if ($i == count($mac_algorithms)) { user_error('No compatible client to server message authentication algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); @@ -1722,7 +1901,8 @@ class Net_SSH2 $createKeyLength = 16; } - for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++); + for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++) { + } if ($i == count($mac_algorithms)) { user_error('No compatible server to client message authentication algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); @@ -1769,14 +1949,16 @@ class Net_SSH2 } $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); - for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++); + for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++) { + } if ($i == count($compression_algorithms)) { user_error('No compatible server to client compression algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $this->decompress = $compression_algorithms[$i] == 'zlib'; - for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++); + for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++) { + } if ($i == count($compression_algorithms)) { user_error('No compatible client to server compression algorithms found'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); @@ -1852,8 +2034,11 @@ class Net_SSH2 } if (!($this->bitmap & NET_SSH2_MASK_LOGIN_REQ)) { - $packet = pack('CNa*', - NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth' + $packet = pack( + 'CNa*', + NET_SSH2_MSG_SERVICE_REQUEST, + strlen('ssh-userauth'), + 'ssh-userauth' ); if (!$this->_send_binary_packet($packet)) { @@ -1898,9 +2083,15 @@ class Net_SSH2 } if (!isset($password)) { - $packet = pack('CNa*Na*Na*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('none'), 'none' + $packet = pack( + 'CNa*Na*Na*', + NET_SSH2_MSG_USERAUTH_REQUEST, + strlen($username), + $username, + strlen('ssh-connection'), + 'ssh-connection', + strlen('none'), + 'none' ); if (!$this->_send_binary_packet($packet)) { @@ -1925,18 +2116,36 @@ class Net_SSH2 } } - $packet = pack('CNa*Na*Na*CNa*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('password'), 'password', 0, strlen($password), $password + $packet = pack( + 'CNa*Na*Na*CNa*', + NET_SSH2_MSG_USERAUTH_REQUEST, + strlen($username), + $username, + strlen('ssh-connection'), + 'ssh-connection', + strlen('password'), + 'password', + 0, + strlen($password), + $password ); // remove the username and password from the logged packet if (!defined('NET_SSH2_LOGGING')) { $logged = null; } else { - $logged = pack('CNa*Na*Na*CNa*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection', - strlen('password'), 'password', 0, strlen('password'), 'password' + $logged = pack( + 'CNa*Na*Na*CNa*', + NET_SSH2_MSG_USERAUTH_REQUEST, + strlen('username'), + 'username', + strlen('ssh-connection'), + 'ssh-connection', + strlen('password'), + 'password', + 0, + strlen('password'), + 'password' ); } @@ -1996,9 +2205,19 @@ class Net_SSH2 */ function _keyboard_interactive_login($username, $password) { - $packet = pack('CNa*Na*Na*Na*Na*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('keyboard-interactive'), 'keyboard-interactive', 0, '', 0, '' + $packet = pack( + 'CNa*Na*Na*Na*Na*', + NET_SSH2_MSG_USERAUTH_REQUEST, + strlen($username), + $username, + strlen('ssh-connection'), + 'ssh-connection', + strlen('keyboard-interactive'), + 'keyboard-interactive', + 0, + '', + 0, + '' ); if (!$this->_send_binary_packet($packet)) { @@ -2069,7 +2288,7 @@ class Net_SSH2 // see http://tools.ietf.org/html/rfc4256#section-3.2 if (strlen($this->last_interactive_response)) { $this->last_interactive_response = ''; - } else if (defined('NET_SSH2_LOGGING')) { + } elseif (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', @@ -2132,6 +2351,7 @@ class Net_SSH2 */ function _ssh_agent_login($username, $agent) { + $this->agent = $agent; $keys = $agent->requestIdentities(); foreach ($keys as $key) { if ($this->_privatekey_login($username, $key)) { @@ -2164,13 +2384,25 @@ class Net_SSH2 'e' => $publickey['e']->toBytes(true), 'n' => $publickey['n']->toBytes(true) ); - $publickey = pack('Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $publickey['n'] + $publickey = pack( + 'Na*Na*Na*', + strlen('ssh-rsa'), + 'ssh-rsa', + strlen($publickey['e']), + $publickey['e'], + strlen($publickey['n']), + $publickey['n'] ); - $part1 = pack('CNa*Na*Na*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('publickey'), 'publickey' + $part1 = pack( + 'CNa*Na*Na*', + NET_SSH2_MSG_USERAUTH_REQUEST, + strlen($username), + $username, + strlen('ssh-connection'), + 'ssh-connection', + strlen('publickey'), + 'publickey' ); $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey); @@ -2261,7 +2493,7 @@ class Net_SSH2 /** * Execute Command * - * If $block is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually. + * If $callback is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually. * In all likelihood, this is not a feature you want to be taking advantage of. * * @param String $command @@ -2288,8 +2520,15 @@ class Net_SSH2 // uses 0x4000, that's what will be used here, as well. $packet_size = 0x4000; - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC], $packet_size); + $packet = pack( + 'CNa*N3', + NET_SSH2_MSG_CHANNEL_OPEN, + strlen('session'), + 'session', + NET_SSH2_CHANNEL_EXEC, + $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC], + $packet_size + ); if (!$this->_send_binary_packet($packet)) { return false; @@ -2304,13 +2543,27 @@ class Net_SSH2 if ($this->request_pty === true) { $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); - $packet = pack('CNNa*CNa*N5a*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', - $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); + $packet = pack( + 'CNNa*CNa*N5a*', + NET_SSH2_MSG_CHANNEL_REQUEST, + $this->server_channels[NET_SSH2_CHANNEL_EXEC], + strlen('pty-req'), + 'pty-req', + 1, + strlen('vt100'), + 'vt100', + $this->windowColumns, + $this->windowRows, + 0, + 0, + strlen($terminal_modes), + $terminal_modes + ); if (!$this->_send_binary_packet($packet)) { return false; } + $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server'); @@ -2339,8 +2592,17 @@ class Net_SSH2 // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates. - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec'), 'exec', 1, strlen($command), $command); + $packet = pack( + 'CNNa*CNa*', + NET_SSH2_MSG_CHANNEL_REQUEST, + $this->server_channels[NET_SSH2_CHANNEL_EXEC], + strlen('exec'), + 'exec', + 1, + strlen($command), + $command + ); + if (!$this->_send_binary_packet($packet)) { return false; } @@ -2396,8 +2658,15 @@ class Net_SSH2 $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = $this->window_size; $packet_size = 0x4000; - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL], $packet_size); + $packet = pack( + 'CNa*N3', + NET_SSH2_MSG_CHANNEL_OPEN, + strlen('session'), + 'session', + NET_SSH2_CHANNEL_SHELL, + $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL], + $packet_size + ); if (!$this->_send_binary_packet($packet)) { return false; @@ -2411,9 +2680,22 @@ class Net_SSH2 } $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); - $packet = pack('CNNa*CNa*N5a*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', - $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes); + $packet = pack( + 'CNNa*CNa*N5a*', + NET_SSH2_MSG_CHANNEL_REQUEST, + $this->server_channels[NET_SSH2_CHANNEL_SHELL], + strlen('pty-req'), + 'pty-req', + 1, + strlen('vt100'), + 'vt100', + $this->windowColumns, + $this->windowRows, + 0, + 0, + strlen($terminal_modes), + $terminal_modes + ); if (!$this->_send_binary_packet($packet)) { return false; @@ -2437,8 +2719,14 @@ class Net_SSH2 return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } - $packet = pack('CNNa*C', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('shell'), 'shell', 1); + $packet = pack( + 'CNNa*C', + NET_SSH2_MSG_CHANNEL_REQUEST, + $this->server_channels[NET_SSH2_CHANNEL_SHELL], + strlen('shell'), + 'shell', + 1 + ); if (!$this->_send_binary_packet($packet)) { return false; } @@ -2477,6 +2765,24 @@ class Net_SSH2 } } + /** + * Return an available open channel + * + * @return Integer + * @access public + */ + function _get_open_channel() + { + $channel = NET_SSH2_CHANNEL_EXEC; + do { + if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) { + return $channel; + } + } while ($channel++ < NET_SSH2_CHANNEL_SUBSYSTEM); + + return false; + } + /** * Returns the output of an interactive shell * @@ -2509,7 +2815,7 @@ class Net_SSH2 $match = $expect; while (true) { if ($mode == NET_SSH2_READ_REGEX) { - preg_match($expect, $this->interactiveBuffer, $matches); + preg_match($expect, substr($this->interactiveBuffer, -1024), $matches); $match = isset($matches[0]) ? $matches[0] : ''; } $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false; @@ -2567,8 +2873,15 @@ class Net_SSH2 { $this->window_size_server_to_client[NET_SSH2_CHANNEL_SUBSYSTEM] = $this->window_size; - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SUBSYSTEM, $this->window_size, 0x4000); + $packet = pack( + 'CNa*N3', + NET_SSH2_MSG_CHANNEL_OPEN, + strlen('session'), + 'session', + NET_SSH2_CHANNEL_SUBSYSTEM, + $this->window_size, + 0x4000 + ); if (!$this->_send_binary_packet($packet)) { return false; @@ -2581,8 +2894,16 @@ class Net_SSH2 return false; } - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SUBSYSTEM], strlen('subsystem'), 'subsystem', 1, strlen($subsystem), $subsystem); + $packet = pack( + 'CNNa*CNa*', + NET_SSH2_MSG_CHANNEL_REQUEST, + $this->server_channels[NET_SSH2_CHANNEL_SUBSYSTEM], + strlen('subsystem'), + 'subsystem', + 1, + strlen($subsystem), + $subsystem + ); if (!$this->_send_binary_packet($packet)) { return false; } @@ -2592,7 +2913,7 @@ class Net_SSH2 $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM); if ($response === false) { - return false; + return false; } $this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA; @@ -2822,9 +3143,8 @@ class Net_SSH2 if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { switch (ord($payload[0])) { case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 - $this->_string_shift($payload, 1); - extract(unpack('Nlength', $this->_string_shift($payload))); - $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length)); + extract(unpack('Nlength', $this->_string_shift($payload, 4))); + $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length); if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) { return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); @@ -2835,18 +3155,55 @@ class Net_SSH2 case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1 $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload, 4))); - $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length)); - - $this->_string_shift($payload, 4); // skip over client channel + $data = $this->_string_shift($payload, $length); extract(unpack('Nserver_channel', $this->_string_shift($payload, 4))); + switch ($data) { + case 'auth-agent': + case 'auth-agent@openssh.com': + if (isset($this->agent)) { + $new_channel = NET_SSH2_CHANNEL_AGENT_FORWARD; - $packet = pack('CN3a*Na*', - NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, ''); + extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4))); + extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4))); - if (!$this->_send_binary_packet($packet)) { - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); + $this->packet_size_client_to_server[$new_channel] = $remote_window_size; + $this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size; + $this->window_size_client_to_server[$new_channel] = $this->window_size; + + $packet_size = 0x4000; + + $packet = pack( + 'CN4', + NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, + $server_channel, + $new_channel, + $packet_size, + $packet_size + ); + + $this->server_channels[$new_channel] = $server_channel; + $this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION; + if (!$this->_send_binary_packet($packet)) { + return false; + } + } + break; + default: + $packet = pack( + 'CN3a*Na*', + NET_SSH2_MSG_REQUEST_FAILURE, + $server_channel, + NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, + 0, + '', + 0, + '' + ); + + if (!$this->_send_binary_packet($packet)) { + return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); + } } - $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: @@ -2983,48 +3340,63 @@ class Net_SSH2 return ''; } - extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); + extract(unpack('Ctype', $this->_string_shift($response, 1))); - $this->window_size_server_to_client[$channel]-= strlen($response); - - // resize the window, if appropriate - if ($this->window_size_server_to_client[$channel] < 0) { - $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size); - if (!$this->_send_binary_packet($packet)) { - return false; - } - $this->window_size_server_to_client[$channel]+= $this->window_size; + if ($type == NET_SSH2_MSG_CHANNEL_OPEN) { + extract(unpack('Nlength', $this->_string_shift($response, 4))); + } else { + extract(unpack('Nchannel', $this->_string_shift($response, 4))); } - switch ($this->channel_status[$channel]) { - case NET_SSH2_MSG_CHANNEL_OPEN: - switch ($type) { - case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: - extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); - $this->server_channels[$channel] = $server_channel; - extract(unpack('Nwindow_size', $this->_string_shift($response, 4))); - $this->window_size_client_to_server[$channel] = $window_size; - $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); - $this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server']; - return $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended); - //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE: - default: - user_error('Unable to open channel'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); + // will not be setup yet on incoming channel open request + if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) { + $this->window_size_server_to_client[$channel]-= strlen($response); + + // resize the window, if appropriate + if ($this->window_size_server_to_client[$channel] < 0) { + $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size); + if (!$this->_send_binary_packet($packet)) { + return false; } - break; - case NET_SSH2_MSG_CHANNEL_REQUEST: - switch ($type) { - case NET_SSH2_MSG_CHANNEL_SUCCESS: - return true; - case NET_SSH2_MSG_CHANNEL_FAILURE: - return false; - default: - user_error('Unable to fulfill channel request'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - case NET_SSH2_MSG_CHANNEL_CLOSE: - return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended); + $this->window_size_server_to_client[$channel]+= $this->window_size; + } + + switch ($this->channel_status[$channel]) { + case NET_SSH2_MSG_CHANNEL_OPEN: + switch ($type) { + case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: + extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); + $this->server_channels[$channel] = $server_channel; + extract(unpack('Nwindow_size', $this->_string_shift($response, 4))); + if ($window_size < 0) { + $window_size&= 0x7FFFFFFF; + $window_size+= 0x80000000; + } + $this->window_size_client_to_server[$channel] = $window_size; + $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); + $this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server']; + $result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended); + $this->_on_channel_open(); + return $result; + //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE: + default: + user_error('Unable to open channel'); + return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); + } + break; + case NET_SSH2_MSG_CHANNEL_REQUEST: + switch ($type) { + case NET_SSH2_MSG_CHANNEL_SUCCESS: + return true; + case NET_SSH2_MSG_CHANNEL_FAILURE: + return false; + default: + user_error('Unable to fulfill channel request'); + return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); + } + case NET_SSH2_MSG_CHANNEL_CLOSE: + return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended); + } } // ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA @@ -3042,6 +3414,15 @@ class Net_SSH2 */ extract(unpack('Nlength', $this->_string_shift($response, 4))); $data = $this->_string_shift($response, $length); + + if ($channel == NET_SSH2_CHANNEL_AGENT_FORWARD) { + $agent_response = $this->agent->_forward_data($data); + if (!is_bool($agent_response)) { + $this->_send_channel_packet($channel, $agent_response); + } + break; + } + if ($client_channel == $channel) { return $data; } @@ -3275,55 +3656,38 @@ class Net_SSH2 */ function _send_channel_packet($client_channel, $data) { - /* The maximum amount of data allowed is determined by the maximum - packet size for the channel, and the current window size, whichever - is smaller. - - -- http://tools.ietf.org/html/rfc4254#section-5.2 */ - $max_size = min( - $this->packet_size_client_to_server[$client_channel], - $this->window_size_client_to_server[$client_channel] - ); - while (strlen($data) > $max_size) { + while (strlen($data)) { if (!$this->window_size_client_to_server[$client_channel]) { $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; // using an invalid channel will let the buffers be built up for the valid channels - $output = $this->_get_channel_packet(-1); + $this->_get_channel_packet(-1); $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - $max_size = min( - $this->packet_size_client_to_server[$client_channel], - $this->window_size_client_to_server[$client_channel] - ); } + /* The maximum amount of data allowed is determined by the maximum + packet size for the channel, and the current window size, whichever + is smaller. + -- http://tools.ietf.org/html/rfc4254#section-5.2 */ + $max_size = min( + $this->packet_size_client_to_server[$client_channel], + $this->window_size_client_to_server[$client_channel] + ); + $temp = $this->_string_shift($data, $max_size); - $packet = pack('CN2a*', + $packet = pack( + 'CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], strlen($temp), $temp ); - $this->window_size_client_to_server[$client_channel]-= strlen($temp); - if (!$this->_send_binary_packet($packet)) { return false; } } - if (strlen($data) >= $this->window_size_client_to_server[$client_channel]) { - $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - $this->_get_channel_packet(-1); - $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; - } - - $this->window_size_client_to_server[$client_channel]-= strlen($data); - - return $this->_send_binary_packet(pack('CN2a*', - NET_SSH2_MSG_CHANNEL_DATA, - $this->server_channels[$client_channel], - strlen($data), - $data)); + return true; } /** @@ -3352,7 +3716,8 @@ class Net_SSH2 $this->curTimeout = 0; - while (!is_bool($this->_get_channel_packet($client_channel))); + while (!is_bool($this->_get_channel_packet($client_channel))) { + } if ($want_reply) { $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); @@ -3372,7 +3737,7 @@ class Net_SSH2 */ function _disconnect($reason) { - if ($this->bitmap) { + if ($this->bitmap & NET_SSH2_MASK_CONNECTED) { $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); $this->_send_binary_packet($data); $this->bitmap = 0; @@ -3412,7 +3777,7 @@ class Net_SSH2 { $args = func_get_args(); foreach ($args as $arg) { - foreach ($arg as $key=>$value) { + foreach ($arg as $key => $value) { if (!defined($value)) { define($value, $key); } else { @@ -3496,6 +3861,22 @@ class Net_SSH2 return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT); } + /** + * Helper function for agent->_on_channel_open() + * + * Used when channels are created to inform agent + * of said channel opening. Must be called after + * channel open confirmation received + * + * @access private + */ + function _on_channel_open() + { + if (isset($this->agent)) { + $this->agent->_on_channel_open($this); + } + } + /** * Returns all errors * @@ -3769,8 +4150,9 @@ class Net_SSH2 $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - $nLength = $temp['length']; + $rawN = $this->_string_shift($server_public_host_key, $temp['length']); + $n = new Math_BigInteger($rawN, -256); + $nLength = strlen(ltrim($rawN, "\0")); /* $temp = unpack('Nlength', $this->_string_shift($signature, 4)); @@ -3807,7 +4189,7 @@ class Net_SSH2 $s = $s->toBytes(); $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); - $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h; + $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h; if ($s != $h) { user_error('Bad server signature'); diff --git a/System/SSH/Agent.php b/System/SSH/Agent.php index ead905f..ea6d55b 100644 --- a/System/SSH/Agent.php +++ b/System/SSH/Agent.php @@ -1,4 +1,5 @@ - * @copyright MMXIV Jim Wigginton + * @copyright 2014 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net * @internal See http://api.libssh.org/rfc/PROTOCOL.agent @@ -63,6 +64,20 @@ define('SYSTEM_SSH_AGENT_FAILURE', 5); define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13); // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); + + +/**@+ + * Agent forwarding status + * + * @access private + */ +// no forwarding requested and not active +define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0); +// request agent forwarding when opportune +define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1); +// forwarding has been request and is active +define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2); + /**#@-*/ /** @@ -225,6 +240,29 @@ class System_SSH_Agent */ var $fsock; + /** + * Agent forwarding status + * + * @access private + */ + var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE; + + /** + * Buffer for accumulating forwarded authentication + * agent data arriving on SSH data channel destined + * for agent unix socket + * + * @access private + */ + var $socket_buffer = ''; + + /** + * Tracking the number of bytes we are expecting + * to arrive for the agent socket on the SSH data + * channel + */ + var $expected_bytes = 0; + /** * Default Constructor * @@ -310,4 +348,113 @@ class System_SSH_Agent return $identities; } + + /** + * Signal that agent forwarding should + * be requested when a channel is opened + * + * @param Net_SSH2 $ssh + * @return Boolean + * @access public + */ + function startSSHForwarding($ssh) + { + if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) { + $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST; + } + } + + /** + * Request agent forwarding of remote server + * + * @param Net_SSH2 $ssh + * @return Boolean + * @access private + */ + function _request_forwarding($ssh) + { + $request_channel = $ssh->_get_open_channel(); + if ($request_channel === false) { + return false; + } + + $packet = pack( + 'CNNa*C', + NET_SSH2_MSG_CHANNEL_REQUEST, + $ssh->server_channels[$request_channel], + strlen('auth-agent-req@openssh.com'), + 'auth-agent-req@openssh.com', + 1 + ); + + $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST; + + if (!$ssh->_send_binary_packet($packet)) { + return false; + } + + $response = $ssh->_get_channel_packet($request_channel); + if ($response === false) { + return false; + } + + $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN; + $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE; + + return true; + } + + /** + * On successful channel open + * + * This method is called upon successful channel + * open to give the SSH Agent an opportunity + * to take further action. i.e. request agent forwarding + * + * @param Net_SSH2 $ssh + * @access private + */ + function _on_channel_open($ssh) + { + if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) { + $this->_request_forwarding($ssh); + } + } + + /** + * Forward data to SSH Agent and return data reply + * + * @param String $data + * @return data from SSH Agent + * @access private + */ + function _forward_data($data) + { + if ($this->expected_bytes > 0) { + $this->socket_buffer.= $data; + $this->expected_bytes -= strlen($data); + } else { + $agent_data_bytes = current(unpack('N', $data)); + $current_data_bytes = strlen($data); + $this->socket_buffer = $data; + if ($current_data_bytes != $agent_data_bytes + 4) { + $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes; + return false; + } + } + + if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) { + user_error('Connection closed attempting to forward data to SSH agent'); + } + + $this->socket_buffer = ''; + $this->expected_bytes = 0; + + $agent_reply_bytes = current(unpack('N', fread($this->fsock, 4))); + + $agent_reply_data = fread($this->fsock, $agent_reply_bytes); + $agent_reply_data = current(unpack('a*', $agent_reply_data)); + + return pack('Na*', $agent_reply_bytes, $agent_reply_data); + } } diff --git a/System/SSH_Agent.php b/System/SSH_Agent.php index 0a00165..ea434b9 100644 --- a/System/SSH_Agent.php +++ b/System/SSH_Agent.php @@ -30,7 +30,7 @@ * @category System * @package System_SSH_Agent * @author Jim Wigginton - * @copyright MMXIV Jim Wigginton + * @copyright 2014 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net * @internal See http://api.libssh.org/rfc/PROTOCOL.agent