update of phpseclib

This commit is contained in:
Roland Gruber 2015-10-04 13:24:43 +00:00
parent bd2254684f
commit 7dc73c1bf4
22 changed files with 2830 additions and 1508 deletions

View File

@ -7,6 +7,10 @@
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
* just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
* to save one include_once().
*
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()} * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()}
@ -107,20 +111,6 @@ define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/ /**#@-*/
/**#@+
* @access private
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/** /**
* Pure-PHP implementation of AES. * Pure-PHP implementation of AES.
* *
@ -201,7 +191,7 @@ class Crypt_AES extends Crypt_Rijndael
default: default:
$this->key_size = 32; $this->key_size = 32;
} }
$this->_setupEngine(); $this->_setEngine();
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -101,20 +101,6 @@ define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB);
define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB); define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/ /**#@-*/
/**#@+
* @access private
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_BLOWFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/** /**
* Pure-PHP implementation of Blowfish. * Pure-PHP implementation of Blowfish.
* *
@ -174,7 +160,7 @@ class Crypt_Blowfish extends Crypt_Base
/** /**
* The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
* *
* S-Box 1 * S-Box 0
* *
* @access private * @access private
* @var array * @var array
@ -340,7 +326,7 @@ class Crypt_Blowfish extends Crypt_Base
/** /**
* P-Array consists of 18 32-bit subkeys * P-Array consists of 18 32-bit subkeys
* *
* @var array $parray * @var array
* @access private * @access private
*/ */
var $parray = array( var $parray = array(
@ -354,7 +340,7 @@ class Crypt_Blowfish extends Crypt_Base
* *
* Holds the expanded key [p] and the key-depended s-boxes [sb] * Holds the expanded key [p] and the key-depended s-boxes [sb]
* *
* @var array $bctx * @var array
* @access private * @access private
*/ */
var $bctx; var $bctx;
@ -395,6 +381,29 @@ class Crypt_Blowfish extends Crypt_Base
parent::setKey($key); parent::setKey($key);
} }
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::isValidEngine()
* @param Integer $engine
* @access public
* @return Boolean
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
if (strlen($this->key) != 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'bf-ecb';
$this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
}
return parent::isValidEngine($engine);
}
/** /**
* Setup the key (expansion) * Setup the key (expansion)
* *
@ -519,7 +528,6 @@ class Crypt_Blowfish extends Crypt_Base
$sb_2[$r >> 8 & 0xff]) + $sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]; $sb_3[$r & 0xff];
} }
return pack("N*", $r ^ $p[0], $l ^ $p[1]); return pack("N*", $r ^ $p[0], $l ^ $p[1]);
} }
@ -534,15 +542,14 @@ class Crypt_Blowfish extends Crypt_Base
$lambda_functions =& Crypt_Blowfish::_getLambdaFunctions(); $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions();
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one. // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
$gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
switch (true) { // Generation of a unique hash for our generated code
case $gen_hi_opt_code:
$code_hash = md5(str_pad("Crypt_Blowfish, {$this->mode}, ", 32, "\0") . $this->key);
break;
default:
$code_hash = "Crypt_Blowfish, {$this->mode}"; $code_hash = "Crypt_Blowfish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
} }
if (!isset($lambda_functions[$code_hash])) { if (!isset($lambda_functions[$code_hash])) {

View File

@ -121,20 +121,6 @@ define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB);
define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB); define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/ /**#@-*/
/**#@+
* @access private
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_DES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/** /**
* Pure-PHP implementation of DES. * Pure-PHP implementation of DES.
* *
@ -191,6 +177,21 @@ class Crypt_DES extends Crypt_Base
*/ */
var $cipher_name_mcrypt = 'des'; var $cipher_name_mcrypt = 'des';
/**
* The OpenSSL names of the cipher / modes
*
* @see Crypt_Base::openssl_mode_names
* @var Array
* @access private
*/
var $openssl_mode_names = array(
CRYPT_MODE_ECB => 'des-ecb',
CRYPT_MODE_CBC => 'des-cbc',
CRYPT_MODE_CFB => 'des-cfb',
CRYPT_MODE_OFB => 'des-ofb'
// CRYPT_MODE_CTR is undefined for DES
);
/** /**
* Optimizing value while CFB-encrypting * Optimizing value while CFB-encrypting
* *
@ -661,6 +662,28 @@ class Crypt_DES extends Crypt_Base
0x00000820, 0x00020020, 0x08000000, 0x08020800 0x00000820, 0x00020020, 0x08000000, 0x08020800
); );
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::isValidEngine()
* @param Integer $engine
* @access public
* @return Boolean
*/
function isValidEngine($engine)
{
if ($this->key_size_max == 8) {
if ($engine == CRYPT_ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ecb';
$this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode();
}
}
return parent::isValidEngine($engine);
}
/** /**
* Sets the key. * Sets the key.
* *
@ -1358,21 +1381,20 @@ class Crypt_DES extends Crypt_Base
$des_rounds = $this->des_rounds; $des_rounds = $this->des_rounds;
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function. // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_DES, one generated $lambda_function cost on php5.5@32bit ~135kb unfreeable mem and ~230kb on php5.5@64bit)
// (Currently, for Crypt_TripleDES, one generated $lambda_function cost on php5.5@32bit ~240kb unfreeable mem and ~340kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one
$gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
// Generation of a uniqe hash for our generated code // Generation of a uniqe hash for our generated code
switch (true) { $code_hash = "Crypt_DES, $des_rounds, {$this->mode}";
case $gen_hi_opt_code: if ($gen_hi_opt_code) {
// For hi-optimized code, we create for each combination of // For hi-optimized code, we create for each combination of
// $mode, $des_rounds and $this->key its own encrypt/decrypt function. // $mode, $des_rounds and $this->key its own encrypt/decrypt function.
$code_hash = md5(str_pad("Crypt_DES, $des_rounds, {$this->mode}, ", 32, "\0") . $this->key);
break;
default:
// After max 10 hi-optimized functions, we create generic // After max 10 hi-optimized functions, we create generic
// (still very fast.. but not ultra) functions for each $mode/$des_rounds // (still very fast.. but not ultra) functions for each $mode/$des_rounds
// Currently 2 * 5 generic functions will be then max. possible. // Currently 2 * 5 generic functions will be then max. possible.
$code_hash = "Crypt_DES, $des_rounds, {$this->mode}"; $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
} }
// Is there a re-usable $lambda_functions in there? If not, we have to create it. // Is there a re-usable $lambda_functions in there? If not, we have to create it.
@ -1427,7 +1449,6 @@ class Crypt_DES extends Crypt_Base
// Creating code for en- and decryption. // Creating code for en- and decryption.
$crypt_block = array(); $crypt_block = array();
foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) { foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) {
/* Do the initial IP permutation. */ /* Do the initial IP permutation. */
$crypt_block[$c] = ' $crypt_block[$c] = '
$in = unpack("N*", $in); $in = unpack("N*", $in);

View File

@ -511,12 +511,14 @@ class Crypt_Hash
// Extend the sixteen 32-bit words into sixty-four 32-bit words // Extend the sixteen 32-bit words into sixty-four 32-bit words
for ($i = 16; $i < 64; $i++) { for ($i = 16; $i < 64; $i++) {
// @codingStandardsIgnoreStart
$s0 = $this->_rightRotate($w[$i - 15], 7) ^ $s0 = $this->_rightRotate($w[$i - 15], 7) ^
$this->_rightRotate($w[$i - 15], 18) ^ $this->_rightRotate($w[$i - 15], 18) ^
$this->_rightShift( $w[$i - 15], 3); $this->_rightShift( $w[$i - 15], 3);
$s1 = $this->_rightRotate($w[$i - 2], 17) ^ $s1 = $this->_rightRotate($w[$i - 2], 17) ^
$this->_rightRotate($w[$i - 2], 19) ^ $this->_rightRotate($w[$i - 2], 19) ^
$this->_rightShift( $w[$i - 2], 10); $this->_rightShift( $w[$i - 2], 10);
// @codingStandardsIgnoreEnd
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
} }

View File

@ -99,20 +99,6 @@ define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB);
define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB); define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/ /**#@-*/
/**#@+
* @access private
* @see Crypt_RC2::Crypt_RC2()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_RC2_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/** /**
* Pure-PHP implementation of RC2. * Pure-PHP implementation of RC2.
* *
@ -138,7 +124,19 @@ class Crypt_RC2 extends Crypt_Base
* @var String * @var String
* @access private * @access private
*/ */
var $key = "\0"; var $key;
/**
* The Original (unpadded) Key
*
* @see Crypt_Base::key
* @see setKey()
* @see encrypt()
* @see decrypt()
* @var String
* @access private
*/
var $orig_key;
/** /**
* The default password key_size used by setPassword() * The default password key_size used by setPassword()
@ -189,6 +187,17 @@ class Crypt_RC2 extends Crypt_Base
*/ */
var $default_key_length = 1024; var $default_key_length = 1024;
/**
* The key length in bits.
*
* @see Crypt_RC2::isValidEnine()
* @see Crypt_RC2::setKey()
* @var Integer
* @access private
* @internal Should be in range [1..1024].
*/
var $current_key_length;
/** /**
* The Key Schedule * The Key Schedule
* *
@ -341,7 +350,30 @@ class Crypt_RC2 extends Crypt_Base
function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC) function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC)
{ {
parent::Crypt_Base($mode); parent::Crypt_Base($mode);
$this->setKey(''); }
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param Integer $engine
* @access public
* @return Boolean
*/
function isValidEngine($engine)
{
switch ($engine) {
case CRYPT_ENGINE_OPENSSL:
if ($this->current_key_length != 128 || strlen($this->orig_key) != 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'rc2-ecb';
$this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
}
return parent::isValidEngine($engine);
} }
/** /**
@ -379,11 +411,14 @@ class Crypt_RC2 extends Crypt_Base
*/ */
function setKey($key, $t1 = 0) function setKey($key, $t1 = 0)
{ {
$this->orig_key = $key;
if ($t1 <= 0) { if ($t1 <= 0) {
$t1 = $this->default_key_length; $t1 = $this->default_key_length;
} elseif ($t1 > 1024) { } elseif ($t1 > 1024) {
$t1 = 1024; $t1 = 1024;
} }
$this->current_key_length = $t1;
// Key byte count should be 1..128. // Key byte count should be 1..128.
$key = strlen($key) ? substr($key, 0, 128) : "\x00"; $key = strlen($key) ? substr($key, 0, 128) : "\x00";
$t = strlen($key); $t = strlen($key);
@ -416,6 +451,52 @@ class Crypt_RC2 extends Crypt_Base
parent::setKey(call_user_func_array('pack', $l)); parent::setKey(call_user_func_array('pack', $l));
} }
/**
* Encrypts a message.
*
* Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code
*
* @see decrypt()
* @access public
* @param String $plaintext
* @return String $ciphertext
*/
function encrypt($plaintext)
{
if ($this->engine == CRYPT_ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::encrypt($plaintext);
$this->key = $temp;
return $result;
}
return parent::encrypt($plaintext);
}
/**
* Decrypts a message.
*
* Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code
*
* @see encrypt()
* @access public
* @param String $ciphertext
* @return String $plaintext
*/
function decrypt($ciphertext)
{
if ($this->engine == CRYPT_ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::decrypt($ciphertext);
$this->key = $temp;
return $result;
}
return parent::encrypt($ciphertext);
}
/** /**
* Encrypts a block * Encrypts a block
* *
@ -506,6 +587,21 @@ class Crypt_RC2 extends Crypt_Base
return pack('vvvv', $r0, $r1, $r2, $r3); return pack('vvvv', $r0, $r1, $r2, $r3);
} }
/**
* Setup the CRYPT_ENGINE_MCRYPT $engine
*
* @see Crypt_Base::_setupMcrypt()
* @access private
*/
function _setupMcrypt()
{
if (!isset($this->key)) {
$this->setKey('');
}
parent::_setupMcrypt();
}
/** /**
* Creates the key schedule * Creates the key schedule
* *
@ -514,6 +610,10 @@ class Crypt_RC2 extends Crypt_Base
*/ */
function _setupKey() function _setupKey()
{ {
if (!isset($this->key)) {
$this->setKey('');
}
// Key has already been expanded in Crypt_RC2::setKey(): // Key has already been expanded in Crypt_RC2::setKey():
// Only the first value must be altered. // Only the first value must be altered.
$l = unpack('Ca/Cb/v*', $this->key); $l = unpack('Ca/Cb/v*', $this->key);
@ -536,14 +636,14 @@ class Crypt_RC2 extends Crypt_Base
// The first 10 generated $lambda_functions will use the $keys hardcoded as integers // The first 10 generated $lambda_functions will use the $keys hardcoded as integers
// for the mixing rounds, for better inline crypt performance [~20% faster]. // for the mixing rounds, for better inline crypt performance [~20% faster].
// But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10. // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
$keys = $this->keys; // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
if (count($lambda_functions) >= 10) { $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
foreach ($this->keys as $k => $v) {
$keys[$k] = '$keys[' . $k . ']';
}
}
$code_hash = md5(str_pad("Crypt_RC2, {$this->mode}, ", 32, "\0") . implode(',', $keys)); // Generation of a uniqe hash for our generated code
$code_hash = "Crypt_RC2, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
// Is there a re-usable $lambda_functions in there? // Is there a re-usable $lambda_functions in there?
// If not, we have to create it. // If not, we have to create it.
@ -551,6 +651,16 @@ class Crypt_RC2 extends Crypt_Base
// Init code for both, encrypt and decrypt. // Init code for both, encrypt and decrypt.
$init_crypt = '$keys = $self->keys;'; $init_crypt = '$keys = $self->keys;';
switch (true) {
case $gen_hi_opt_code:
$keys = $this->keys;
default:
$keys = array();
foreach ($this->keys as $k => $v) {
$keys[$k] = '$keys[' . $k . ']';
}
}
// $in is the current 8 bytes block which has to be en/decrypt // $in is the current 8 bytes block which has to be en/decrypt
$encrypt_block = $decrypt_block = ' $encrypt_block = $decrypt_block = '
$in = unpack("v4", $in); $in = unpack("v4", $in);

View File

@ -69,20 +69,6 @@ if (!class_exists('Crypt_Base')) {
include_once 'Base.php'; include_once 'Base.php';
} }
/**#@+
* @access private
* @see Crypt_RC4::Crypt_RC4()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_RC4::_crypt() * @see Crypt_RC4::_crypt()
@ -181,6 +167,38 @@ class Crypt_RC4 extends Crypt_Base
parent::Crypt_Base(CRYPT_MODE_STREAM); parent::Crypt_Base(CRYPT_MODE_STREAM);
} }
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param Integer $engine
* @access public
* @return Boolean
*/
function isValidEngine($engine)
{
switch ($engine) {
case CRYPT_ENGINE_OPENSSL:
switch (strlen($this->key)) {
case 5:
$this->cipher_name_openssl = 'rc4-40';
break;
case 8:
$this->cipher_name_openssl = 'rc4-64';
break;
case 16:
$this->cipher_name_openssl = 'rc4';
break;
default:
return false;
}
}
return parent::isValidEngine($engine);
}
/** /**
* Dummy function. * Dummy function.
* *
@ -230,7 +248,7 @@ class Crypt_RC4 extends Crypt_Base
*/ */
function encrypt($plaintext) function encrypt($plaintext)
{ {
if ($this->engine == CRYPT_MODE_MCRYPT) { if ($this->engine != CRYPT_ENGINE_INTERNAL) {
return parent::encrypt($plaintext); return parent::encrypt($plaintext);
} }
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
@ -250,7 +268,7 @@ class Crypt_RC4 extends Crypt_Base
*/ */
function decrypt($ciphertext) function decrypt($ciphertext)
{ {
if ($this->engine == CRYPT_MODE_MCRYPT) { if ($this->engine != CRYPT_ENGINE_INTERNAL) {
return parent::decrypt($ciphertext); return parent::decrypt($ciphertext);
} }
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);

View File

@ -107,6 +107,13 @@ define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
* compatibility with protocols (like SSH-1) written before OAEP's introduction. * compatibility with protocols (like SSH-1) written before OAEP's introduction.
*/ */
define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
/**
* Do not use any padding
*
* Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy
* stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc.
*/
define('CRYPT_RSA_ENCRYPTION_NONE', 3);
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -599,7 +606,8 @@ class Crypt_RSA
$publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
// clear the buffer of error strings stemming from a minimalistic openssl.cnf // clear the buffer of error strings stemming from a minimalistic openssl.cnf
while (openssl_error_string() !== false); while (openssl_error_string() !== false) {
}
return array( return array(
'privatekey' => $privatekey, 'privatekey' => $privatekey,
@ -789,19 +797,39 @@ class Crypt_RSA
$encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none'; $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
$key.= $encryption; $key.= $encryption;
$key.= "\r\nComment: " . $this->comment . "\r\n"; $key.= "\r\nComment: " . $this->comment . "\r\n";
$public = pack('Na*Na*Na*', $public = pack(
strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus'] 'Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($raw['publicExponent']),
$raw['publicExponent'],
strlen($raw['modulus']),
$raw['modulus']
); );
$source = pack('Na*Na*Na*Na*', $source = pack(
strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, 'Na*Na*Na*Na*',
strlen($this->comment), $this->comment, strlen($public), $public strlen('ssh-rsa'),
'ssh-rsa',
strlen($encryption),
$encryption,
strlen($this->comment),
$this->comment,
strlen($public),
$public
); );
$public = base64_encode($public); $public = base64_encode($public);
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
$key.= chunk_split($public, 64); $key.= chunk_split($public, 64);
$private = pack('Na*Na*Na*Na*', $private = pack(
strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'], 'Na*Na*Na*Na*',
strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient'] strlen($raw['privateExponent']),
$raw['privateExponent'],
strlen($raw['prime1']),
$raw['prime1'],
strlen($raw['prime2']),
$raw['prime2'],
strlen($raw['coefficient']),
$raw['coefficient']
); );
if (empty($this->password) && !is_string($this->password)) { if (empty($this->password) && !is_string($this->password)) {
$source.= pack('Na*', strlen($private), $private); $source.= pack('Na*', strlen($private), $private);
@ -868,8 +896,14 @@ class Crypt_RSA
if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) { if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) {
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPrivateKey = pack('Ca*a*Ca*a*', $RSAPrivateKey = pack(
CRYPT_RSA_ASN1_INTEGER, "\01\00", $rsaOID, 4, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey 'Ca*a*Ca*a*',
CRYPT_RSA_ASN1_INTEGER,
"\01\00",
$rsaOID,
4,
$this->_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
); );
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
if (!empty($this->password) || is_string($this->password)) { if (!empty($this->password) || is_string($this->password)) {
@ -883,20 +917,35 @@ class Crypt_RSA
$crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount); $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
$RSAPrivateKey = $crypto->encrypt($RSAPrivateKey); $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
$parameters = pack('Ca*a*Ca*N', $parameters = pack(
CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($salt)), $salt, 'Ca*a*Ca*N',
CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(4), $iterationCount CRYPT_RSA_ASN1_OCTETSTRING,
$this->_encodeLength(strlen($salt)),
$salt,
CRYPT_RSA_ASN1_INTEGER,
$this->_encodeLength(4),
$iterationCount
); );
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03"; $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
$encryptionAlgorithm = pack('Ca*a*Ca*a*', $encryptionAlgorithm = pack(
CRYPT_RSA_ASN1_OBJECT, $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), $pbeWithMD5AndDES_CBC, 'Ca*a*Ca*a*',
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($parameters)), $parameters CRYPT_RSA_ASN1_OBJECT,
$this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
$pbeWithMD5AndDES_CBC,
CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($parameters)),
$parameters
); );
$RSAPrivateKey = pack('Ca*a*Ca*a*', $RSAPrivateKey = pack(
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($encryptionAlgorithm)), $encryptionAlgorithm, 'Ca*a*Ca*a*',
CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($encryptionAlgorithm)),
$encryptionAlgorithm,
CRYPT_RSA_ASN1_OCTETSTRING,
$this->_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
); );
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
@ -983,9 +1032,12 @@ class Crypt_RSA
'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent) 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
); );
$RSAPublicKey = pack('Ca*a*a*', $RSAPublicKey = pack(
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), 'Ca*a*a*',
$components['modulus'], $components['publicExponent'] CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
); );
if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) { if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) {
@ -998,8 +1050,11 @@ class Crypt_RSA
$RSAPublicKey = chr(0) . $RSAPublicKey; $RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey; $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
$RSAPublicKey = pack('Ca*a*', $RSAPublicKey = pack(
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey 'Ca*a*',
CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
); );
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
@ -1772,6 +1827,41 @@ class Crypt_RSA
return $temp; return $temp;
} }
/**
* Returns the public key's fingerprint
*
* The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
* no public key currently loaded, false is returned.
* Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
*
* @access public
* @param String $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
* for invalid values.
*/
public function getPublicKeyFingerprint($algorithm = 'md5')
{
if (empty($this->modulus) || empty($this->publicExponent)) {
return false;
}
$modulus = $this->modulus->toBytes(true);
$publicExponent = $this->publicExponent->toBytes(true);
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
switch ($algorithm) {
case 'sha256':
$hash = new Crypt_Hash('sha256');
$base = base64_encode($hash->hash($RSAPublicKey));
return substr($base, 0, strlen($base) - 1);
case 'md5':
return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
default:
return false;
}
}
/** /**
* Returns the private key * Returns the private key
* *
@ -2408,6 +2498,22 @@ class Crypt_RSA
return substr($m, 1); return substr($m, 1);
} }
/**
* Raw Encryption / Decryption
*
* Doesn't use padding and is not recommended.
*
* @access private
* @param String $m
* @return String
*/
function _raw_encrypt($m)
{
$temp = $this->_os2ip($m);
$temp = $this->_rsaep($temp);
return $this->_i2osp($temp, $this->k);
}
/** /**
* RSAES-PKCS1-V1_5-ENCRYPT * RSAES-PKCS1-V1_5-ENCRYPT
* *
@ -2531,7 +2637,7 @@ class Crypt_RSA
// be output. // be output.
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
$sLen = $this->sLen == false ? $this->hLen : $this->sLen; $sLen = $this->sLen === false ? $this->hLen : $this->sLen;
$mHash = $this->hash->hash($m); $mHash = $this->hash->hash($m);
if ($emLen < $this->hLen + $sLen + 2) { if ($emLen < $this->hLen + $sLen + 2) {
@ -2569,7 +2675,7 @@ class Crypt_RSA
// be output. // be output.
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8); $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
$sLen = $this->sLen == false ? $this->hLen : $this->sLen; $sLen = $this->sLen === false ? $this->hLen : $this->sLen;
$mHash = $this->hash->hash($m); $mHash = $this->hash->hash($m);
if ($emLen < $this->hLen + $sLen + 2) { if ($emLen < $this->hLen + $sLen + 2) {
@ -2854,6 +2960,13 @@ class Crypt_RSA
function encrypt($plaintext) function encrypt($plaintext)
{ {
switch ($this->encryptionMode) { switch ($this->encryptionMode) {
case CRYPT_RSA_ENCRYPTION_NONE:
$plaintext = str_split($plaintext, $this->k);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_raw_encrypt($m);
}
return $ciphertext;
case CRYPT_RSA_ENCRYPTION_PKCS1: case CRYPT_RSA_ENCRYPTION_PKCS1:
$length = $this->k - 11; $length = $this->k - 11;
if ($length <= 0) { if ($length <= 0) {
@ -2902,6 +3015,9 @@ class Crypt_RSA
$plaintext = ''; $plaintext = '';
switch ($this->encryptionMode) { switch ($this->encryptionMode) {
case CRYPT_RSA_ENCRYPTION_NONE:
$decrypt = '_raw_encrypt';
break;
case CRYPT_RSA_ENCRYPTION_PKCS1: case CRYPT_RSA_ENCRYPTION_PKCS1:
$decrypt = '_rsaes_pkcs1_v1_5_decrypt'; $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
break; break;

File diff suppressed because it is too large Load Diff

View File

@ -59,19 +59,31 @@ if (!class_exists('Crypt_DES')) {
include_once 'DES.php'; include_once 'DES.php';
} }
/**#@+
* @access public
* @see Crypt_TripleDES::Crypt_TripleDES()
*/
/** /**
* Encrypt / decrypt using inner chaining * 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). * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
*/ */
define('CRYPT_MODE_3CBC', -2);
/**
* BC version of the above.
*/
define('CRYPT_DES_MODE_3CBC', -2); define('CRYPT_DES_MODE_3CBC', -2);
/** /**
* Encrypt / decrypt using outer chaining * Encrypt / decrypt using outer chaining
* *
* Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
*/ */
define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC);
/**
* BC version of the above.
*/
define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3);
/**#@-*/
/** /**
* Pure-PHP implementation of Triple DES. * Pure-PHP implementation of Triple DES.
@ -186,20 +198,20 @@ class Crypt_TripleDES extends Crypt_DES
* @param optional Integer $mode * @param optional Integer $mode
* @access public * @access public
*/ */
function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) function Crypt_TripleDES($mode = CRYPT_MODE_CBC)
{ {
switch ($mode) { switch ($mode) {
// In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC
// and additional flag us internally as 3CBC // and additional flag us internally as 3CBC
case CRYPT_DES_MODE_3CBC: case CRYPT_DES_MODE_3CBC:
parent::Crypt_Base(CRYPT_DES_MODE_CBC); parent::Crypt_Base(CRYPT_MODE_CBC);
$this->mode_3cbc = true; $this->mode_3cbc = true;
// This three $des'es will do the 3CBC work (if $key > 64bits) // This three $des'es will do the 3CBC work (if $key > 64bits)
$this->des = array( $this->des = array(
new Crypt_DES(CRYPT_DES_MODE_CBC), new Crypt_DES(CRYPT_MODE_CBC),
new Crypt_DES(CRYPT_DES_MODE_CBC), new Crypt_DES(CRYPT_MODE_CBC),
new Crypt_DES(CRYPT_DES_MODE_CBC), new Crypt_DES(CRYPT_MODE_CBC),
); );
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
@ -213,6 +225,27 @@ class Crypt_TripleDES extends Crypt_DES
} }
} }
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param Integer $engine
* @access public
* @return Boolean
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ede3';
$mode = $this->_openssl_translate_mode();
$this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
}
return parent::isValidEngine($engine);
}
/** /**
* Sets the initialization vector. (optional) * Sets the initialization vector. (optional)
* *
@ -255,7 +288,7 @@ class Crypt_TripleDES extends Crypt_DES
$key = str_pad(substr($key, 0, 24), 24, chr(0)); $key = str_pad(substr($key, 0, 24), 24, chr(0));
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
// http://php.net/function.mcrypt-encrypt#47973 // http://php.net/function.mcrypt-encrypt#47973
//$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); $key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
} else { } else {
$key = str_pad($key, 8, chr(0)); $key = str_pad($key, 8, chr(0));
} }
@ -283,7 +316,7 @@ class Crypt_TripleDES extends Crypt_DES
function encrypt($plaintext) function encrypt($plaintext)
{ {
// parent::en/decrypt() is able to do all the work for all modes and keylengths, // parent::en/decrypt() is able to do all the work for all modes and keylengths,
// except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits // except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits
// if the key is smaller then 8, do what we'd normally do // if the key is smaller then 8, do what we'd normally do
if ($this->mode_3cbc && strlen($this->key) > 8) { if ($this->mode_3cbc && strlen($this->key) > 8) {
@ -425,4 +458,24 @@ class Crypt_TripleDES extends Crypt_DES
// setup our key // setup our key
parent::_setupKey(); parent::_setupKey();
} }
/**
* Sets the internal crypt engine
*
* @see Crypt_Base::Crypt_Base()
* @see Crypt_Base::setPreferredEngine()
* @param Integer $engine
* @access public
* @return Integer
*/
function setPreferredEngine($engine)
{
if ($this->mode_3cbc) {
$this->des[0]->setPreferredEngine($engine);
$this->des[1]->setPreferredEngine($engine);
$this->des[2]->setPreferredEngine($engine);
}
return parent::setPreferredEngine($engine);
}
} }

View File

@ -101,20 +101,6 @@ define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB);
define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB); define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/ /**#@-*/
/**#@+
* @access private
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_TWOFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/** /**
* Pure-PHP implementation of Twofish. * Pure-PHP implementation of Twofish.
* *
@ -618,7 +604,9 @@ class Crypt_Twofish extends Crypt_Base
$u^= 0x7fffffff & ($t >> 1); $u^= 0x7fffffff & ($t >> 1);
// Add the modular polynomial on underflow. // Add the modular polynomial on underflow.
if ($t & 0x01) $u^= 0xa6 ; if ($t & 0x01) {
$u^= 0xa6 ;
}
// Remove t * (a + 1/a) * (x^3 + x). // Remove t * (a + 1/a) * (x^3 + x).
$B^= ($u << 24) | ($u << 8); $B^= ($u << 24) | ($u << 8);
@ -754,21 +742,19 @@ class Crypt_Twofish extends Crypt_Base
$lambda_functions =& Crypt_Twofish::_getLambdaFunctions(); $lambda_functions =& Crypt_Twofish::_getLambdaFunctions();
// Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one. // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
// (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit)
$gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
switch (true) { // Generation of a uniqe hash for our generated code
case $gen_hi_opt_code:
$code_hash = md5(str_pad("Crypt_Twofish, {$this->mode}, ", 32, "\0") . $this->key);
break;
default:
$code_hash = "Crypt_Twofish, {$this->mode}"; $code_hash = "Crypt_Twofish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
} }
if (!isset($lambda_functions[$code_hash])) { if (!isset($lambda_functions[$code_hash])) {
switch (true) { switch (true) {
case $gen_hi_opt_code: case $gen_hi_opt_code:
$K = $this->K; $K = $this->K;
$init_crypt = ' $init_crypt = '
static $S0, $S1, $S2, $S3; static $S0, $S1, $S2, $S3;
if (!$S0) { if (!$S0) {
@ -786,7 +772,6 @@ class Crypt_Twofish extends Crypt_Base
for ($i = 0; $i < 40; ++$i) { for ($i = 0; $i < 40; ++$i) {
$K[] = '$K_' . $i; $K[] = '$K_' . $i;
} }
$init_crypt = ' $init_crypt = '
$S0 = $self->S0; $S0 = $self->S0;
$S1 = $self->S1; $S1 = $self->S1;

View File

@ -117,6 +117,22 @@ class File_ANSI
*/ */
var $old_y; var $old_y;
/**
* An empty attribute cell
*
* @var Object
* @access private
*/
var $base_attr_cell;
/**
* The current attribute cell
*
* @var Object
* @access private
*/
var $attr_cell;
/** /**
* An empty attribute row * An empty attribute row
* *
@ -141,62 +157,6 @@ class File_ANSI
*/ */
var $attrs; var $attrs;
/**
* The current foreground color
*
* @var String
* @access private
*/
var $foreground;
/**
* The current background color
*
* @var String
* @access private
*/
var $background;
/**
* Bold flag
*
* @var Boolean
* @access private
*/
var $bold;
/**
* Underline flag
*
* @var Boolean
* @access private
*/
var $underline;
/**
* Blink flag
*
* @var Boolean
* @access private
*/
var $blink;
/**
* Reverse flag
*
* @var Boolean
* @access private
*/
var $reverse;
/**
* Color flag
*
* @var Boolean
* @access private
*/
var $color;
/** /**
* Current ANSI code * Current ANSI code
* *
@ -205,6 +165,14 @@ class File_ANSI
*/ */
var $ansi; var $ansi;
/**
* Tokenization
*
* @var Array
* @access private
*/
var $tokenization;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -213,6 +181,16 @@ class File_ANSI
*/ */
function File_ANSI() function File_ANSI()
{ {
$attr_cell = new stdClass();
$attr_cell->bold = false;
$attr_cell->underline = false;
$attr_cell->blink = false;
$attr_cell->background = 'black';
$attr_cell->foreground = 'white';
$attr_cell->reverse = false;
$this->base_attr_cell = clone($attr_cell);
$this->attr_cell = clone($attr_cell);
$this->setHistory(200); $this->setHistory(200);
$this->setDimensions(80, 24); $this->setDimensions(80, 24);
} }
@ -232,17 +210,9 @@ class File_ANSI
$this->max_y = $y - 1; $this->max_y = $y - 1;
$this->x = $this->y = 0; $this->x = $this->y = 0;
$this->history = $this->history_attrs = array(); $this->history = $this->history_attrs = array();
$this->attr_row = array_fill(0, $this->max_x + 1, ''); $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
$this->screen = array_fill(0, $this->max_y + 1, ''); $this->screen = array_fill(0, $this->max_y + 1, '');
$this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row); $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
$this->foreground = 'white';
$this->background = 'black';
$this->bold = false;
$this->underline = false;
$this->blink = false;
$this->reverse = false;
$this->color = false;
$this->ansi = ''; $this->ansi = '';
} }
@ -278,6 +248,7 @@ class File_ANSI
*/ */
function appendString($source) function appendString($source)
{ {
$this->tokenization = array('');
for ($i = 0; $i < strlen($source); $i++) { for ($i = 0; $i < strlen($source); $i++) {
if (strlen($this->ansi)) { if (strlen($this->ansi)) {
$this->ansi.= $source[$i]; $this->ansi.= $source[$i];
@ -294,6 +265,8 @@ class File_ANSI
default: default:
continue 2; continue 2;
} }
$this->tokenization[] = $this->ansi;
$this->tokenization[] = '';
// http://ascii-table.com/ansi-escape-sequences-vt-100.php // http://ascii-table.com/ansi-escape-sequences-vt-100.php
switch ($this->ansi) { switch ($this->ansi) {
case "\x1B[H": // Move cursor to upper left corner case "\x1B[H": // Move cursor to upper left corner
@ -315,7 +288,7 @@ class File_ANSI
case "\x1B[K": // Clear screen from cursor right case "\x1B[K": // Clear screen from cursor right
$this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x); $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
array_splice($this->attrs[$this->y], $this->x + 1); array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
break; break;
case "\x1B[2K": // Clear entire line case "\x1B[2K": // Clear entire line
$this->screen[$this->y] = str_repeat(' ', $this->x); $this->screen[$this->y] = str_repeat(' ', $this->x);
@ -323,6 +296,7 @@ class File_ANSI
break; break;
case "\x1B[?1h": // set cursor key to application case "\x1B[?1h": // set cursor key to application
case "\x1B[?25h": // show the cursor case "\x1B[?25h": // show the cursor
case "\x1B(B": // set united states g0 character set
break; break;
case "\x1BE": // Move to next line case "\x1BE": // Move to next line
$this->_newLine(); $this->_newLine();
@ -330,6 +304,10 @@ class File_ANSI
break; break;
default: default:
switch (true) { switch (true) {
case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
$this->old_y = $this->y;
$this->y+= $match[1];
break;
case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
$this->old_x = $this->x; $this->old_x = $this->x;
$this->old_y = $this->y; $this->old_y = $this->y;
@ -338,65 +316,44 @@ class File_ANSI
break; break;
case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
$this->old_x = $this->x; $this->old_x = $this->x;
$x = $match[1] - 1; $this->x+= $match[1];
break;
case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
$this->old_x = $this->x;
$this->x-= $match[1];
break; break;
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
break; break;
case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
$attr_cell = &$this->attr_cell;
$mods = explode(';', $match[1]); $mods = explode(';', $match[1]);
foreach ($mods as $mod) { foreach ($mods as $mod) {
switch ($mod) { switch ($mod) {
case 0: // Turn off character attributes case 0: // Turn off character attributes
$this->attrs[$this->y][$this->x] = ''; $attr_cell = clone($this->base_attr_cell);
if ($this->bold) $this->attrs[$this->y][$this->x].= '</b>';
if ($this->underline) $this->attrs[$this->y][$this->x].= '</u>';
if ($this->blink) $this->attrs[$this->y][$this->x].= '</blink>';
if ($this->color) $this->attrs[$this->y][$this->x].= '</span>';
if ($this->reverse) {
$temp = $this->background;
$this->background = $this->foreground;
$this->foreground = $temp;
}
$this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false;
break; break;
case 1: // Turn bold mode on case 1: // Turn bold mode on
if (!$this->bold) { $attr_cell->bold = true;
$this->attrs[$this->y][$this->x] = '<b>';
$this->bold = true;
}
break; break;
case 4: // Turn underline mode on case 4: // Turn underline mode on
if (!$this->underline) { $attr_cell->underline = true;
$this->attrs[$this->y][$this->x] = '<u>';
$this->underline = true;
}
break; break;
case 5: // Turn blinking mode on case 5: // Turn blinking mode on
if (!$this->blink) { $attr_cell->blink = true;
$this->attrs[$this->y][$this->x] = '<blink>';
$this->blink = true;
}
break; break;
case 7: // Turn reverse video on case 7: // Turn reverse video on
$this->reverse = !$this->reverse; $attr_cell->reverse = !$attr_cell->reverse;
$temp = $this->background; $temp = $attr_cell->background;
$this->background = $this->foreground; $attr_cell->background = $attr_cell->foreground;
$this->foreground = $temp; $attr_cell->foreground = $temp;
$this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">';
if ($this->color) {
$this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x];
}
$this->color = true;
break; break;
default: // set colors default: // set colors
//$front = $this->reverse ? &$this->background : &$this->foreground; //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
$front = &$this->{ $this->reverse ? 'background' : 'foreground' }; $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
//$back = $this->reverse ? &$this->foreground : &$this->background; //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
$back = &$this->{ $this->reverse ? 'foreground' : 'background' }; $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
switch ($mod) { switch ($mod) {
// @codingStandardsIgnoreStart
case 30: $front = 'black'; break; case 30: $front = 'black'; break;
case 31: $front = 'red'; break; case 31: $front = 'red'; break;
case 32: $front = 'green'; break; case 32: $front = 'green'; break;
@ -414,30 +371,25 @@ class File_ANSI
case 45: $back = 'magenta'; break; case 45: $back = 'magenta'; break;
case 46: $back = 'cyan'; break; case 46: $back = 'cyan'; break;
case 47: $back = 'white'; break; case 47: $back = 'white'; break;
// @codingStandardsIgnoreEnd
default: default:
user_error('Unsupported attribute: ' . $mod); //user_error('Unsupported attribute: ' . $mod);
$this->ansi = ''; $this->ansi = '';
break 2; break 2;
} }
unset($temp);
$this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">';
if ($this->color) {
$this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x];
}
$this->color = true;
} }
} }
break; break;
default: default:
user_error("{$this->ansi} unsupported\r\n"); //user_error("{$this->ansi} is unsupported\r\n");
} }
} }
$this->ansi = ''; $this->ansi = '';
continue; continue;
} }
$this->tokenization[count($this->tokenization) - 1].= $source[$i];
switch ($source[$i]) { switch ($source[$i]) {
case "\r": case "\r":
$this->x = 0; $this->x = 0;
@ -445,12 +397,32 @@ class File_ANSI
case "\n": case "\n":
$this->_newLine(); $this->_newLine();
break; break;
case "\x08": // backspace
if ($this->x) {
$this->x--;
$this->attrs[$this->y][$this->x] = clone($this->base_attr_cell);
$this->screen[$this->y] = substr_replace(
$this->screen[$this->y],
$source[$i],
$this->x,
1
);
}
break;
case "\x0F": // shift case "\x0F": // shift
break; break;
case "\x1B": // start ANSI escape code case "\x1B": // start ANSI escape code
$this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
//if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
// array_pop($this->tokenization);
//}
$this->ansi.= "\x1B"; $this->ansi.= "\x1B";
break; break;
default: default:
$this->attrs[$this->y][$this->x] = clone($this->attr_cell);
if ($this->x > strlen($this->screen[$this->y])) {
$this->screen[$this->y] = str_repeat(' ', $this->x);
}
$this->screen[$this->y] = substr_replace( $this->screen[$this->y] = substr_replace(
$this->screen[$this->y], $this->screen[$this->y],
$source[$i], $source[$i],
@ -498,6 +470,63 @@ class File_ANSI
$this->y++; $this->y++;
} }
/**
* Returns the current coordinate without preformating
*
* @access private
* @return String
*/
function _processCoordinate($last_attr, $cur_attr, $char)
{
$output = '';
if ($last_attr != $cur_attr) {
$close = $open = '';
if ($last_attr->foreground != $cur_attr->foreground) {
if ($cur_attr->foreground != 'white') {
$open.= '<span style="color: ' . $cur_attr->foreground . '">';
}
if ($last_attr->foreground != 'white') {
$close = '</span>' . $close;
}
}
if ($last_attr->background != $cur_attr->background) {
if ($cur_attr->background != 'black') {
$open.= '<span style="background: ' . $cur_attr->background . '">';
}
if ($last_attr->background != 'black') {
$close = '</span>' . $close;
}
}
if ($last_attr->bold != $cur_attr->bold) {
if ($cur_attr->bold) {
$open.= '<b>';
} else {
$close = '</b>' . $close;
}
}
if ($last_attr->underline != $cur_attr->underline) {
if ($cur_attr->underline) {
$open.= '<u>';
} else {
$close = '</u>' . $close;
}
}
if ($last_attr->blink != $cur_attr->blink) {
if ($cur_attr->blink) {
$open.= '<blink>';
} else {
$close = '</blink>' . $close;
}
}
$output.= $close . $open;
}
$output.= htmlspecialchars($char);
return $output;
}
/** /**
* Returns the current screen without preformating * Returns the current screen without preformating
* *
@ -507,17 +536,18 @@ class File_ANSI
function _getScreen() function _getScreen()
{ {
$output = ''; $output = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i <= $this->max_y; $i++) { for ($i = 0; $i <= $this->max_y; $i++) {
for ($j = 0; $j <= $this->max_x + 1; $j++) { for ($j = 0; $j <= $this->max_x; $j++) {
if (isset($this->attrs[$i][$j])) { $cur_attr = $this->attrs[$i][$j];
$output.= $this->attrs[$i][$j]; $output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
} $last_attr = $this->attrs[$i][$j];
if (isset($this->screen[$i][$j])) {
$output.= htmlspecialchars($this->screen[$i][$j]);
}
} }
$output.= "\r\n"; $output.= "\r\n";
} }
$output = substr($output, 0, -2);
// close any remaining open tags
$output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
return rtrim($output); return rtrim($output);
} }
@ -529,7 +559,7 @@ class File_ANSI
*/ */
function getScreen() function getScreen()
{ {
return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $this->_getScreen() . '</pre>'; return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->_getScreen() . '</pre>';
} }
/** /**
@ -541,19 +571,20 @@ class File_ANSI
function getHistory() function getHistory()
{ {
$scrollback = ''; $scrollback = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i < count($this->history); $i++) { for ($i = 0; $i < count($this->history); $i++) {
for ($j = 0; $j <= $this->max_x + 1; $j++) { for ($j = 0; $j <= $this->max_x + 1; $j++) {
if (isset($this->history_attrs[$i][$j])) { $cur_attr = $this->history_attrs[$i][$j];
$scrollback.= $this->history_attrs[$i][$j]; $scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
} $last_attr = $this->history_attrs[$i][$j];
if (isset($this->history[$i][$j])) {
$scrollback.= htmlspecialchars($this->history[$i][$j]);
}
} }
$scrollback.= "\r\n"; $scrollback.= "\r\n";
} }
$base_attr_cell = $this->base_attr_cell;
$this->base_attr_cell = $last_attr;
$scrollback.= $this->_getScreen(); $scrollback.= $this->_getScreen();
$this->base_attr_cell = $base_attr_cell;
return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $scrollback . '</pre>'; return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
} }
} }

View File

@ -329,6 +329,10 @@ class File_ASN1
$current+= array('headerlength' => 2); $current+= array('headerlength' => 2);
} }
if ($length > strlen($encoded)) {
return false;
}
$content = $this->_string_shift($encoded, $length); $content = $this->_string_shift($encoded, $length);
// at this point $length can be overwritten. it's only accurate for definite length things as is // at this point $length can be overwritten. it's only accurate for definite length things as is
@ -357,14 +361,21 @@ class File_ASN1
} }
$newcontent = array(); $newcontent = array();
if (strlen($content)) { $remainingLength = $length;
$newcontent = $this->_decode_ber($content, $start); while ($remainingLength > 0) {
$length = $newcontent['length']; $temp = $this->_decode_ber($content, $start);
$length = $temp['length'];
// end-of-content octets - see paragraph 8.1.5
if (substr($content, $length, 2) == "\0\0") { if (substr($content, $length, 2) == "\0\0") {
$length+= 2; $length+= 2;
$start+= $length;
$newcontent[] = $temp;
break;
} }
$start+= $length; $start+= $length;
$newcontent = array($newcontent); $remainingLength-= $length;
$newcontent[] = $temp;
$this->_string_shift($content, $length);
} }
return array( return array(
@ -886,7 +897,7 @@ class File_ASN1
} }
foreach ($mapping['children'] as $key => $child) { foreach ($mapping['children'] as $key => $child) {
if (!isset($source[$key])) { if (!array_key_exists($key, $source)) {
if (!isset($child['optional'])) { if (!isset($child['optional'])) {
return false; return false;
} }

View File

@ -1505,6 +1505,16 @@ class File_X509
case 'rsaEncryption': case 'rsaEncryption':
$cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))); = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
/* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
-- https://tools.ietf.org/html/rfc3279#section-2.3.1
given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank,
it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever.
*/
$cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;
// https://tools.ietf.org/html/rfc3279#section-2.2.1
$cert['signatureAlgorithm']['parameters'] = null;
$cert['tbsCertificate']['signature']['parameters'] = null;
} }
} }
@ -1589,7 +1599,7 @@ class File_X509
} }
} }
} }
} elseif ($map) { } else {
$value = base64_encode($value); $value = base64_encode($value);
} }
} }
@ -1612,6 +1622,10 @@ class File_X509
if (is_array($extensions)) { if (is_array($extensions)) {
$size = count($extensions); $size = count($extensions);
for ($i = 0; $i < $size; $i++) { for ($i = 0; $i < $size; $i++) {
if (is_object($extensions[$i]) && strtolower(get_class($extensions[$i])) == 'file_asn1_element') {
continue;
}
$id = $extensions[$i]['extnId']; $id = $extensions[$i]['extnId'];
$value = &$extensions[$i]['extnValue']; $value = &$extensions[$i]['extnValue'];
@ -2917,7 +2931,7 @@ class File_X509
switch (true) { switch (true) {
case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')): case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']); case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
break; break;
default: default:
switch ($algorithm) { switch ($algorithm) {
@ -3044,7 +3058,7 @@ class File_X509
$algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm'); $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
switch (true) { switch (true) {
case !$algorithm: case !$algorithm:
case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']); case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
break; break;
default: default:
switch ($algorithm) { switch ($algorithm) {
@ -3263,7 +3277,21 @@ class File_X509
$startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
$endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year')); $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
$serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new Math_BigInteger(); if (!empty($this->serialNumber)) {
$serialNumber = $this->serialNumber;
} else {
if (!function_exists('crypt_random_string')) {
include_once 'Crypt/Random.php';
}
/* "The serial number MUST be a positive integer"
"Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
-- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
for the integer to be positive the leading bit needs to be 0 hence the
application of a bitmap
*/
$serialNumber = new Math_BigInteger(crypt_random_string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);
}
$this->currentCert = array( $this->currentCert = array(
'tbsCertificate' => 'tbsCertificate' =>
@ -3301,8 +3329,7 @@ class File_X509
// ) // )
//), //),
'keyIdentifier' => $issuer->currentKeyIdentifier 'keyIdentifier' => $issuer->currentKeyIdentifier
) ));
);
//$extensions = &$this->currentCert['tbsCertificate']['extensions']; //$extensions = &$this->currentCert['tbsCertificate']['extensions'];
//if (isset($issuer->serialNumber)) { //if (isset($issuer->serialNumber)) {
// $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
@ -3345,7 +3372,8 @@ class File_X509
$keyUsage = array(); $keyUsage = array();
} }
$this->setExtension('id-ce-keyUsage', $this->setExtension(
'id-ce-keyUsage',
array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign')))) array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
); );
@ -3354,8 +3382,11 @@ class File_X509
$basicConstraints = array(); $basicConstraints = array();
} }
$this->setExtension('id-ce-basicConstraints', $this->setExtension(
array_unique(array_merge(array('cA' => true), $basicConstraints)), true); 'id-ce-basicConstraints',
array_unique(array_merge(array('cA' => true), $basicConstraints)),
true
);
if (!isset($subject->currentKeyIdentifier)) { if (!isset($subject->currentKeyIdentifier)) {
$this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false); $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
@ -3552,6 +3583,11 @@ class File_X509
$crlNumber = $this->serialNumber; $crlNumber = $this->serialNumber;
} else { } else {
$crlNumber = $this->getExtension('id-ce-cRLNumber'); $crlNumber = $this->getExtension('id-ce-cRLNumber');
// "The CRL number is a non-critical CRL extension that conveys a
// monotonically increasing sequence number for a given CRL scope and
// CRL issuer. This extension allows users to easily determine when a
// particular CRL supersedes another CRL."
// -- https://tools.ietf.org/html/rfc5280#section-5.2.3
$crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null; $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null;
} }
@ -3590,8 +3626,7 @@ class File_X509
// ) // )
//), //),
'keyIdentifier' => $issuer->currentKeyIdentifier 'keyIdentifier' => $issuer->currentKeyIdentifier
) ));
);
//$extensions = &$tbsCertList['crlExtensions']; //$extensions = &$tbsCertList['crlExtensions'];
//if (isset($issuer->serialNumber)) { //if (isset($issuer->serialNumber)) {
// $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
@ -4124,7 +4159,7 @@ class File_X509
case $disposition == FILE_X509_ATTR_APPEND: case $disposition == FILE_X509_ATTR_APPEND:
$last = $key; $last = $key;
break; break;
case $disposition >= $n; case $disposition >= $n:
$disposition -= $n; $disposition -= $n;
break; break;
default: default:
@ -4382,7 +4417,6 @@ class File_X509
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked
if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) { if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
if (!empty($date)) { if (!empty($date)) {
$rclist[$i]['revocationDate'] = $this->_timeField($date); $rclist[$i]['revocationDate'] = $this->_timeField($date);
} }

View File

@ -1675,17 +1675,23 @@ class Math_BigInteger
'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent']) 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
); );
$RSAPublicKey = pack('Ca*a*a*', $RSAPublicKey = pack(
48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])), 'Ca*a*a*',
$components['modulus'], $components['publicExponent'] 48,
$this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
); );
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPublicKey = chr(0) . $RSAPublicKey; $RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey; $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
$encapsulated = pack('Ca*a*', $encapsulated = pack(
48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey 'Ca*a*',
48,
$this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
); );
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
@ -1817,7 +1823,8 @@ class Math_BigInteger
// calculate the appropriate window size. // calculate the appropriate window size.
// $window_size == 3 if $window_ranges is between 25 and 81, for example. // $window_size == 3 if $window_ranges is between 25 and 81, for example.
for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i) {
}
$n_value = $n->value; $n_value = $n->value;
@ -3018,7 +3025,8 @@ class Math_BigInteger
} }
} else { } else {
$temp = ord($bits[0]); $temp = ord($bits[0]);
for ($i = 0; $temp >> $i; ++$i); for ($i = 0; $temp >> $i; ++$i) {
}
$precision = 8 * strlen($bits) - 8 + $i; $precision = 8 * strlen($bits) - 8 + $i;
$mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
} }
@ -3433,7 +3441,8 @@ class Math_BigInteger
} else { } else {
for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
$temp = ~$r_value[$i] & 0xFFFFFF; $temp = ~$r_value[$i] & 0xFFFFFF;
for ($j = 1; ($temp >> $j) & 1; ++$j); for ($j = 1; ($temp >> $j) & 1; ++$j) {
}
if ($j != 25) { if ($j != 25) {
break; break;
} }

View File

@ -17,7 +17,7 @@
* if (!$ssh->login('username', 'password')) { * if (!$ssh->login('username', 'password')) {
* exit('bad login'); * exit('bad login');
* } * }
*
* $scp = new Net_SCP($ssh); * $scp = new Net_SCP($ssh);
* $scp->put('abcd', str_repeat('x', 1024*1024)); * $scp->put('abcd', str_repeat('x', 1024*1024));
* ?> * ?>

View File

@ -102,6 +102,11 @@ define('NET_SFTP_LOCAL_FILE', 1);
*/ */
// this value isn't really used anymore but i'm keeping it reserved for historical reasons // this value isn't really used anymore but i'm keeping it reserved for historical reasons
define('NET_SFTP_STRING', 2); define('NET_SFTP_STRING', 2);
/**
* Reads data from callback:
* function callback($length) returns string to proceed, null for EOF
*/
define('NET_SFTP_CALLBACK', 16);
/** /**
* Resumes an upload * Resumes an upload
*/ */
@ -429,8 +434,15 @@ class Net_SFTP extends Net_SSH2
$this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size; $this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size;
$packet = pack('CNa*N3', $packet = pack(
NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000); 'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
NET_SFTP_CHANNEL,
$this->window_size,
0x4000
);
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
return false; return false;
@ -443,8 +455,16 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
$packet = pack('CNNa*CNa*', $packet = pack(
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('subsystem'), 'subsystem', 1, strlen('sftp'), 'sftp'); 'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SFTP_CHANNEL],
strlen('subsystem'),
'subsystem',
1,
strlen('sftp'),
'sftp'
);
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
return false; return false;
} }
@ -459,8 +479,16 @@ class Net_SFTP extends Net_SSH2
"exec sftp-server"; "exec sftp-server";
// we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does
// is redundant // is redundant
$packet = pack('CNNa*CNa*', $packet = pack(
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('exec'), 'exec', 1, strlen($command), $command); 'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SFTP_CHANNEL],
strlen('exec'),
'exec',
1,
strlen($command),
$command
);
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
return false; return false;
} }
@ -896,7 +924,7 @@ class Net_SFTP extends Net_SSH2
} else { } else {
$temp = $dir . '/' . $shortname; $temp = $dir . '/' . $shortname;
} }
$this->_update_stat_cache($temp, (object) $attributes); $this->_update_stat_cache($temp, (object) array('lstat' => $attributes));
} }
// SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the // 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. // final SSH_FXP_STATUS packet should tell us that, already.
@ -1057,16 +1085,34 @@ class Net_SFTP extends Net_SSH2
*/ */
function _update_stat_cache($path, $value) function _update_stat_cache($path, $value)
{ {
if ($this->use_stat_cache === false) {
return;
}
// preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/')) // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/'))
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->stat_cache; $temp = &$this->stat_cache;
$max = count($dirs) - 1; $max = count($dirs) - 1;
foreach ($dirs as $i => $dir) { foreach ($dirs as $i => $dir) {
// if $temp is an object that means one of two things.
// 1. a file was deleted and changed to a directory behind phpseclib's back
// 2. it's a symlink. when lstat is done it's unclear what it's a symlink to
if (is_object($temp)) {
$temp = array();
}
if (!isset($temp[$dir])) { if (!isset($temp[$dir])) {
$temp[$dir] = array(); $temp[$dir] = array();
} }
if ($i === $max) { if ($i === $max) {
if (is_object($temp[$dir])) {
if (!isset($value->stat) && isset($temp[$dir]->stat)) {
$value->stat = $temp[$dir]->stat;
}
if (!isset($value->lstat) && isset($temp[$dir]->lstat)) {
$value->lstat = $temp[$dir]->lstat;
}
}
$temp[$dir] = $value; $temp[$dir] = $value;
break; break;
} }
@ -1144,11 +1190,11 @@ class Net_SFTP extends Net_SSH2
if ($this->use_stat_cache) { if ($this->use_stat_cache) {
$result = $this->_query_stat_cache($filename); $result = $this->_query_stat_cache($filename);
if (is_array($result) && isset($result['.'])) { if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) {
return (array) $result['.']; return $result['.']->stat;
} }
if (is_object($result)) { if (is_object($result) && isset($result->stat)) {
return (array) $result; return $result->stat;
} }
} }
@ -1161,7 +1207,7 @@ class Net_SFTP extends Net_SSH2
if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.'; $filename.= '/.';
} }
$this->_update_stat_cache($filename, (object) $stat); $this->_update_stat_cache($filename, (object) array('stat' => $stat));
return $stat; return $stat;
} }
@ -1174,7 +1220,7 @@ class Net_SFTP extends Net_SSH2
if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.'; $filename.= '/.';
} }
$this->_update_stat_cache($filename, (object) $stat); $this->_update_stat_cache($filename, (object) array('stat' => $stat));
return $stat; return $stat;
} }
@ -1201,11 +1247,11 @@ class Net_SFTP extends Net_SSH2
if ($this->use_stat_cache) { if ($this->use_stat_cache) {
$result = $this->_query_stat_cache($filename); $result = $this->_query_stat_cache($filename);
if (is_array($result) && isset($result['.'])) { if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) {
return (array) $result['.']; return $result['.']->lstat;
} }
if (is_object($result)) { if (is_object($result) && isset($result->lstat)) {
return (array) $result; return $result->lstat;
} }
} }
@ -1218,7 +1264,7 @@ class Net_SFTP extends Net_SSH2
if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.'; $filename.= '/.';
} }
$this->_update_stat_cache($filename, (object) $lstat); $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $lstat; return $lstat;
} }
@ -1226,7 +1272,7 @@ class Net_SFTP extends Net_SSH2
if ($lstat != $stat) { if ($lstat != $stat) {
$lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK)); $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
$this->_update_stat_cache($filename, (object) $lstat); $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $stat; return $stat;
} }
@ -1239,7 +1285,7 @@ class Net_SFTP extends Net_SSH2
if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.'; $filename.= '/.';
} }
$this->_update_stat_cache($filename, (object) $lstat); $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $lstat; return $lstat;
} }
@ -1759,6 +1805,10 @@ class Net_SFTP extends Net_SSH2
* *
* If $data is a resource then it'll be used as a resource instead. * If $data is a resource then it'll be used as a resource instead.
* *
*
* Setting $mode to NET_SFTP_CALLBACK will use $data as callback function, which gets only one parameter -- number
* of bytes to return, and returns a string if there is some data or null if there is no more data
*
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
* care of that, yourself. * care of that, yourself.
* *
@ -1784,11 +1834,12 @@ class Net_SFTP extends Net_SSH2
* @param optional Integer $mode * @param optional Integer $mode
* @param optional Integer $start * @param optional Integer $start
* @param optional Integer $local_start * @param optional Integer $local_start
* @param optional callable|null $progressCallback
* @return Boolean * @return Boolean
* @access public * @access public
* @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode(). * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode().
*/ */
function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1) function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1, $progressCallback = null)
{ {
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false; return false;
@ -1836,7 +1887,15 @@ class Net_SFTP extends Net_SSH2
} }
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
$dataCallback = false;
switch (true) { switch (true) {
case $mode & NET_SFTP_CALLBACK:
if (!is_callable($data)) {
user_error("\$data should be is_callable if you set NET_SFTP_CALLBACK flag");
}
$dataCallback = $data;
// do nothing
break;
case is_resource($data): case is_resource($data):
$mode = $mode & ~NET_SFTP_LOCAL_FILE; $mode = $mode & ~NET_SFTP_LOCAL_FILE;
$fp = $data; $fp = $data;
@ -1863,6 +1922,8 @@ class Net_SFTP extends Net_SSH2
} else { } else {
fseek($fp, $offset); fseek($fp, $offset);
} }
} elseif ($dataCallback) {
$size = 0;
} else { } else {
$size = strlen($data); $size = strlen($data);
} }
@ -1874,8 +1935,15 @@ class Net_SFTP extends Net_SSH2
// make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header" // make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header"
$sftp_packet_size-= strlen($handle) + 25; $sftp_packet_size-= strlen($handle) + 25;
$i = 0; $i = 0;
while ($sent < $size) { while ($dataCallback || ($sent < $size)) {
if ($dataCallback) {
$temp = call_user_func($dataCallback, $sftp_packet_size);
if (is_null($temp)) {
break;
}
} else {
$temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
}
$subtemp = $offset + $sent; $subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
@ -1885,6 +1953,9 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
$sent+= strlen($temp); $sent+= strlen($temp);
if (is_callable($progressCallback)) {
call_user_func($progressCallback, $sent);
}
$i++; $i++;
@ -2180,6 +2251,7 @@ class Net_SFTP extends Net_SSH2
if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) { if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) {
return false; return false;
} }
$this->_remove_from_stat_cache($temp);
$i++; $i++;
@ -2190,12 +2262,12 @@ class Net_SFTP extends Net_SSH2
$i = 0; $i = 0;
} }
} }
$this->_remove_from_stat_cache($path);
} }
if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) { if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
return false; return false;
} }
$this->_remove_from_stat_cache($path);
$i++; $i++;
@ -2273,7 +2345,7 @@ class Net_SFTP extends Net_SSH2
*/ */
function is_link($path) function is_link($path)
{ {
$result = $this->_get_stat_cache_prop($path, 'type'); $result = $this->_get_lstat_cache_prop($path, 'type');
if ($result === false) { if ($result === false) {
return false; return false;
} }
@ -2367,13 +2439,20 @@ class Net_SFTP extends Net_SSH2
} }
switch ($type) { switch ($type) {
case NET_SFTP_TYPE_BLOCK_DEVICE: return 'block'; case NET_SFTP_TYPE_BLOCK_DEVICE:
case NET_SFTP_TYPE_CHAR_DEVICE: return 'char'; return 'block';
case NET_SFTP_TYPE_DIRECTORY: return 'dir'; case NET_SFTP_TYPE_CHAR_DEVICE:
case NET_SFTP_TYPE_FIFO: return 'fifo'; return 'char';
case NET_SFTP_TYPE_REGULAR: return 'file'; case NET_SFTP_TYPE_DIRECTORY:
case NET_SFTP_TYPE_SYMLINK: return 'link'; return 'dir';
default: return false; case NET_SFTP_TYPE_FIFO:
return 'fifo';
case NET_SFTP_TYPE_REGULAR:
return 'file';
case NET_SFTP_TYPE_SYMLINK:
return 'link';
default:
return false;
} }
} }
@ -2388,18 +2467,48 @@ class Net_SFTP extends Net_SSH2
* @access private * @access private
*/ */
function _get_stat_cache_prop($path, $prop) function _get_stat_cache_prop($path, $prop)
{
return $this->_get_xstat_cache_prop($path, $prop, 'stat');
}
/**
* Return an lstat properity
*
* Uses cache if appropriate.
*
* @param String $path
* @param String $prop
* @return Mixed
* @access private
*/
function _get_lstat_cache_prop($path, $prop)
{
return $this->_get_xstat_cache_prop($path, $prop, 'lstat');
}
/**
* Return a stat or lstat properity
*
* Uses cache if appropriate.
*
* @param String $path
* @param String $prop
* @return Mixed
* @access private
*/
function _get_xstat_cache_prop($path, $prop, $type)
{ {
if ($this->use_stat_cache) { if ($this->use_stat_cache) {
$path = $this->_realpath($path); $path = $this->_realpath($path);
$result = $this->_query_stat_cache($path); $result = $this->_query_stat_cache($path);
if (is_object($result) && isset($result->$prop)) { if (is_object($result) && isset($result->$type)) {
return $result->$prop; return $result->{$type}[$prop];
} }
} }
$result = $this->stat($path); $result = $this->$type($path);
if ($result === false || !isset($result[$prop])) { if ($result === false || !isset($result[$prop])) {
return false; return false;

View File

@ -280,14 +280,17 @@ class Net_SFTP_Stream
if ($this->size === false) { if ($this->size === false) {
if ($this->mode[0] == 'r') { if ($this->mode[0] == 'r') {
return false; return false;
} else {
$this->sftp->touch($path);
$this->size = 0;
} }
} else { } else {
switch ($this->mode[0]) { switch ($this->mode[0]) {
case 'x': case 'x':
return false; return false;
case 'w': case 'w':
case 'c':
$this->sftp->truncate($path, 0); $this->sftp->truncate($path, 0);
$this->size = 0;
} }
} }
@ -511,7 +514,7 @@ class Net_SFTP_Stream
$path_from = $this->_parse_path($path_from); $path_from = $this->_parse_path($path_from);
$path_to = parse_url($path_to); $path_to = parse_url($path_to);
if ($path_from == false) { if ($path_from === false) {
return false; return false;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* Pure-PHP ssh-agent client. * Pure-PHP ssh-agent client.
* *
@ -63,6 +64,20 @@ define('SYSTEM_SSH_AGENT_FAILURE', 5);
define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13); define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
/**@+
* Agent forwarding status
*
* @access private
*/
// no forwarding requested and not active
define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
// request agent forwarding when opportune
define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
// forwarding has been request and is active
define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
/**#@-*/ /**#@-*/
/** /**
@ -225,6 +240,29 @@ class System_SSH_Agent
*/ */
var $fsock; var $fsock;
/**
* Agent forwarding status
*
* @access private
*/
var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
/**
* Buffer for accumulating forwarded authentication
* agent data arriving on SSH data channel destined
* for agent unix socket
*
* @access private
*/
var $socket_buffer = '';
/**
* Tracking the number of bytes we are expecting
* to arrive for the agent socket on the SSH data
* channel
*/
var $expected_bytes = 0;
/** /**
* Default Constructor * Default Constructor
* *
@ -310,4 +348,113 @@ class System_SSH_Agent
return $identities; return $identities;
} }
/**
* Signal that agent forwarding should
* be requested when a channel is opened
*
* @param Net_SSH2 $ssh
* @return Boolean
* @access public
*/
function startSSHForwarding($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
}
}
/**
* Request agent forwarding of remote server
*
* @param Net_SSH2 $ssh
* @return Boolean
* @access private
*/
function _request_forwarding($ssh)
{
$request_channel = $ssh->_get_open_channel();
if ($request_channel === false) {
return false;
}
$packet = pack(
'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST,
$ssh->server_channels[$request_channel],
strlen('auth-agent-req@openssh.com'),
'auth-agent-req@openssh.com',
1
);
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
if (!$ssh->_send_binary_packet($packet)) {
return false;
}
$response = $ssh->_get_channel_packet($request_channel);
if ($response === false) {
return false;
}
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
return true;
}
/**
* On successful channel open
*
* This method is called upon successful channel
* open to give the SSH Agent an opportunity
* to take further action. i.e. request agent forwarding
*
* @param Net_SSH2 $ssh
* @access private
*/
function _on_channel_open($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
$this->_request_forwarding($ssh);
}
}
/**
* Forward data to SSH Agent and return data reply
*
* @param String $data
* @return data from SSH Agent
* @access private
*/
function _forward_data($data)
{
if ($this->expected_bytes > 0) {
$this->socket_buffer.= $data;
$this->expected_bytes -= strlen($data);
} else {
$agent_data_bytes = current(unpack('N', $data));
$current_data_bytes = strlen($data);
$this->socket_buffer = $data;
if ($current_data_bytes != $agent_data_bytes + 4) {
$this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
return false;
}
}
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
user_error('Connection closed attempting to forward data to SSH agent');
}
$this->socket_buffer = '';
$this->expected_bytes = 0;
$agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
$agent_reply_data = fread($this->fsock, $agent_reply_bytes);
$agent_reply_data = current(unpack('a*', $agent_reply_data));
return pack('Na*', $agent_reply_bytes, $agent_reply_data);
}
} }