diff --git a/lam/lib/3rdParty/phpseclib/Crypt/AES.php b/lam/lib/3rdParty/phpseclib/Crypt/AES.php index 1677e20d..efbf6339 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/AES.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/AES.php @@ -36,26 +36,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_AES * @author Jim Wigginton * @copyright MMVIII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -90,6 +93,18 @@ define('CRYPT_AES_MODE_ECB', 1); * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 */ define('CRYPT_AES_MODE_CBC', 2); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_AES_MODE_CFB', 3); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_AES_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -139,6 +154,16 @@ class Crypt_AES extends Crypt_Rijndael { */ var $demcrypt; + /** + * mcrypt resource for CFB mode + * + * @see Crypt_AES::encrypt() + * @see Crypt_AES::decrypt() + * @var String + * @access private + */ + var $ecb; + /** * Default Constructor. * @@ -168,6 +193,7 @@ class Crypt_AES extends Crypt_Rijndael { case CRYPT_AES_MODE_MCRYPT: switch ($mode) { case CRYPT_AES_MODE_ECB: + $this->paddable = true; $this->mode = MCRYPT_MODE_ECB; break; case CRYPT_AES_MODE_CTR: @@ -177,22 +203,39 @@ class Crypt_AES extends Crypt_Rijndael { $this->mode = 'ctr'; //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR; break; + case CRYPT_AES_MODE_CFB: + $this->mode = 'ncfb'; + break; + case CRYPT_AES_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; case CRYPT_AES_MODE_CBC: default: + $this->paddable = true; $this->mode = MCRYPT_MODE_CBC; } + $this->debuffer = $this->enbuffer = ''; + break; default: switch ($mode) { case CRYPT_AES_MODE_ECB: + $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_ECB; break; case CRYPT_AES_MODE_CTR: $this->mode = CRYPT_RIJNDAEL_MODE_CTR; break; + case CRYPT_AES_MODE_CFB: + $this->mode = CRYPT_RIJNDAEL_MODE_CFB; + break; + case CRYPT_AES_MODE_OFB: + $this->mode = CRYPT_RIJNDAEL_MODE_OFB; + break; case CRYPT_AES_MODE_CBC: default: + $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_CBC; } } @@ -235,6 +278,7 @@ class Crypt_AES extends Crypt_Rijndael { function encrypt($plaintext) { if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $changed = $this->changed; $this->_mcryptSetup(); /* if ($this->mode == CRYPT_AES_MODE_CTR) { @@ -247,8 +291,44 @@ class Crypt_AES extends Crypt_Rijndael { return $ciphertext; } */ + // re: http://phpseclib.sourceforge.net/cfb-demo.phps + // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's + // rewritten CFB implementation the above outputs the same thing twice. + if ($this->mode == 'ncfb') { + if ($changed) { + $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } - if ($this->mode != 'ctr') { + if (strlen($this->enbuffer)) { + $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); + $this->enbuffer.= $ciphertext; + if (strlen($this->enbuffer) == 16) { + $this->encryptIV = $this->enbuffer; + $this->enbuffer = ''; + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $last_pos = strlen($plaintext) & 0xFFFFFFF0; + $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; + + if (strlen($plaintext) & 0xF) { + if (strlen($ciphertext)) { + $this->encryptIV = substr($ciphertext, -16); + } + $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); + $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; + $ciphertext.= $this->enbuffer; + } + + return $ciphertext; + } + + if ($this->paddable) { $plaintext = $this->_pad($plaintext); } @@ -276,6 +356,7 @@ class Crypt_AES extends Crypt_Rijndael { function decrypt($ciphertext) { if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $changed = $this->changed; $this->_mcryptSetup(); /* if ($this->mode == CRYPT_AES_MODE_CTR) { @@ -288,8 +369,42 @@ class Crypt_AES extends Crypt_Rijndael { return $plaintext; } */ + if ($this->mode == 'ncfb') { + if ($changed) { + $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } - if ($this->mode != 'ctr') { + if (strlen($this->debuffer)) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); + + $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($this->debuffer) == 16) { + $this->decryptIV = $this->debuffer; + $this->debuffer = ''; + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + $ciphertext = substr($ciphertext, strlen($plaintext)); + } else { + $plaintext = ''; + } + + $last_pos = strlen($ciphertext) & 0xFFFFFFF0; + $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; + + if (strlen($ciphertext) & 0xF) { + if (strlen($plaintext)) { + $this->decryptIV = substr($ciphertext, $last_pos - 16, 16); + } + $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); + $this->debuffer = substr($ciphertext, $last_pos); + $plaintext.= $this->debuffer ^ $this->decryptIV; + } + + return $plaintext; + } + + if ($this->paddable) { // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://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) + 15) & 0xFFFFFFF0, chr(0)); @@ -301,7 +416,7 @@ class Crypt_AES extends Crypt_Rijndael { mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); } - return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } return parent::decrypt($ciphertext); @@ -345,7 +460,7 @@ class Crypt_AES extends Crypt_Rijndael { $this->key_size = 32; } - $this->key = substr($this->key, 0, $this->key_size); + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0)); if (!isset($this->enmcrypt)) { diff --git a/lam/lib/3rdParty/phpseclib/Crypt/DES.php b/lam/lib/3rdParty/phpseclib/Crypt/DES.php index 4da005eb..a9f083f7 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/DES.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/DES.php @@ -33,26 +33,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_DES * @author Jim Wigginton * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -97,6 +100,18 @@ define('CRYPT_DES_MODE_ECB', 1); * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 */ define('CRYPT_DES_MODE_CBC', 2); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_DES_MODE_CFB', 3); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_DES_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -191,7 +206,7 @@ class Crypt_DES { * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. * - * @see Crypt_AES::encrypt() + * @see Crypt_DES::encrypt() * @var String * @access private */ @@ -203,21 +218,68 @@ class Crypt_DES { * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. * - * @see Crypt_AES::decrypt() + * @see Crypt_DES::decrypt() * @var String * @access private */ var $demcrypt; /** - * Does the (en|de)mcrypt resource need to be (re)initialized? + * Does the enmcrypt resource need to be (re)initialized? * - * @see setKey() - * @see setIV() + * @see Crypt_DES::setKey() + * @see Crypt_DES::setIV() * @var Boolean * @access private */ - var $changed = true; + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_DES::setKey() + * @see Crypt_DES::setIV() + * @var Boolean + * @access private + */ + var $dechanged = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_DES::Crypt_DES() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_DES::encrypt() + * @var String + * @access private + */ + var $enbuffer = ''; + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_DES::decrypt() + * @var String + * @access private + */ + var $debuffer = ''; + + /** + * mcrypt resource for CFB mode + * + * @see Crypt_DES::encrypt() + * @see Crypt_DES::decrypt() + * @var String + * @access private + */ + var $ecb; /** * Default Constructor. @@ -248,14 +310,22 @@ class Crypt_DES { case CRYPT_DES_MODE_MCRYPT: switch ($mode) { case CRYPT_DES_MODE_ECB: + $this->paddable = true; $this->mode = MCRYPT_MODE_ECB; break; case CRYPT_DES_MODE_CTR: $this->mode = 'ctr'; //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR; break; + case CRYPT_DES_MODE_CFB: + $this->mode = 'ncfb'; + break; + case CRYPT_DES_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; case CRYPT_DES_MODE_CBC: default: + $this->paddable = true; $this->mode = MCRYPT_MODE_CBC; } @@ -263,11 +333,17 @@ class Crypt_DES { default: switch ($mode) { case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CTR: case CRYPT_DES_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_DES_MODE_CTR: + case CRYPT_DES_MODE_CFB: + case CRYPT_DES_MODE_OFB: $this->mode = $mode; break; default: + $this->paddable = true; $this->mode = CRYPT_DES_MODE_CBC; } } @@ -289,7 +365,7 @@ class Crypt_DES { */ function setKey($key) { - $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? substr($key, 0, 8) : $this->_prepareKey($key); + $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key); $this->changed = true; } @@ -365,20 +441,55 @@ class Crypt_DES { */ function encrypt($plaintext) { - if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { + if ($this->paddable) { $plaintext = $this->_pad($plaintext); } if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { + if ($this->enchanged) { if (!isset($this->enmcrypt)) { $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); - $this->changed = false; + if ($this->mode != 'ncfb') { + $this->enchanged = false; + } } - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + if ($this->mode != 'ncfb') { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + if ($this->enchanged) { + $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); + $this->enchanged = false; + } + + if (strlen($this->enbuffer)) { + $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); + $this->enbuffer.= $ciphertext; + if (strlen($this->enbuffer) == 8) { + $this->encryptIV = $this->enbuffer; + $this->enbuffer = ''; + mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); + } + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $last_pos = strlen($plaintext) & 0xFFFFFFF8; + $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; + + if (strlen($plaintext) & 0x7) { + if (strlen($ciphertext)) { + $this->encryptIV = substr($ciphertext, -8); + } + $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); + $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; + $ciphertext.= $this->enbuffer; + } + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); @@ -391,6 +502,8 @@ class Crypt_DES { $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); } + $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: @@ -412,13 +525,78 @@ class Crypt_DES { break; case CRYPT_DES_MODE_CTR: $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); - $ciphertext.= $block ^ $key; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $buffer.= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); + $key = $this->_string_shift($buffer, 8); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); + $ciphertext.= $block ^ $key; + } } if ($this->continuousBuffer) { $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer = substr($key, $start) . $buffer; + } + } + break; + case CRYPT_DES_MODE_CFB: + if (!empty($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $xor = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != 8) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } + $ciphertext.= $iv; + } + + if ($this->continuousBuffer) { + $this->encryptIV = $iv; + } + break; + case CRYPT_DES_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer.= $xor; + $key = $this->_string_shift($buffer, 8); + $ciphertext.= substr($plaintext, $i, 8) ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $ciphertext.= substr($plaintext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer = substr($key, $start) . $buffer; + } } } @@ -436,22 +614,60 @@ class Crypt_DES { */ function decrypt($ciphertext) { - if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { + if ($this->paddable) { // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://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) + 7) & 0xFFFFFFF8, chr(0)); } if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { + if ($this->dechanged) { if (!isset($this->demcrypt)) { $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); - $this->changed = false; + if ($this->mode != 'ncfb') { + $this->dechanged = false; + } } - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + if ($this->mode != 'ncfb') { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + if ($this->dechanged) { + $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); + $this->dechanged = false; + } + + if (strlen($this->debuffer)) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); + + $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($this->debuffer) == 8) { + $this->decryptIV = $this->debuffer; + $this->debuffer = ''; + mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); + } + $ciphertext = substr($ciphertext, strlen($plaintext)); + } else { + $plaintext = ''; + } + + $last_pos = strlen($ciphertext) & 0xFFFFFFF8; + $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; + + if (strlen($ciphertext) & 0x7) { + if (strlen($plaintext)) { + $this->decryptIV = substr($ciphertext, $last_pos - 8, 8); + } + $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); + $this->debuffer = substr($ciphertext, $last_pos); + $plaintext.= $this->debuffer ^ $this->decryptIV; + } + + return $plaintext; + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); @@ -464,6 +680,8 @@ class Crypt_DES { $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); } + $buffer = &$this->debuffer; + $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: @@ -484,17 +702,82 @@ class Crypt_DES { break; case CRYPT_DES_MODE_CTR: $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); - $plaintext.= $block ^ $key; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $buffer.= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); + $key = $this->_string_shift($buffer, 8); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); + $plaintext.= $block ^ $key; + } } if ($this->continuousBuffer) { $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % 8) { + $buffer = substr($key, $start) . $buffer; + } + } + break; + case CRYPT_DES_MODE_CFB: + if (!empty($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) == 8) { + $xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + $block = $this->decryptIV; + } else { + $plaintext = ''; + $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $plaintext.= $block ^ $xor; + if ($continuousBuffer && strlen($block) != 8) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == 8) { + $xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT); + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $block; + } + break; + case CRYPT_DES_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer.= $xor; + $key = $this->_string_shift($buffer, 8); + $plaintext.= substr($ciphertext, $i, 8) ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); + $plaintext.= substr($ciphertext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % 8) { + $buffer = substr($key, $start) . $buffer; + } } } - return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext; + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } /** @@ -939,6 +1222,23 @@ class Crypt_DES { return $temp; } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @return String + * @access private + */ + function _string_shift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } } // vim: ts=4:sw=4:et: diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Hash.php b/lam/lib/3rdParty/phpseclib/Crypt/Hash.php index 21b6d99c..9ac22aec 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Hash.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Hash.php @@ -29,26 +29,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_Hash * @author Jim Wigginton * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -204,7 +207,8 @@ class Crypt_Hash { switch ($hash) { case 'md2': - $mode = CRYPT_HASH_MODE_INTERNAL; + $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ? + CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL; break; case 'sha384': case 'sha512': @@ -236,6 +240,7 @@ class Crypt_Hash { case 'md5-96': $this->hash = 'md5'; return; + case 'md2': case 'sha256': case 'sha384': case 'sha512': @@ -303,7 +308,7 @@ class Crypt_Hash { resultant L byte string as the actual key to HMAC." -- http://tools.ietf.org/html/rfc2104#section-2 */ - $key = strlen($this->key) > $this->b ? call_user_func($this->$hash, $this->key) : $this->key; + $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; $key = str_pad($key, $this->b, chr(0)); // step 1 $temp = $this->ipad ^ $key; // step 2 @@ -332,7 +337,7 @@ class Crypt_Hash { /** * Returns the hash length (in bytes) * - * @access private + * @access public * @return Integer */ function getLength() @@ -404,7 +409,10 @@ class Crypt_Hash { $l = chr(0); for ($i = 0; $i < $length; $i+= 16) { for ($j = 0; $j < 16; $j++) { - $c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); + // RFC1319 incorrectly states that C[j] should be set to S[c xor L] + //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); + // per , however, C[j] should be set to S[c xor L] xor C[j] + $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j])); $l = $c[$j]; } } diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RC4.php b/lam/lib/3rdParty/phpseclib/Crypt/RC4.php index 1d26dd14..f7b22fbf 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/RC4.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/RC4.php @@ -35,26 +35,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_RC4 * @author Jim Wigginton * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -159,6 +162,15 @@ class Crypt_RC4 { */ var $mode; + /** + * Continuous Buffer status + * + * @see Crypt_RC4::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + /** * Default Constructor. * diff --git a/lam/lib/3rdParty/phpseclib/Crypt/RSA.php b/lam/lib/3rdParty/phpseclib/Crypt/RSA.php index 351fb97b..7b795d1f 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/RSA.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/RSA.php @@ -42,26 +42,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_RSA * @author Jim Wigginton * @copyright MMIX Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -170,6 +173,14 @@ define('CRYPT_RSA_MODE_OPENSSL', 2); * Used by OpenSSH */ define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0); +/** + * PuTTY formatted private key + */ +define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1); +/** + * XML formatted private key + */ +define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2); /**#@-*/ /**#@+ @@ -190,17 +201,21 @@ define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0); * * 1, n, modulo, modulus */ -define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 1); +define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3); /** * PKCS#1 formatted public key */ -define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 2); +define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4); +/** + * XML formatted public key + */ +define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5); /** * OpenSSH formatted public key * * Place in $HOME/.ssh/authorized_keys */ -define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 3); +define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6); /**#@-*/ /** @@ -372,6 +387,30 @@ class Crypt_RSA { */ var $password = ''; + /** + * Components + * + * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions - + * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't. + * + * @see Crypt_RSA::_start_element_handler() + * @var Array + * @access private + */ + var $components = array(); + + /** + * Current String + * + * For use with parsing XML formatted keys. + * + * @see Crypt_RSA::_character_handler() + * @see Crypt_RSA::_stop_element_handler() + * @var Mixed + * @access private + */ + var $current; + /** * The constructor * @@ -492,16 +531,16 @@ class Crypt_RSA { $timeout-= time() - $start; $start = time(); if ($timeout <= 0) { - return serialize(array( + return array( 'privatekey' => '', 'publickey' => '', - 'partialkey' => array( + 'partialkey' => serialize(array( 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents - ) - )); + )) + ); } } @@ -516,15 +555,22 @@ class Crypt_RSA { } if ($primes[$i] === false) { // if we've reached the timeout - return array( - 'privatekey' => '', - 'publickey' => '', - 'partialkey' => empty($primes) ? '' : serialize(array( - 'primes' => array_slice($primes, 0, $i - 1), + if (count($primes) > 1) { + $partialkey = ''; + } else { + array_pop($primes); + $partialkey = serialize(array( + 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents - )) + )); + } + + return array( + 'privatekey' => '', + 'publickey' => '', + 'partialkey' => $partialkey ); } @@ -770,7 +816,7 @@ class Crypt_RSA { * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { $iv = pack('H*', trim($matches[2])); - $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key + $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key); $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; @@ -778,6 +824,19 @@ class Crypt_RSA { $ciphertext = $key; } switch ($matches[1]) { + case 'AES-128-CBC': + if (!class_exists('Crypt_AES')) { + require_once('Crypt/AES.php'); + } + $symkey = substr($symkey, 0, 16); + $crypto = new Crypt_AES(); + break; + case 'DES-EDE3-CFB': + if (!class_exists('Crypt_TripleDES')) { + require_once('Crypt/TripleDES.php'); + } + $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB); + break; case 'DES-EDE3-CBC': if (!class_exists('Crypt_TripleDES')) { require_once('Crypt/TripleDES.php'); @@ -927,9 +986,164 @@ class Crypt_RSA { 'publicExponent' => $publicExponent ); } + // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue + // http://en.wikipedia.org/wiki/XML_Signature + case CRYPT_RSA_PRIVATE_FORMAT_XML: + case CRYPT_RSA_PUBLIC_FORMAT_XML: + $this->components = array(); + + $xml = xml_parser_create('UTF-8'); + xml_set_object($xml, $this); + xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler'); + xml_set_character_data_handler($xml, '_data_handler'); + if (!xml_parse($xml, $key)) { + return false; + } + + return $this->components; + // from PuTTY's SSHPUBK.C + case CRYPT_RSA_PRIVATE_FORMAT_PUTTY: + $components = array(); + $key = preg_split('#\r\n|\r|\n#', $key); + $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0])); + if ($type != 'ssh-rsa') { + return false; + } + $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); + + $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3])); + $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); + $public = substr($public, 11); + extract(unpack('Nlength', $this->_string_shift($public, 4))); + $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256); + extract(unpack('Nlength', $this->_string_shift($public, 4))); + $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256); + + $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4])); + $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength)))); + + switch ($encryption) { + case 'aes256-cbc': + if (!class_exists('Crypt_AES')) { + require_once('Crypt/AES.php'); + } + $symkey = ''; + $sequence = 0; + while (strlen($symkey) < 32) { + $temp = pack('Na*', $sequence++, $this->password); + $symkey.= pack('H*', sha1($temp)); + } + $symkey = substr($symkey, 0, 32); + $crypto = new Crypt_AES(); + } + + if ($encryption != 'none') { + $crypto->setKey($symkey); + $crypto->disablePadding(); + $private = $crypto->decrypt($private); + if ($private === false) { + return false; + } + } + + extract(unpack('Nlength', $this->_string_shift($private, 4))); + $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256); + extract(unpack('Nlength', $this->_string_shift($private, 4))); + $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256)); + extract(unpack('Nlength', $this->_string_shift($private, 4))); + $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256); + + $temp = $components['primes'][1]->subtract($this->one); + $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp)); + $temp = $components['primes'][2]->subtract($this->one); + $components['exponents'][] = $components['publicExponent']->modInverse($temp); + + extract(unpack('Nlength', $this->_string_shift($private, 4))); + $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256)); + + return $components; } } + /** + * Start Element Handler + * + * Called by xml_set_element_handler() + * + * @access private + * @param Resource $parser + * @param String $name + * @param Array $attribs + */ + function _start_element_handler($parser, $name, $attribs) + { + //$name = strtoupper($name); + switch ($name) { + case 'MODULUS': + $this->current = &$this->components['modulus']; + break; + case 'EXPONENT': + $this->current = &$this->components['publicExponent']; + break; + case 'P': + $this->current = &$this->components['primes'][1]; + break; + case 'Q': + $this->current = &$this->components['primes'][2]; + break; + case 'DP': + $this->current = &$this->components['exponents'][1]; + break; + case 'DQ': + $this->current = &$this->components['exponents'][2]; + break; + case 'INVERSEQ': + $this->current = &$this->components['coefficients'][2]; + break; + case 'D': + $this->current = &$this->components['privateExponent']; + break; + default: + unset($this->current); + } + $this->current = ''; + } + + /** + * Stop Element Handler + * + * Called by xml_set_element_handler() + * + * @access private + * @param Resource $parser + * @param String $name + */ + function _stop_element_handler($parser, $name) + { + //$name = strtoupper($name); + if ($name == 'RSAKEYVALUE') { + return; + } + $this->current = new Math_BigInteger(base64_decode($this->current), 256); + } + + /** + * Data Handler + * + * Called by xml_set_character_data_handler() + * + * @access private + * @param Resource $parser + * @param String $data + */ + function _data_handler($parser, $data) + { + if (!isset($this->current) || is_object($this->current)) { + return; + } + $this->current.= trim($data); + } + /** * Loads a public or private key * @@ -939,9 +1153,27 @@ class Crypt_RSA { * @param String $key * @param Integer $type optional */ - function loadKey($key, $type = CRYPT_RSA_PRIVATE_FORMAT_PKCS1) + function loadKey($key, $type = false) { - $components = $this->_parseKey($key, $type); + if ($type === false) { + $types = array( + CRYPT_RSA_PUBLIC_FORMAT_RAW, + CRYPT_RSA_PRIVATE_FORMAT_PKCS1, + CRYPT_RSA_PRIVATE_FORMAT_XML, + CRYPT_RSA_PRIVATE_FORMAT_PUTTY, + CRYPT_RSA_PUBLIC_FORMAT_OPENSSH + ); + foreach ($types as $type) { + $components = $this->_parseKey($key, $type); + if ($components !== false) { + break; + } + } + + } else { + $components = $this->_parseKey($key, $type); + } + if ($components === false) { return false; } @@ -1002,10 +1234,15 @@ class Crypt_RSA { function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { $components = $this->_parseKey($key, $type); + if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { + user_error('Trying to load a public key? Use loadKey() instead. It\'s called loadKey() and not loadPrivateKey() for a reason.', E_USER_NOTICE); return false; } + $this->publicExponent = $components['publicExponent']; + + return true; } /** @@ -1365,7 +1602,6 @@ class Crypt_RSA { function _blind($x, $r, $i) { $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); - $x = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->modInverse($this->primes[$i]); @@ -1662,6 +1898,7 @@ class Crypt_RSA { $c = $this->_os2ip($c); $m = $this->_rsadp($c); + if ($m === false) { user_error('Decryption error', E_USER_NOTICE); return false; @@ -1752,8 +1989,8 @@ class Crypt_RSA { return false; } - $maskedDB = substr($em, 0, $em - $this->hLen - 1); - $h = substr($em, $em - $this->hLen - 1, $this->hLen); + $maskedDB = substr($em, 0, -$this->hLen - 1); + $h = substr($em, -$this->hLen - 1, $this->hLen); $temp = chr(0xFF << ($emBits & 7)); if ((~$maskedDB[0] & $temp) != $temp) { return false; diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Random.php b/lam/lib/3rdParty/phpseclib/Crypt/Random.php index a5c7f2ba..1ffc7465 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Random.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Random.php @@ -15,26 +15,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_Random * @author Jim Wigginton * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -61,14 +64,14 @@ function crypt_random($min = 0, $max = 0x7FFFFFFF) } // see http://en.wikipedia.org/wiki//dev/random - // if open_basedir is enabled file_exists() will ouput an "open_basedir restriction in effect" warning, - // so we suppress it. - if (@file_exists('/dev/urandom')) { - static $fp; - if (!$fp) { - $fp = fopen('/dev/urandom', 'rb'); - } - extract(unpack('Nrandom', fread($fp, 4))); + static $urandom = true; + if ($urandom === true) { + // Warning's will be output unles the error suppression operator is used. Errors such as + // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc. + $urandom = @fopen('/dev/urandom', 'rb'); + } + if (!is_bool($urandom)) { + extract(unpack('Nrandom', fread($urandom, 4))); // say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this: // -4 % 3 + 0 = -1, even though -1 < $min diff --git a/lam/lib/3rdParty/phpseclib/Crypt/Rijndael.php b/lam/lib/3rdParty/phpseclib/Crypt/Rijndael.php index c0d915c2..b98619e1 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/Rijndael.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/Rijndael.php @@ -44,26 +44,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_Rijndael * @author Jim Wigginton * @copyright MMVIII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -93,6 +96,18 @@ define('CRYPT_RIJNDAEL_MODE_ECB', 1); * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 */ define('CRYPT_RIJNDAEL_MODE_CBC', 2); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_CFB', 3); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_OFB', 4); /**#@-*/ /**#@+ @@ -356,6 +371,33 @@ class Crypt_Rijndael { */ var $dt3; + /** + * Is the mode one that is paddable? + * + * @see Crypt_Rijndael::Crypt_Rijndael() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Rijndael::encrypt() + * @var String + * @access private + */ + var $enbuffer = array('encrypted' => '', 'xor' => ''); + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Rijndael::decrypt() + * @var String + * @access private + */ + var $debuffer = array('ciphertext' => ''); + /** * Default Constructor. * @@ -371,10 +413,16 @@ class Crypt_Rijndael { switch ($mode) { case CRYPT_RIJNDAEL_MODE_ECB: case CRYPT_RIJNDAEL_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; case CRYPT_RIJNDAEL_MODE_CTR: + case CRYPT_RIJNDAEL_MODE_CFB: + case CRYPT_RIJNDAEL_MODE_OFB: $this->mode = $mode; break; default: + $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_CBC; } @@ -611,11 +659,13 @@ class Crypt_Rijndael { function encrypt($plaintext) { $this->_setup(); - if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) { + if ($this->paddable) { $plaintext = $this->_pad($plaintext); } $block_size = $this->block_size; + $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: @@ -637,13 +687,78 @@ class Crypt_Rijndael { break; case CRYPT_RIJNDAEL_MODE_CTR: $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $ciphertext.= $block ^ $key; + if (!empty($buffer)) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $key = $this->_string_shift($buffer, $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->_generate_xor($block_size, $xor)); + $ciphertext.= $block ^ $key; + } } if ($this->continuousBuffer) { $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer = substr($key, $start) . $buffer; + } + } + break; + case CRYPT_RIJNDAEL_MODE_CFB: + if (!empty($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $xor = $this->_encryptBlock($iv); + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != $block_size) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } + $ciphertext.= $iv; + } + + if ($this->continuousBuffer) { + $this->encryptIV = $iv; + } + break; + case CRYPT_RIJNDAEL_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $buffer.= $xor; + $key = $this->_string_shift($buffer, $block_size); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer = substr($key, $start) . $buffer; + } } } @@ -664,13 +779,15 @@ class Crypt_Rijndael { { $this->_setup(); - if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) { + if ($this->paddable) { // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://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 - 1) % $this->block_size, chr(0)); + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); } $block_size = $this->block_size; + $buffer = &$this->debuffer; + $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: @@ -691,17 +808,82 @@ class Crypt_Rijndael { break; case CRYPT_RIJNDAEL_MODE_CTR: $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $plaintext.= $block ^ $key; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $key = $this->_string_shift($buffer, $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->_generate_xor($block_size, $xor)); + $plaintext.= $block ^ $key; + } } if ($this->continuousBuffer) { $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer = substr($key, $start) . $buffer; + } + } + break; + case CRYPT_RIJNDAEL_MODE_CFB: + if (!empty($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) == $block_size) { + $xor = $this->_encryptBlock($buffer['ciphertext']); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + $block = $this->decryptIV; + } else { + $plaintext = ''; + $xor = $this->_encryptBlock($this->decryptIV); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $plaintext.= $block ^ $xor; + if ($continuousBuffer && strlen($block) != $block_size) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == $block_size) { + $xor = $this->_encryptBlock($block); + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $block; + } + break; + case CRYPT_RIJNDAEL_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $buffer.= $xor; + $key = $this->_string_shift($buffer, $block_size); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer = substr($key, $start) . $buffer; + } } } - return $this->mode != CRYPT_RIJNDAEL_MODE_CTR ? $this->_unpad($plaintext) : $plaintext; + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } /** diff --git a/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php b/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php index 150b4efe..34432921 100644 --- a/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php +++ b/lam/lib/3rdParty/phpseclib/Crypt/TripleDES.php @@ -27,26 +27,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Crypt * @package Crypt_TripleDES * @author Jim Wigginton * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -54,14 +57,14 @@ /** * Include Crypt_DES */ -require_once 'DES.php'; +require_once('DES.php'); /** * 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_DES_MODE_3CBC', 3); +define('CRYPT_DES_MODE_3CBC', -2); /** * Encrypt / decrypt using outer chaining @@ -156,7 +159,7 @@ class Crypt_TripleDES { * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. * - * @see Crypt_AES::encrypt() + * @see Crypt_TripleDES::encrypt() * @var String * @access private */ @@ -168,21 +171,68 @@ class Crypt_TripleDES { * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. * - * @see Crypt_AES::decrypt() + * @see Crypt_TripleDES::decrypt() * @var String * @access private */ var $demcrypt; /** - * Does the (en|de)mcrypt resource need to be (re)initialized? + * Does the enmcrypt resource need to be (re)initialized? * - * @see setKey() - * @see setIV() + * @see Crypt_TripleDES::setKey() + * @see Crypt_TripleDES::setIV() * @var Boolean * @access private */ - var $changed = true; + var $enchanged = true; + + /** + * Does the demcrypt resource need to be (re)initialized? + * + * @see Crypt_TripleDES::setKey() + * @see Crypt_TripleDES::setIV() + * @var Boolean + * @access private + */ + var $dechanged = true; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_TripleDES::Crypt_TripleDES() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_TripleDES::encrypt() + * @var String + * @access private + */ + var $enbuffer = ''; + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_TripleDES::decrypt() + * @var String + * @access private + */ + var $debuffer = ''; + + /** + * mcrypt resource for CFB mode + * + * @see Crypt_TripleDES::encrypt() + * @see Crypt_TripleDES::decrypt() + * @var String + * @access private + */ + var $ecb; /** * Default Constructor. @@ -229,13 +279,21 @@ class Crypt_TripleDES { case CRYPT_DES_MODE_MCRYPT: switch ($mode) { case CRYPT_DES_MODE_ECB: + $this->paddable = true; $this->mode = MCRYPT_MODE_ECB; break; case CRYPT_DES_MODE_CTR: $this->mode = 'ctr'; break; + case CRYPT_DES_MODE_CFB: + $this->mode = 'ncfb'; + break; + case CRYPT_DES_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; case CRYPT_DES_MODE_CBC: default: + $this->paddable = true; $this->mode = MCRYPT_MODE_CBC; } @@ -254,11 +312,17 @@ class Crypt_TripleDES { switch ($mode) { case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CTR: case CRYPT_DES_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_DES_MODE_CTR: + case CRYPT_DES_MODE_CFB: + case CRYPT_DES_MODE_OFB: $this->mode = $mode; break; default: + $this->paddable = true; $this->mode = CRYPT_DES_MODE_CBC; } } @@ -285,6 +349,8 @@ class Crypt_TripleDES { // 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); + } else { + $key = str_pad($key, 8, chr(0)); } $this->key = $key; switch (true) { @@ -294,7 +360,7 @@ class Crypt_TripleDES { $this->des[1]->setKey(substr($key, 8, 8)); $this->des[2]->setKey(substr($key, 16, 8)); } - $this->changed = true; + $this->enchanged = $this->dechanged = true; } /** @@ -314,7 +380,7 @@ class Crypt_TripleDES { $this->des[1]->setIV($iv); $this->des[2]->setIV($iv); } - $this->changed = true; + $this->enchanged = $this->dechanged = true; } /** @@ -323,9 +389,9 @@ class Crypt_TripleDES { * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the * plaintext / ciphertext in CTR mode. * - * @see Crypt_DES::decrypt() - * @see Crypt_DES::encrypt() - * @access public + * @see Crypt_TripleDES::decrypt() + * @see Crypt_TripleDES::encrypt() + * @access private * @param Integer $length * @param String $iv */ @@ -363,7 +429,7 @@ class Crypt_TripleDES { */ function encrypt($plaintext) { - if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { + if ($this->paddable) { $plaintext = $this->_pad($plaintext); } @@ -375,15 +441,50 @@ class Crypt_TripleDES { } if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { + if ($this->enchanged) { if (!isset($this->enmcrypt)) { $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); } mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - $this->changed = false; + if ($this->mode != 'ncfb') { + $this->enchanged = false; + } } - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + if ($this->mode != 'ncfb') { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + if ($this->enchanged) { + $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); + $this->enchanged = false; + } + + if (strlen($this->enbuffer)) { + $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); + $this->enbuffer.= $ciphertext; + if (strlen($this->enbuffer) == 8) { + $this->encryptIV = $this->enbuffer; + $this->enbuffer = ''; + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $last_pos = strlen($plaintext) & 0xFFFFFFF8; + $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; + + if (strlen($plaintext) & 0x7) { + if (strlen($ciphertext)) { + $this->encryptIV = substr($ciphertext, -8); + } + $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); + $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; + $ciphertext.= $this->enbuffer; + } + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); @@ -398,17 +499,21 @@ class Crypt_TripleDES { return $this->des[0]->encrypt($plaintext); } - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $plaintext = str_pad($plaintext, ceil(strlen($plaintext) / 8) * 8, chr(0)); - $des = $this->des; + $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: for ($i = 0; $i < strlen($plaintext); $i+=8) { $block = substr($plaintext, $i, 8); + // all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something. + // only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that + // function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make + // encryption and decryption take more time, per this: + // + // http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); @@ -431,16 +536,92 @@ class Crypt_TripleDES { break; case CRYPT_DES_MODE_CTR: $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $key = $this->_generate_xor(8, $xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $block = substr($plaintext, $i, 8); - $ciphertext.= $block ^ $key; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $key = $this->_generate_xor(8, $xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $buffer.= $key; + $key = $this->_string_shift($buffer, 8); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $key = $this->_generate_xor(8, $xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $ciphertext.= $block ^ $key; + } } if ($this->continuousBuffer) { $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer = substr($key, $start) . $buffer; + } + } + break; + case CRYPT_DES_MODE_CFB: + if (!empty($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=8) { + $block = substr($plaintext, $i, 8); + $iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT); + $iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT); + $xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT); + + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != 8) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } + $ciphertext.= $iv; + } + + if ($this->continuousBuffer) { + $this->encryptIV = $iv; + } + break; + case CRYPT_DES_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer.= $xor; + $key = $this->_string_shift($buffer, 8); + $ciphertext.= substr($plaintext, $i, 8) ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=8) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $ciphertext.= substr($plaintext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer = substr($key, $start) . $buffer; + } } } @@ -461,36 +642,78 @@ class Crypt_TripleDES { return $this->_unpad($plaintext); } - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://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) + 7) & 0xFFFFFFF8, chr(0)); + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://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) + 7) & 0xFFFFFFF8, chr(0)); + } if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { + if ($this->dechanged) { if (!isset($this->demcrypt)) { $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); } mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - $this->changed = false; + if ($this->mode != 'ncfb') { + $this->dechanged = false; + } } - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + if ($this->mode != 'ncfb') { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + if ($this->dechanged) { + $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); + $this->dechanged = false; + } + + if (strlen($this->debuffer)) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); + + $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($this->debuffer) == 8) { + $this->decryptIV = $this->debuffer; + $this->debuffer = ''; + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + $ciphertext = substr($ciphertext, strlen($plaintext)); + } else { + $plaintext = ''; + } + + $last_pos = strlen($ciphertext) & 0xFFFFFFF8; + $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; + + if (strlen($ciphertext) & 0x7) { + if (strlen($plaintext)) { + $this->decryptIV = substr($ciphertext, $last_pos - 8, 8); + } + $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); + $this->debuffer = substr($ciphertext, $last_pos); + $plaintext.= $this->debuffer ^ $this->decryptIV; + } + + return $plaintext; + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); } - return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } if (strlen($this->key) <= 8) { $this->des[0]->mode = $this->mode; - - return $this->_unpad($this->des[0]->decrypt($plaintext)); + $plaintext = $this->des[0]->decrypt($ciphertext); + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } $des = $this->des; + $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: @@ -518,20 +741,99 @@ class Crypt_TripleDES { break; case CRYPT_DES_MODE_CTR: $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $key = $this->_generate_xor(8, $xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $block = substr($ciphertext, $i, 8); - $plaintext.= $block ^ $key; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $key = $this->_generate_xor(8, $xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $buffer.= $key; + $key = $this->_string_shift($buffer, 8); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $key = $this->_generate_xor(8, $xor); + $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); + $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); + $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); + $plaintext.= $block ^ $key; + } } if ($this->continuousBuffer) { $this->decryptIV = $xor; + if ($start = strlen($plaintext) & 7) { + $buffer = substr($key, $start) . $buffer; + } + } + break; + case CRYPT_DES_MODE_CFB: + if (!empty($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) == 8) { + $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + $block = $this->decryptIV; + } else { + $plaintext = ''; + $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $plaintext.= $block ^ $xor; + if ($continuousBuffer && strlen($block) != 8) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == 8) { + $xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $block; + } + break; + case CRYPT_DES_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer.= $xor; + $key = $this->_string_shift($buffer, 8); + $plaintext.= substr($ciphertext, $i, 8) ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=8) { + $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $plaintext.= substr($ciphertext, $i, 8) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) & 7) { + $buffer = substr($key, $start) . $buffer; + } } } - return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext; + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } /** @@ -684,6 +986,23 @@ class Crypt_TripleDES { return substr($text, 0, -$length); } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @return String + * @access private + */ + function _string_shift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } } // vim: ts=4:sw=4:et: diff --git a/lam/lib/3rdParty/phpseclib/Math/BigInteger.php b/lam/lib/3rdParty/phpseclib/Math/BigInteger.php index 1dabf3ac..defe7081 100644 --- a/lam/lib/3rdParty/phpseclib/Math/BigInteger.php +++ b/lam/lib/3rdParty/phpseclib/Math/BigInteger.php @@ -47,26 +47,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Math * @package Math_BigInteger * @author Jim Wigginton * @copyright MMVI Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://pear.php.net/package/Math_BigInteger */ @@ -596,9 +599,12 @@ class Math_BigInteger { { $hex = $this->toHex($twos_compliment); $bits = ''; - for ($i = 0; $i < strlen($hex); $i+=8) { + for ($i = 0, $end = strlen($hex) & 0xFFFFFFF8; $i < $end; $i+=8) { $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT); } + if ($end != strlen($hex)) { // hexdec('') == 0 + $bits.= str_pad(decbin(hexdec(substr($hex, $end))), strlen($hex) & 7, '0', STR_PAD_LEFT); + } return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); } diff --git a/lam/lib/3rdParty/phpseclib/Net/SFTP.php b/lam/lib/3rdParty/phpseclib/Net/SFTP.php index 625d2908..75d0cacc 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SFTP.php +++ b/lam/lib/3rdParty/phpseclib/Net/SFTP.php @@ -28,27 +28,29 @@ * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Net * @package Net_SFTP * @author Jim Wigginton * @copyright MMIX Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id$ + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ @@ -74,7 +76,7 @@ define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX); /** * SFTP channel constant * - * Net_SSH2::exec() uses 0 and Net_SSH2::interactiveRead() / Net_SSH2::interactiveWrite() use 1. + * Net_SSH2::exec() uses 0 and Net_SSH2::read() / Net_SSH2::write() use 1. * * @see Net_SSH2::_send_channel_packet() * @see Net_SSH2::_get_channel_packet() @@ -210,7 +212,16 @@ class Net_SFTP extends Net_SSH2 { * @var String * @access private */ - var $errors = array(); + var $sftp_errors = array(); + + /** + * File Type + * + * @see Net_SFTP::_parseLongname() + * @var Integer + * @access private + */ + var $fileType = 0; /** * Default Constructor. @@ -236,7 +247,7 @@ class Net_SFTP extends Net_SSH2 { 4 => 'NET_SFTP_CLOSE', 5 => 'NET_SFTP_READ', 6 => 'NET_SFTP_WRITE', - 8 => 'NET_SFTP_FSTAT', + 7 => 'NET_SFTP_LSTAT', 9 => 'NET_SFTP_SETSTAT', 11 => 'NET_SFTP_OPENDIR', 12 => 'NET_SFTP_READDIR', @@ -279,7 +290,11 @@ class Net_SFTP extends Net_SSH2 { 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+ 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS', 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME', - -1 => 'NET_SFTP_ATTR_EXTENDED' // unpack('N', "\xFF\xFF\xFF\xFF") == array(1 => int(-1)) + // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers + // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in + // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000. + // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored. + -1 << 31 => 'NET_SFTP_ATTR_EXTENDED' ); // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name @@ -290,11 +305,20 @@ class Net_SFTP extends Net_SSH2 { 0x00000008 => 'NET_SFTP_OPEN_CREATE', 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE' ); + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 + // see Net_SFTP::_parseLongname() for an explanation + $this->file_types = array( + 1 => 'NET_SFTP_TYPE_REGULAR', + 2 => 'NET_SFTP_TYPE_DIRECTORY', + 3 => 'NET_SFTP_TYPE_SYMLINK', + 4 => 'NET_SFTP_TYPE_SPECIAL' + ); $this->_define_array( $this->packet_types, $this->status_codes, $this->attributes, - $this->open_flags + $this->open_flags, + $this->file_types ); } @@ -492,6 +516,11 @@ class Net_SFTP extends Net_SSH2 { $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway extract(unpack('Nlength', $this->_string_shift($response, 4))); $realpath = $this->_string_shift($response, $length); + // the following is SFTPv3 only code. see Net_SFTP::_parseLongname() for more information. + // per the above comment, this is a shot in the dark that, on most servers, won't help us in determining + // the file type for Net_SFTP::stat() and Net_SFTP::lstat() but it's worth a shot. + extract(unpack('Nlength', $this->_string_shift($response, 4))); + $this->fileType = $this->_parseLongname($this->_string_shift($response, $length)); break; case NET_SFTP_STATUS: extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); @@ -579,7 +608,7 @@ class Net_SFTP extends Net_SSH2 { } /** - * Returns a list of files in the given directory + * Returns a detailed list of files in the given directory * * @param optional String $dir * @return Mixed @@ -590,6 +619,13 @@ class Net_SFTP extends Net_SSH2 { return $this->_list($dir, true); } + /** + * Reads a list, be it detailed or not, of files in the given directory + * + * @param optional String $dir + * @return Mixed + * @access private + */ function _list($dir, $raw = true) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { @@ -641,12 +677,16 @@ class Net_SFTP extends Net_SSH2 { extract(unpack('Nlength', $this->_string_shift($response, 4))); $shortname = $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->_string_shift($response, $length); // SFTPv4+ drop this field - the "longname" field + $longname = $this->_string_shift($response, $length); $attributes = $this->_parseAttributes($response); // we also don't care about the attributes if (!$raw) { $contents[] = $shortname; } else { $contents[$shortname] = $attributes; + $fileType = $this->_parseLongname($longname); + if ($fileType) { + $contents[$shortname]['type'] = $fileType; + } } // 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. @@ -693,7 +733,7 @@ class Net_SFTP extends Net_SSH2 { * * Files larger than 4GB will show up as being exactly 4GB. * - * @param optional String $dir + * @param String $filename * @return Mixed * @access public */ @@ -708,17 +748,82 @@ class Net_SFTP extends Net_SSH2 { return false; } + return $this->_size($filename); + } + + /** + * Returns general information about a file. + * + * Returns an array on success and false otherwise. + * + * @param String $filename + * @return Mixed + * @access public + */ + function stat($filename) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + return false; + } + + $filename = $this->_realpath($filename); + if ($filename === false) { + return false; + } + + return $this->_stat($filename, NET_SFTP_STAT); + } + + /** + * Returns general information about a file or symbolic link. + * + * Returns an array on success and false otherwise. + * + * @param String $filename + * @return Mixed + * @access public + */ + function lstat($filename) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + return false; + } + + $filename = $this->_realpath($filename); + if ($filename === false) { + return false; + } + + return $this->_stat($filename, NET_SFTP_LSTAT); + } + + /** + * Returns general information about a file or symbolic link + * + * Determines information without calling Net_SFTP::_realpath(). + * The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT. + * + * @param String $filename + * @param Integer $type + * @return Mixed + * @access private + */ + function _stat($filename, $type) + { // SFTPv4+ adds an additional 32-bit integer field - flags - to the following: $packet = pack('Na*', strlen($filename), $filename); - if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) { + if (!$this->_send_sftp_packet($type, $packet)) { return false; } $response = $this->_get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_ATTRS: - $attrs = $this->_parseAttributes($response); - return $attrs['size']; + $attributes = $this->_parseAttributes($response); + if ($this->fileType) { + $attributes['type'] = $this->fileType; + } + return $attributes; case NET_SFTP_STATUS: extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); @@ -729,6 +834,21 @@ class Net_SFTP extends Net_SSH2 { return false; } + /** + * Returns the file size, in bytes, or false, on failure + * + * Determines the size without calling Net_SFTP::_realpath() + * + * @param String $filename + * @return Mixed + * @access private + */ + function _size($filename) + { + $result = $this->_stat($filename, NET_SFTP_LSTAT); + return $result === false ? false : $result['size']; + } + /** * Set permissions on a file. * @@ -894,7 +1014,7 @@ class Net_SFTP extends Net_SSH2 { * * @param String $remote_file * @param String $data - * @param optional Integer $flags + * @param optional Integer $mode * @return Boolean * @access public * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode(). @@ -937,7 +1057,7 @@ class Net_SFTP extends Net_SSH2 { user_error("$data is not a valid file", E_USER_NOTICE); return false; } - $fp = fopen($data, 'rb'); + $fp = @fopen($data, 'rb'); if (!$fp) { return false; } @@ -950,7 +1070,7 @@ class Net_SFTP extends Net_SSH2 { $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; - $sftp_packet_size = 34000; // PuTTY uses 4096 + $sftp_packet_size = 4096; // PuTTY uses 4096 $i = 0; while ($sent < $size) { $temp = $mode == NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : $this->_string_shift($data, $sftp_packet_size); @@ -1051,6 +1171,11 @@ class Net_SFTP extends Net_SSH2 { return false; } + $size = $this->_size($remote_file); + if ($size === false) { + return false; + } + $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0); if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { return false; @@ -1070,25 +1195,6 @@ class Net_SFTP extends Net_SSH2 { return false; } - $packet = pack('Na*', strlen($handle), $handle); - if (!$this->_send_sftp_packet(NET_SFTP_FSTAT, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_ATTRS: - $attrs = $this->_parseAttributes($response); - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - default: - user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - if ($local_file !== false) { $fp = fopen($local_file, 'wb'); if (!$fp) { @@ -1099,7 +1205,7 @@ class Net_SFTP extends Net_SSH2 { } $read = 0; - while ($read < $attrs['size']) { + while ($read < $size) { $packet = pack('Na*N3', strlen($handle), $handle, 0, $read, 1 << 20); if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { return false; @@ -1136,6 +1242,14 @@ class Net_SFTP extends Net_SSH2 { return false; } + extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); + $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); + + // check the status from the NET_SFTP_STATUS case in the above switch after the file has been closed + if ($status != NET_SFTP_STATUS_OK) { + return false; + } + extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { extract(unpack('Nlength', $this->_string_shift($response, 4))); @@ -1164,7 +1278,7 @@ class Net_SFTP extends Net_SSH2 { return false; } - $remote_file = $this->_realpath($path); + $path = $this->_realpath($path); if ($path === false) { return false; } @@ -1285,6 +1399,40 @@ class Net_SFTP extends Net_SSH2 { return $attr; } + /** + * Parse Longname + * + * SFTPv3 doesn't provide any easy way of identifying a file type. You could try to open + * a file as a directory and see if an error is returned or you could try to parse the + * SFTPv3-specific longname field of the SSH_FXP_NAME packet. That's what this function does. + * The result is returned using the + * {@link http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 SFTPv4 type constants}. + * + * If the longname is in an unrecognized format bool(false) is returned. + * + * @param String $longname + * @return Mixed + * @access private + */ + function _parseLongname($longname) + { + // http://en.wikipedia.org/wiki/Unix_file_types + if (preg_match('#^[^/]([r-][w-][x-]){3}#', $longname)) { + switch ($longname[0]) { + case '-': + return NET_SFTP_TYPE_REGULAR; + case 'd': + return NET_SFTP_TYPE_DIRECTORY; + case 'l': + return NET_SFTP_TYPE_SYMLINK; + default: + return NET_SFTP_TYPE_SPECIAL; + } + } + + return false; + } + /** * Sends SFTP Packets * @@ -1428,7 +1576,7 @@ class Net_SFTP extends Net_SSH2 { */ function getLastSFTPError() { - return $this->sftp_errors[count($this->sftp_errors) - 1]; + return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : ''; } /** diff --git a/lam/lib/3rdParty/phpseclib/Net/SSH1.php b/lam/lib/3rdParty/phpseclib/Net/SSH1.php index 72995c12..f791ba1f 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SSH1.php +++ b/lam/lib/3rdParty/phpseclib/Net/SSH1.php @@ -16,15 +16,7 @@ * exit('Login Failed'); * } * - * while (true) { - * echo $ssh->interactiveRead(); - * - * $read = array(STDIN); - * $write = $except = NULL; - * if (stream_select($read, $write, $except, 0)) { - * $ssh->interactiveWrite(fread(STDIN, 1)); - * } - * } + * echo $ssh->exec('ls -la'); * ?> * * @@ -38,33 +30,38 @@ * exit('Login Failed'); * } * - * echo $ssh->exec('ls -la'); + * echo $ssh->read('username@username:~$'); + * $ssh->write("ls -la\n"); + * echo $ssh->read('username@username:~$'); * ?> * * * More information on the SSHv1 specification can be found by reading * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}. * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Net * @package Net_SSH1 * @author Jim Wigginton * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -101,28 +98,6 @@ require_once('Crypt/RC4.php'); */ require_once('Crypt/Random.php'); -/**#@+ - * Protocol Flags - * - * @access private - */ -define('NET_SSH1_MSG_DISCONNECT', 1); -define('NET_SSH1_SMSG_PUBLIC_KEY', 2); -define('NET_SSH1_CMSG_SESSION_KEY', 3); -define('NET_SSH1_CMSG_USER', 4); -define('NET_SSH1_CMSG_AUTH_PASSWORD', 9); -define('NET_SSH1_CMSG_REQUEST_PTY', 10); -define('NET_SSH1_CMSG_EXEC_SHELL', 12); -define('NET_SSH1_CMSG_EXEC_CMD', 13); -define('NET_SSH1_SMSG_SUCCESS', 14); -define('NET_SSH1_SMSG_FAILURE', 15); -define('NET_SSH1_CMSG_STDIN_DATA', 16); -define('NET_SSH1_SMSG_STDOUT_DATA', 17); -define('NET_SSH1_SMSG_STDERR_DATA', 18); -define('NET_SSH1_SMSG_EXITSTATUS', 20); -define('NET_SSH1_CMSG_EXIT_CONFIRMATION', 33); -/**#@-*/ - /**#@+ * Encryption Methods * @@ -245,6 +220,34 @@ define('NET_SSH1_MASK_LOGIN', 0x00000002); define('NET_SSH1_MASK_SHELL', 0x00000004); /**#@-*/ +/**#@+ + * @access public + * @see Net_SSH1::getLog() + */ +/** + * Returns the message numbers + */ +define('NET_SSH1_LOG_SIMPLE', 1); +/** + * Returns the message content + */ +define('NET_SSH1_LOG_COMPLEX', 2); +/**#@-*/ + +/**#@+ + * @access public + * @see Net_SSH1::read() + */ +/** + * Returns when a string matching $expect exactly is found + */ +define('NET_SSH1_READ_SIMPLE', 1); +/** + * Returns when a string matching the regular expression $expect is found + */ +define('NET_SSH1_READ_REGEX', 2); +/**#@-*/ + /** * Pure-PHP implementation of SSHv1. * @@ -281,7 +284,7 @@ class Net_SSH1 { /** * Execution Bitmap * - * The bits that are set reprsent functions that have been called already. This is used to determine + * The bits that are set represent functions that have been called already. This is used to determine * if a requisite function has been successfully executed. If not, an error should be thrown. * * @var Integer @@ -377,6 +380,42 @@ class Net_SSH1 { */ var $server_identification = ''; + /** + * Protocol Flags + * + * @see Net_SSH1::Net_SSH1() + * @var Array + * @access private + */ + var $protocol_flags = array(); + + /** + * Protocol Flag Log + * + * @see Net_SSH1::getLog() + * @var Array + * @access private + */ + var $protocol_flag_log = array(); + + /** + * Message Log + * + * @see Net_SSH1::getLog() + * @var Array + * @access private + */ + var $message_log = array(); + + /** + * Interactive Buffer + * + * @see Net_SSH1::read() + * @var Array + * @access private + */ + var $interactive_buffer = ''; + /** * Default Constructor. * @@ -391,6 +430,27 @@ class Net_SSH1 { */ function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES) { + $this->protocol_flags = array( + 1 => 'NET_SSH1_MSG_DISCONNECT', + 2 => 'NET_SSH1_SMSG_PUBLIC_KEY', + 3 => 'NET_SSH1_CMSG_SESSION_KEY', + 4 => 'NET_SSH1_CMSG_USER', + 9 => 'NET_SSH1_CMSG_AUTH_PASSWORD', + 10 => 'NET_SSH1_CMSG_REQUEST_PTY', + 12 => 'NET_SSH1_CMSG_EXEC_SHELL', + 13 => 'NET_SSH1_CMSG_EXEC_CMD', + 14 => 'NET_SSH1_SMSG_SUCCESS', + 15 => 'NET_SSH1_SMSG_FAILURE', + 16 => 'NET_SSH1_CMSG_STDIN_DATA', + 17 => 'NET_SSH1_SMSG_STDOUT_DATA', + 18 => 'NET_SSH1_SMSG_STDERR_DATA', + 19 => 'NET_SSH1_CMSG_EOF', + 20 => 'NET_SSH1_SMSG_EXITSTATUS', + 33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION' + ); + + $this->_define_array($this->protocol_flags); + $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); if (!$this->fsock) { user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE); @@ -398,6 +458,17 @@ class Net_SSH1 { } $this->server_identification = $init_line = fgets($this->fsock, 255); + + if (defined('NET_SSH1_LOGGING')) { + $this->protocol_flags_log[] = '<-'; + $this->protocol_flags_log[] = '->'; + + if (NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) { + $this->message_log[] = $this->server_identification; + $this->message_log[] = $this->identifier . "\r\n"; + } + } + if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) { user_error('Can only connect to SSH servers', E_USER_NOTICE); return; @@ -574,6 +645,12 @@ class Net_SSH1 { return false; } + // remove the username and password from the last logged packet + if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) { + $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password'); + $this->message_log[count($this->message_log) - 1] = $data; // zzzzz + } + $response = $this->_get_binary_packet(); if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) { @@ -607,30 +684,13 @@ class Net_SSH1 { * @return mixed * @access public */ - function exec($cmd) + function exec($cmd, $block = true) { if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { user_error('Operation disallowed prior to login()', E_USER_NOTICE); return false; } - // connect using the sample parameters in protocol-1.5.txt. - // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text - // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell. - $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE); - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { - user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE); - return false; - } - $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd); if (!$this->_send_binary_packet($data)) { @@ -638,6 +698,10 @@ class Net_SSH1 { return false; } + if (!$block) { + return true; + } + $output = ''; $response = $this->_get_binary_packet(); @@ -669,6 +733,9 @@ class Net_SSH1 { */ function _initShell() { + // connect using the sample parameters in protocol-1.5.txt. + // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text + // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell. $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END); if (!$this->_send_binary_packet($data)) { @@ -697,6 +764,58 @@ class Net_SSH1 { return true; } + /** + * Inputs a command into an interactive shell. + * + * @see Net_SSH1::interactiveWrite() + * @param String $cmd + * @return Boolean + * @access public + */ + function write($cmd) + { + return $this->interactiveWrite($cmd); + } + + /** + * Returns the output of an interactive shell when there's a match for $expect + * + * $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX, + * a regular expression. + * + * @see Net_SSH1::write() + * @param String $expect + * @param Integer $mode + * @return Boolean + * @access public + */ + function read($expect, $mode = NET_SSH1_READ_SIMPLE) + { + if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { + user_error('Operation disallowed prior to login()', E_USER_NOTICE); + return false; + } + + if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) { + user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); + return false; + } + + $match = $expect; + while (true) { + if ($mode == NET_SSH1_READ_REGEX) { + preg_match($expect, $this->interactiveBuffer, $matches); + $match = $matches[0]; + } + $pos = strpos($this->interactiveBuffer, $match); + if ($pos !== false) { + return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); + } + $response = $this->_get_binary_packet(); + $this->interactiveBuffer.= substr($response[NET_SSH1_RESPONSE_DATA], 4); + } + } + /** * Inputs a command into an interactive shell. * @@ -728,7 +847,7 @@ class Net_SSH1 { } /** - * Reads the output of an interactive shell. + * Returns the output of an interactive shell when no more output is available. * * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like * "", you're seeing ANSI escape codes. According to @@ -794,7 +913,18 @@ class Net_SSH1 { function _disconnect($msg = 'Client Quit') { if ($this->bitmap) { - $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg); + $data = pack('C', NET_SSH1_CMSG_EOF); + $this->_send_binary_packet($data); + + $response = $this->_get_binary_packet(); + switch ($response[NET_SSH1_RESPONSE_TYPE]) { + case NET_SSH1_SMSG_EXITSTATUS: + $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION); + break; + default: + $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg); + } + $this->_send_binary_packet($data); fclose($this->fsock); $this->bitmap = 0; @@ -825,7 +955,9 @@ class Net_SSH1 { $padding_length = 8 - ($temp['length'] & 7); $length = $temp['length'] + $padding_length; + $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 $raw = fread($this->fsock, $length); + $stop = strtok(microtime(), ' ') + strtok(''); if ($this->crypto !== false) { $raw = $this->crypto->decrypt($raw); @@ -842,8 +974,19 @@ class Net_SSH1 { // return false; //} + $type = ord($type); + + if (defined('NET_SSH1_LOGGING')) { + $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN'; + $this->protocol_flags_log[] = '<- ' . $temp . + ' (' . round($stop - $start, 4) . 's)'; + if (NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) { + $this->message_log[] = $data; + } + } + return array( - NET_SSH1_RESPONSE_TYPE => ord($type), + NET_SSH1_RESPONSE_TYPE => $type, NET_SSH1_RESPONSE_DATA => $data ); } @@ -864,6 +1007,15 @@ class Net_SSH1 { return false; } + if (defined('NET_SSH1_LOGGING')) { + $temp = isset($this->protocol_flags[ord($data[0])]) ? $this->protocol_flags[ord($data[0])] : 'UNKNOWN'; + $this->protocol_flags_log[] = '-> ' . $temp . + ' (' . round($stop - $start, 4) . 's)'; + if (NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) { + $this->message_log[] = substr($data, 1); + } + } + $length = strlen($data) + 4; $padding_length = 8 - ($length & 7); @@ -881,7 +1033,11 @@ class Net_SSH1 { $packet = pack('Na*', $length, $data); - return strlen($packet) == fputs($this->fsock, $packet); + $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 + $result = strlen($packet) == fputs($this->fsock, $packet); + $stop = strtok(microtime(), ' ') + strtok(''); + + return $result; } /** @@ -1054,6 +1210,98 @@ class Net_SSH1 { return $m->toBytes(); } + /** + * Define Array + * + * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of + * named constants from it, using the value as the name of the constant and the index as the value of the constant. + * If any of the constants that would be defined already exists, none of the constants will be defined. + * + * @param Array $array + * @access private + */ + function _define_array() + { + $args = func_get_args(); + foreach ($args as $arg) { + foreach ($arg as $key=>$value) { + if (!defined($value)) { + define($value, $key); + } else { + break 2; + } + } + } + } + + /** + * Returns a log of the packets that have been sent and received. + * + * Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING') + * + * @access public + * @return String or Array + */ + function getLog() + { + if (!defined('NET_SSH1_LOGGING')) { + return false; + } + + switch (NET_SSH1_LOGGING) { + case NET_SSH1_LOG_SIMPLE: + return $this->message_number_log; + break; + case NET_SSH1_LOG_COMPLEX: + return $this->_format_log($this->message_log, $this->protocol_flags_log); + break; + default: + return false; + } + } + + /** + * Formats a log for printing + * + * @param Array $message_log + * @param Array $message_number_log + * @access private + * @return String + */ + function _format_log($message_log, $message_number_log) + { + static $boundary = ':', $long_width = 65, $short_width = 16; + + $output = ''; + for ($i = 0; $i < count($message_log); $i++) { + $output.= $message_number_log[$i] . "\r\n"; + $current_log = $message_log[$i]; + $j = 0; + do { + if (!empty($current_log)) { + $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; + } + $fragment = $this->_string_shift($current_log, $short_width); + $hex = substr( + preg_replace( + '#(.)#es', + '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)', + $fragment), + strlen($boundary) + ); + // replace non ASCII printable characters with dots + // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters + // also replace < with a . since < messes up the output on web browsers + $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); + $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n"; + $j++; + } while (!empty($current_log)); + $output.= "\r\n"; + } + + return $output; + } + /** * Return the server key public exponent * diff --git a/lam/lib/3rdParty/phpseclib/Net/SSH2.php b/lam/lib/3rdParty/phpseclib/Net/SSH2.php index 9f3a50d7..0980cbac 100644 --- a/lam/lib/3rdParty/phpseclib/Net/SSH2.php +++ b/lam/lib/3rdParty/phpseclib/Net/SSH2.php @@ -35,31 +35,35 @@ * exit('Login Failed'); * } * - * echo $ssh->exec('pwd'); - * echo $ssh->exec('ls -la'); + * echo $ssh->read('username@username:~$'); + * $ssh->write("ls -la\n"); + * echo $ssh->read('username@username:~$'); * ?> * * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * * @category Net * @package Net_SSH2 * @author Jim Wigginton * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id$ * @link http://phpseclib.sourceforge.net */ @@ -104,6 +108,7 @@ require_once('Crypt/AES.php'); */ define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); define('NET_SSH2_MASK_LOGIN', 0x00000002); +define('NET_SSH2_MASK_SHELL', 0x00000004); /**#@-*/ /**#@+ @@ -123,6 +128,7 @@ define('NET_SSH2_MASK_LOGIN', 0x00000002); * @access private */ define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100 +define('NET_SSH2_CHANNEL_SHELL',1); /**#@-*/ /**#@+ @@ -139,6 +145,20 @@ define('NET_SSH2_LOG_SIMPLE', 1); define('NET_SSH2_LOG_COMPLEX', 2); /**#@-*/ +/**#@+ + * @access public + * @see Net_SSH2::read() + */ +/** + * Returns when a string matching $expect exactly is found + */ +define('NET_SSH2_READ_SIMPLE', 1); +/** + * Returns when a string matching the regular expression $expect is found + */ +define('NET_SSH2_READ_REGEX', 2); +/**#@-*/ + /** * Pure-PHP implementation of SSHv2. * @@ -384,6 +404,17 @@ class Net_SSH2 { */ var $session_id = false; + /** + * Exchange hash + * + * The current exchange hash + * + * @see Net_SSH2::_key_exchange() + * @var String + * @access private + */ + var $exchange_hash = false; + /** * Message Numbers * @@ -563,6 +594,15 @@ class Net_SSH2 { */ var $signature_format = ''; + /** + * Interactive Buffer + * + * @see Net_SSH2::read() + * @var Array + * @access private + */ + var $interactiveBuffer = ''; + /** * Default Constructor. * @@ -641,7 +681,9 @@ class Net_SSH2 { $this->terminal_modes, $this->channel_extended_data_type_codes, array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'), - array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK') + array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'), + array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', + 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE') ); $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); @@ -667,6 +709,11 @@ class Net_SSH2 { $temp.= fgets($this->fsock, 255); } + if (feof($this->fsock)) { + user_error('Connection closed by server', E_USER_NOTICE); + return false; + } + $ext = array(); if (extension_loaded('mcrypt')) { $ext[] = 'mcrypt'; @@ -1009,17 +1056,17 @@ class Net_SSH2 { $key = $f->modPow($x, $p); $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('H*', $hash($this->exchange_hash)); + if ($this->session_id === false) { - $source = 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 - ); - - $source = pack('H*', $hash($source)); - - $this->session_id = $source; + $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++); @@ -1119,15 +1166,15 @@ class Net_SSH2 { $this->encrypt->enableContinuousBuffer(); $this->encrypt->disablePadding(); - $iv = pack('H*', $hash($keyBytes . $this->session_id . 'A' . $this->session_id)); + $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id)); while ($this->encrypt_block_size > strlen($iv)) { - $iv.= pack('H*', $hash($keyBytes . $this->session_id . $iv)); + $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); } $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); - $key = pack('H*', $hash($keyBytes . $this->session_id . 'C' . $this->session_id)); + $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id)); while ($encryptKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); + $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); } @@ -1136,15 +1183,15 @@ class Net_SSH2 { $this->decrypt->enableContinuousBuffer(); $this->decrypt->disablePadding(); - $iv = pack('H*', $hash($keyBytes . $this->session_id . 'B' . $this->session_id)); + $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id)); while ($this->decrypt_block_size > strlen($iv)) { - $iv.= pack('H*', $hash($keyBytes . $this->session_id . $iv)); + $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); } $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); - $key = pack('H*', $hash($keyBytes . $this->session_id . 'D' . $this->session_id)); + $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id)); while ($decryptKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); + $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); } @@ -1218,15 +1265,15 @@ class Net_SSH2 { $this->hmac_size = 12; } - $key = pack('H*', $hash($keyBytes . $this->session_id . 'E' . $this->session_id)); + $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id)); while ($createKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); + $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); - $key = pack('H*', $hash($keyBytes . $this->session_id . 'F' . $this->session_id)); + $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id)); while ($checkKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); + $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); @@ -1250,6 +1297,8 @@ class Net_SSH2 { /** * Login * + * The $password parameter can be a plaintext password or a Crypt_RSA object. + * * @param String $username * @param optional String $password * @return Boolean @@ -1285,7 +1334,7 @@ class Net_SSH2 { } // although PHP5's get_class() preserves the case, PHP4's does not - if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') { + if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') { return $this->_privatekey_login($username, $password); } @@ -1325,7 +1374,17 @@ class Net_SSH2 { $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_FAILURE: - // either the login is bad or the server employees multi-factor authentication + // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees + // multi-factor authentication + extract(unpack('Nlength', $this->_string_shift($response, 4))); + $auth_methods = explode(',', $this->_string_shift($response, $length)); + if (in_array('keyboard-interactive', $auth_methods)) { + if ($this->_keyboard_interactive_login($username, $password)) { + $this->bitmap |= NET_SSH2_MASK_LOGIN; + return true; + } + return false; + } return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap |= NET_SSH2_MASK_LOGIN; @@ -1335,6 +1394,117 @@ class Net_SSH2 { return false; } + /** + * Login via keyboard-interactive authentication + * + * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator. + * + * @param String $username + * @param String $password + * @return Boolean + * @access private + */ + 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, '' + ); + + if (!$this->_send_binary_packet($packet)) { + return false; + } + + return $this->_keyboard_interactive_process($password); + } + + /** + * Handle the keyboard-interactive requests / responses. + * + * @param String $responses... + * @return Boolean + * @access private + */ + function _keyboard_interactive_process() + { + $responses = func_get_args(); + + $response = $this->_get_binary_packet(); + if ($response === false) { + user_error('Connection closed by server', E_USER_NOTICE); + return false; + } + + extract(unpack('Ctype', $this->_string_shift($response, 1))); + + switch ($type) { + case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: + // see http://tools.ietf.org/html/rfc4256#section-3.2 + if (defined('NET_SSH2_LOGGING')) { + $this->message_number_log[count($this->message_number_log) - 1] = str_replace( + 'UNKNOWN', + 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', + $this->message_number_log[count($this->message_number_log) - 1] + ); + } + + extract(unpack('Nlength', $this->_string_shift($response, 4))); + $this->_string_shift($response, $length); // name; may be empty + extract(unpack('Nlength', $this->_string_shift($response, 4))); + $this->_string_shift($response, $length); // instruction; may be empty + extract(unpack('Nlength', $this->_string_shift($response, 4))); + $this->_string_shift($response, $length); // language tag; may be empty + extract(unpack('Nnum_prompts', $this->_string_shift($response, 4))); + /* + for ($i = 0; $i < $num_prompts; $i++) { + extract(unpack('Nlength', $this->_string_shift($response, 4))); + // prompt - ie. "Password: "; must not be empty + $this->_string_shift($response, $length); + $echo = $this->_string_shift($response) != chr(0); + } + */ + + /* + After obtaining the requested information from the user, the client + MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message. + */ + // see http://tools.ietf.org/html/rfc4256#section-3.4 + $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses)); + for ($i = 0; $i < count($responses); $i++) { + $packet.= pack('Na*', strlen($responses[$i]), $responses[$i]); + $logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer'); + } + + if (!$this->_send_binary_packet($packet)) { + return false; + } + + if (defined('NET_SSH2_LOGGING')) { + $this->message_number_log[count($this->message_number_log) - 1] = str_replace( + 'UNKNOWN', + 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE', + $this->message_number_log[count($this->message_number_log) - 1] + ); + $this->message_log[count($this->message_log) - 1] = $logged; + } + + /* + After receiving the response, the server MUST send either an + SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another + SSH_MSG_USERAUTH_INFO_REQUEST message. + */ + // maybe phpseclib should force close the connection after x request / responses? unless something like that is done + // there could be an infinite loop of request / responses. + return $this->_keyboard_interactive_process(); + case NET_SSH2_MSG_USERAUTH_SUCCESS: + return true; + case NET_SSH2_MSG_USERAUTH_FAILURE: + return false; + } + + return false; + } + /** * Login with an RSA private key * @@ -1368,7 +1538,6 @@ class Net_SSH2 { $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey); $packet = $part1 . chr(0) . $part2; - if (!$this->_send_binary_packet($packet)) { return false; } @@ -1390,7 +1559,11 @@ class Net_SSH2 { // we'll just take it on faith that the public key blob and the public key algorithm name are as // they should be if (defined('NET_SSH2_LOGGING')) { - $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PK_OK'; + $this->message_number_log[count($this->message_number_log) - 1] = str_replace( + 'UNKNOWN', + 'NET_SSH2_MSG_USERAUTH_PK_OK', + $this->message_number_log[count($this->message_number_log) - 1] + ); } } @@ -1427,11 +1600,15 @@ 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. + * In all likelihood, this is not a feature you want to be taking advantage of. + * * @param String $command + * @param optional Boolean $block * @return String * @access public */ - function exec($command) + function exec($command, $block = true) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; @@ -1462,7 +1639,7 @@ class Net_SSH2 { // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things // down. the one place where it might be desirable is if you're doing something like Net_SSH2::exec('ping localhost &'). - // with a pty-req SSH_MSG_cHANNEL_REQUEST, exec() will return immediately and the ping process will then + // with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then // then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but // neither will your script. @@ -1484,6 +1661,10 @@ class Net_SSH2 { $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; + if (!$block) { + return true; + } + $output = ''; while (true) { $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); @@ -1498,6 +1679,143 @@ class Net_SSH2 { } } + /** + * Creates an interactive shell + * + * @see Net_SSH2::read() + * @see Net_SSH2::write() + * @return Boolean + * @access private + */ + function _initShell() + { + $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF; + $packet_size = 0x4000; + + $packet = pack('CNa*N3', + NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL], $packet_size); + + if (!$this->_send_binary_packet($packet)) { + return false; + } + + $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN; + + $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); + if ($response === false) { + return false; + } + + $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', + 80, 24, 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', E_USER_NOTICE); + return false; + } + + list(, $type) = unpack('C', $this->_string_shift($response, 1)); + + switch ($type) { + case NET_SSH2_MSG_CHANNEL_SUCCESS: + break; + case NET_SSH2_MSG_CHANNEL_FAILURE: + default: + user_error('Unable to request pseudo-terminal', E_USER_NOTICE); + 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); + if (!$this->_send_binary_packet($packet)) { + return false; + } + + $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; + + $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); + if ($response === false) { + return false; + } + + $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; + + $this->bitmap |= NET_SSH2_MASK_SHELL; + + return true; + } + + /** + * Returns the output of an interactive shell + * + * Returns when there's a match for $expect, which can take the form of a string literal or, + * if $mode == NET_SSH2_READ_REGEX, a regular expression. + * + * @see Net_SSH2::read() + * @param String $expect + * @param Integer $mode + * @return String + * @access public + */ + function read($expect, $mode = NET_SSH2_READ_SIMPLE) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + user_error('Operation disallowed prior to login()', E_USER_NOTICE); + return false; + } + + if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { + user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); + return false; + } + + $match = $expect; + while (true) { + if ($mode == NET_SSH2_READ_REGEX) { + preg_match($expect, $this->interactiveBuffer, $matches); + $match = $matches[0]; + } + $pos = strpos($this->interactiveBuffer, $match); + if ($pos !== false) { + return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); + } + $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); + + $this->interactiveBuffer.= $response; + } + } + + /** + * Inputs a command into an interactive shell. + * + * @see Net_SSH1::interactiveWrite() + * @param String $cmd + * @return Boolean + * @access public + */ + function write($cmd) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + user_error('Operation disallowed prior to login()', E_USER_NOTICE); + return false; + } + + if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { + user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); + return false; + } + + return $this->_send_channel_packet(NET_SSH2_CHANNEL_SHELL, $cmd); + } + /** * Disconnect * @@ -1541,6 +1859,10 @@ class Net_SSH2 { $raw = fread($this->fsock, $this->decrypt_block_size); $stop = strtok(microtime(), ' ') + strtok(''); + if (empty($raw)) { + return ''; + } + if ($this->decrypt !== false) { $raw = $this->decrypt->decrypt($raw); } @@ -1577,7 +1899,7 @@ class Net_SSH2 { $this->get_seq_no++; if (defined('NET_SSH2_LOGGING')) { - $temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN'; + $temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')'; $this->message_number_log[] = '<- ' . $temp . ' (' . round($stop - $start, 4) . 's)'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { @@ -1683,7 +2005,7 @@ class Net_SSH2 { * @return Mixed * @access private */ - function _get_channel_packet($client_channel) + function _get_channel_packet($client_channel, $skip_extended = false) { if (!empty($this->channel_buffers[$client_channel])) { return array_shift($this->channel_buffers[$client_channel]); @@ -1696,6 +2018,10 @@ class Net_SSH2 { return false; } + if (empty($response)) { + return ''; + } + extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); switch ($this->channel_status[$channel]) { @@ -1728,6 +2054,7 @@ class Net_SSH2 { switch ($type) { case NET_SSH2_MSG_CHANNEL_DATA: + /* if ($client_channel == NET_SSH2_CHANNEL_EXEC) { // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server // this actually seems to make things twice as fast. more to the point, the message right after @@ -1735,6 +2062,7 @@ class Net_SSH2 { // in OpenSSH it slows things down but only by a couple thousandths of a second. $this->_send_channel_packet($client_channel, chr(0)); } + */ extract(unpack('Nlength', $this->_string_shift($response, 4))); $data = $this->_string_shift($response, $length); if ($client_channel == $channel) { @@ -1746,9 +2074,14 @@ class Net_SSH2 { $this->channel_buffers[$client_channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: + if ($skip_extended) { + break; + } + /* if ($client_channel == NET_SSH2_CHANNEL_EXEC) { $this->_send_channel_packet($client_channel, chr(0)); } + */ // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); $data = $this->_string_shift($response, $length); @@ -1844,7 +2177,7 @@ class Net_SSH2 { $stop = strtok(microtime(), ' ') + strtok(''); if (defined('NET_SSH2_LOGGING')) { - $temp = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN'; + $temp = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')'; $this->message_number_log[] = '-> ' . $temp . ' (' . round($stop - $start, 4) . 's)'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { @@ -1907,6 +2240,31 @@ class Net_SSH2 { $data)); } + /** + * Closes and flushes a channel + * + * Net_SSH2 doesn't properly close most channels. For exec() channels are normally closed by the server + * and for SFTP channels are presumably closed when the client disconnects. This functions is intended + * for SCP more than anything. + * + * @param Integer $client_channel + * @return Boolean + * @access private + */ + function _close_channel($client_channel) + { + // see http://tools.ietf.org/html/rfc4254#section-5.3 + + $packet = pack('CN', + NET_SSH2_MSG_CHANNEL_EOF, + $this->server_channels[$client_channel]); + if (!$this->_send_binary_packet($packet)) { + return false; + } + + while ($this->_get_channel_packet($client_channel) !== true); + } + /** * Disconnect * @@ -2227,7 +2585,7 @@ class Net_SSH2 { $w = $s->modInverse($q); - $u1 = $w->multiply(new Math_BigInteger(sha1($this->session_id), 16)); + $u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash), 16)); list(, $u1) = $u1->divide($q); $u2 = $w->multiply($r); @@ -2265,7 +2623,7 @@ class Net_SSH2 { $rsa = new Crypt_RSA(); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW); - if (!$rsa->verify($this->session_id, $signature)) { + if (!$rsa->verify($this->exchange_hash, $signature)) { user_error('Bad server signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } @@ -2288,7 +2646,7 @@ class Net_SSH2 { $s = $s->modPow($e, $n); $s = $s->toBytes(); - $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->session_id)); + $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h; if ($s != $h) { diff --git a/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/array_fill.php b/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/array_fill.php index 9a0d802a..356e4016 100644 --- a/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/array_fill.php +++ b/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/array_fill.php @@ -7,7 +7,7 @@ * * @category PHP * @package PHP_Compat - * @license LGPL - http://www.gnu.org/licenses/lgpl.html + * @license http://www.opensource.org/licenses/mit-license.html MIT License * @copyright 2004-2007 Aidan Lister , Arpad Ray * @link http://php.net/function.array_fill * @author Jim Wigginton @@ -38,6 +38,4 @@ if (!function_exists('array_fill')) { { return php_compat_array_fill($start_index, $num, $value); } -} - -?> \ No newline at end of file +} \ No newline at end of file diff --git a/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/bcpowmod.php b/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/bcpowmod.php index 62c4bf83..6c47c27b 100644 --- a/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/bcpowmod.php +++ b/lam/lib/3rdParty/phpseclib/PHP/Compat/Function/bcpowmod.php @@ -63,5 +63,4 @@ if (!function_exists('bcpowmod')) { { return php_compat_bcpowmod($x, $y, $modulus, $scale); } -} -?> \ No newline at end of file +} \ No newline at end of file