new phpseclib
This commit is contained in:
parent
55e4ba8634
commit
dd380bc594
|
@ -36,26 +36,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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)) {
|
||||
|
|
|
@ -33,26 +33,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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:
|
||||
|
|
|
@ -29,26 +29,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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 <http://www.rfc-editor.org/errata_search.php?rfc=1319>, 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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,26 +35,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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.
|
||||
*
|
||||
|
|
|
@ -42,26 +42,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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;
|
||||
|
|
|
@ -15,26 +15,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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
|
||||
|
|
|
@ -44,26 +44,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,26 +27,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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:
|
||||
|
|
|
@ -47,26 +47,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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');
|
||||
}
|
||||
|
||||
|
|
|
@ -28,27 +28,29 @@
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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');
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
|
@ -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:~$');
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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
|
||||
* "[00m", 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
|
||||
*
|
||||
|
|
|
@ -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:~$');
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* 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 <terrafrost@php.net>
|
||||
* @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) {
|
||||
|
|
|
@ -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 <aidan@php.net>, Arpad Ray <arpad@php.net>
|
||||
* @link http://php.net/function.array_fill
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
|
@ -38,6 +38,4 @@ if (!function_exists('array_fill')) {
|
|||
{
|
||||
return php_compat_array_fill($start_index, $num, $value);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
|
@ -63,5 +63,4 @@ if (!function_exists('bcpowmod')) {
|
|||
{
|
||||
return php_compat_bcpowmod($x, $y, $modulus, $scale);
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
Loading…
Reference in New Issue