phpSeclib update

This commit is contained in:
Roland Gruber 2015-07-06 19:44:12 +00:00
parent bc0b29a090
commit 0fd01851b9
23 changed files with 2632 additions and 1339 deletions

View File

@ -19,7 +19,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/AES.php'); * include 'Crypt/AES.php';
* *
* $aes = new Crypt_AES(); * $aes = new Crypt_AES();
* *
@ -56,7 +56,7 @@
* @category Crypt * @category Crypt
* @package Crypt_AES * @package Crypt_AES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton * @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -109,7 +109,7 @@ define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_AES::Crypt_AES() * @see Crypt_Base::Crypt_Base()
*/ */
/** /**
* Toggles the internal implementation * Toggles the internal implementation
@ -126,7 +126,6 @@ define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* *
* @package Crypt_AES * @package Crypt_AES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Crypt_AES extends Crypt_Rijndael class Crypt_AES extends Crypt_Rijndael
@ -140,35 +139,6 @@ class Crypt_AES extends Crypt_Rijndael
*/ */
var $const_namespace = 'AES'; var $const_namespace = 'AES';
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_AES_MODE_ECB
*
* - CRYPT_AES_MODE_CBC
*
* - CRYPT_AES_MODE_CTR
*
* - CRYPT_AES_MODE_CFB
*
* - CRYPT_AES_MODE_OFB
*
* If not explictly set, CRYPT_AES_MODE_CBC will be used.
*
* @see Crypt_Rijndael::Crypt_Rijndael()
* @see Crypt_Base::Crypt_Base()
* @param optional Integer $mode
* @access public
*/
function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
{
parent::Crypt_Rijndael($mode);
}
/** /**
* Dummy function * Dummy function
* *
@ -182,4 +152,56 @@ class Crypt_AES extends Crypt_Rijndael
{ {
return; return;
} }
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @see Crypt_Rijndael:setKeyLength()
* @access public
* @param Integer $length
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see Crypt_Rijndael:setKey()
* @see setKeyLength()
* @access public
* @param String $key
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 24:
$this->key_size = 24;
break;
default:
$this->key_size = 32;
}
$this->_setupEngine();
}
}
} }

View File

@ -47,9 +47,8 @@
* @package Crypt_Base * @package Crypt_Base
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 1.0.1
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -117,7 +116,6 @@ define('CRYPT_MODE_MCRYPT', 2);
* @package Crypt_Base * @package Crypt_Base
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @version 1.0.0
* @access public * @access public
*/ */
class Crypt_Base class Crypt_Base
@ -279,7 +277,7 @@ class Crypt_Base
* $buffer bytes > $cfb_init_len than * $buffer bytes > $cfb_init_len than
* using the $ecb resource furthermore. * using the $ecb resource furthermore.
* *
* This value depends of the choosen cipher * This value depends of the chosen cipher
* and the time it would be needed for it's * and the time it would be needed for it's
* initialization [by mcrypt_generic_init()] * initialization [by mcrypt_generic_init()]
* which, typically, depends on the complexity * which, typically, depends on the complexity
@ -438,9 +436,9 @@ class Crypt_Base
* *
* - CRYPT_MODE_OFB * - CRYPT_MODE_OFB
* *
* (or the alias constants of the choosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...) * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
* *
* If not explictly set, CRYPT_MODE_CBC will be used. * If not explicitly set, CRYPT_MODE_CBC will be used.
* *
* @param optional Integer $mode * @param optional Integer $mode
* @access public * @access public
@ -500,7 +498,7 @@ class Crypt_Base
/** /**
* Sets the initialization vector. (optional) * Sets the initialization vector. (optional)
* *
* SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explictly set, it'll be assumed * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
* to be all zero's. * to be all zero's.
* *
* Note: Could, but not must, extend by the child Crypt_* class * Note: Could, but not must, extend by the child Crypt_* class
@ -543,7 +541,7 @@ class Crypt_Base
* Sets the password. * Sets the password.
* *
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
* $hash, $salt, $count, $dkLen * $hash, $salt, $count, $dkLen
* *
* Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
@ -553,6 +551,7 @@ class Crypt_Base
* @see Crypt/Hash.php * @see Crypt/Hash.php
* @param String $password * @param String $password
* @param optional String $method * @param optional String $method
* @return Boolean
* @access public * @access public
*/ */
function setPassword($password, $method = 'pbkdf2') function setPassword($password, $method = 'pbkdf2')
@ -560,7 +559,7 @@ class Crypt_Base
$key = ''; $key = '';
switch ($method) { switch ($method) {
default: // 'pbkdf2' default: // 'pbkdf2' or 'pbkdf1'
$func_args = func_get_args(); $func_args = func_get_args();
// Hash function // Hash function
@ -574,10 +573,34 @@ class Crypt_Base
$count = isset($func_args[4]) ? $func_args[4] : 1000; $count = isset($func_args[4]) ? $func_args[4] : 1000;
// Keylength // Keylength
$dkLen = isset($func_args[5]) ? $func_args[5] : $this->password_key_size; if (isset($func_args[5])) {
$dkLen = $func_args[5];
} else {
$dkLen = $method == 'pbkdf1' ? 2 * $this->password_key_size : $this->password_key_size;
}
// Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
switch (true) { switch (true) {
case $method == 'pbkdf1':
if (!class_exists('Crypt_Hash')) {
include_once 'Crypt/Hash.php';
}
$hashObj = new Crypt_Hash();
$hashObj->setHash($hash);
if ($dkLen > $hashObj->getLength()) {
user_error('Derived key too long');
return false;
}
$t = $password . $salt;
for ($i = 0; $i < $count; ++$i) {
$t = $hashObj->hash($t);
}
$key = substr($t, 0, $dkLen);
$this->setKey(substr($key, 0, $dkLen >> 1));
$this->setIV(substr($key, $dkLen >> 1));
return true;
// Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
case !function_exists('hash_pbkdf2'): case !function_exists('hash_pbkdf2'):
case !function_exists('hash_algos'): case !function_exists('hash_algos'):
case !in_array($hash, hash_algos()): case !in_array($hash, hash_algos()):
@ -604,6 +627,8 @@ class Crypt_Base
} }
$this->setKey($key); $this->setKey($key);
return true;
} }
/** /**
@ -1446,7 +1471,7 @@ class Crypt_Base
* - each time on _setup(), after(!) _setupKey() * - each time on _setup(), after(!) _setupKey()
* *
* *
* This ensures that _setupInlineCrypt() has allways a * This ensures that _setupInlineCrypt() has always a
* full ready2go initializated internal cipher $engine state * full ready2go initializated internal cipher $engine state
* where, for example, the keys allready expanded, * where, for example, the keys allready expanded,
* keys/block_size calculated and such. * keys/block_size calculated and such.

View File

@ -14,7 +14,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/Blowfish.php'); * include 'Crypt/Blowfish.php';
* *
* $blowfish = new Crypt_Blowfish(); * $blowfish = new Crypt_Blowfish();
* *
@ -48,9 +48,8 @@
* @package Crypt_Blowfish * @package Crypt_Blowfish
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 1.0
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -104,7 +103,7 @@ define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_Blowfish::Crypt_Blowfish() * @see Crypt_Base::Crypt_Base()
*/ */
/** /**
* Toggles the internal implementation * Toggles the internal implementation
@ -122,7 +121,6 @@ define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* @package Crypt_Blowfish * @package Crypt_Blowfish
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @version 1.0
* @access public * @access public
*/ */
class Crypt_Blowfish extends Crypt_Base class Crypt_Blowfish extends Crypt_Base
@ -369,34 +367,6 @@ class Crypt_Blowfish extends Crypt_Base
*/ */
var $kl; var $kl;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_BLOWFISH_MODE_ECB
*
* - CRYPT_BLOWFISH_MODE_CBC
*
* - CRYPT_BLOWFISH_MODE_CTR
*
* - CRYPT_BLOWFISH_MODE_CFB
*
* - CRYPT_BLOWFISH_MODE_OFB
*
* If not explictly set, CRYPT_BLOWFISH_MODE_CBC will be used.
*
* @see Crypt_Base::Crypt_Base()
* @param optional Integer $mode
* @access public
*/
function Crypt_Blowfish($mode = CRYPT_BLOWFISH_MODE_CBC)
{
parent::Crypt_Base($mode);
}
/** /**
* Sets the key. * Sets the key.
* *

View File

@ -16,7 +16,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/DES.php'); * include 'Crypt/DES.php';
* *
* $des = new Crypt_DES(); * $des = new Crypt_DES();
* *
@ -53,7 +53,7 @@
* @category Crypt * @category Crypt
* @package Crypt_DES * @package Crypt_DES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -123,7 +123,7 @@ define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB);
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_DES::Crypt_DES() * @see Crypt_Base::Crypt_Base()
*/ */
/** /**
* Toggles the internal implementation * Toggles the internal implementation
@ -140,7 +140,6 @@ define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* *
* @package Crypt_DES * @package Crypt_DES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Crypt_DES extends Crypt_Base class Crypt_DES extends Crypt_Base
@ -662,34 +661,6 @@ class Crypt_DES extends Crypt_Base
0x00000820, 0x00020020, 0x08000000, 0x08020800 0x00000820, 0x00020020, 0x08000000, 0x08020800
); );
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_DES_MODE_ECB
*
* - CRYPT_DES_MODE_CBC
*
* - CRYPT_DES_MODE_CTR
*
* - CRYPT_DES_MODE_CFB
*
* - CRYPT_DES_MODE_OFB
*
* If not explictly set, CRYPT_DES_MODE_CBC will be used.
*
* @see Crypt_Base::Crypt_Base()
* @param optional Integer $mode
* @access public
*/
function Crypt_DES($mode = CRYPT_DES_MODE_CBC)
{
parent::Crypt_Base($mode);
}
/** /**
* Sets the key. * Sets the key.
* *

View File

@ -5,7 +5,7 @@
* *
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following: * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
* *
* md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512 * md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
* *
* If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
* the hash. If no valid algorithm is provided, sha1 will be used. * the hash. If no valid algorithm is provided, sha1 will be used.
@ -18,7 +18,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/Hash.php'); * include 'Crypt/Hash.php';
* *
* $hash = new Crypt_Hash('sha1'); * $hash = new Crypt_Hash('sha1');
* *
@ -49,7 +49,7 @@
* @category Crypt * @category Crypt
* @package Crypt_Hash * @package Crypt_Hash
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -77,7 +77,6 @@ define('CRYPT_HASH_MODE_HASH', 3);
* *
* @package Crypt_Hash * @package Crypt_Hash
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Crypt_Hash class Crypt_Hash
@ -208,6 +207,9 @@ class Crypt_Hash
switch ($hash) { switch ($hash) {
case 'md5-96': case 'md5-96':
case 'sha1-96': case 'sha1-96':
case 'sha256-96':
case 'sha512-96':
$hash = substr($hash, 0, -3);
$this->l = 12; // 96 / 8 = 12 $this->l = 12; // 96 / 8 = 12
break; break;
case 'md2': case 'md2':
@ -244,14 +246,12 @@ class Crypt_Hash
case CRYPT_HASH_MODE_MHASH: case CRYPT_HASH_MODE_MHASH:
switch ($hash) { switch ($hash) {
case 'md5': case 'md5':
case 'md5-96':
$this->hash = MHASH_MD5; $this->hash = MHASH_MD5;
break; break;
case 'sha256': case 'sha256':
$this->hash = MHASH_SHA256; $this->hash = MHASH_SHA256;
break; break;
case 'sha1': case 'sha1':
case 'sha1-96':
default: default:
$this->hash = MHASH_SHA1; $this->hash = MHASH_SHA1;
} }
@ -259,7 +259,6 @@ class Crypt_Hash
case CRYPT_HASH_MODE_HASH: case CRYPT_HASH_MODE_HASH:
switch ($hash) { switch ($hash) {
case 'md5': case 'md5':
case 'md5-96':
$this->hash = 'md5'; $this->hash = 'md5';
return; return;
case 'md2': case 'md2':
@ -269,7 +268,6 @@ class Crypt_Hash
$this->hash = $hash; $this->hash = $hash;
return; return;
case 'sha1': case 'sha1':
case 'sha1-96':
default: default:
$this->hash = 'sha1'; $this->hash = 'sha1';
} }
@ -282,7 +280,6 @@ class Crypt_Hash
$this->hash = array($this, '_md2'); $this->hash = array($this, '_md2');
break; break;
case 'md5': case 'md5':
case 'md5-96':
$this->b = 64; $this->b = 64;
$this->hash = array($this, '_md5'); $this->hash = array($this, '_md5');
break; break;
@ -296,7 +293,6 @@ class Crypt_Hash
$this->hash = array($this, '_sha512'); $this->hash = array($this, '_sha512');
break; break;
case 'sha1': case 'sha1':
case 'sha1-96':
default: default:
$this->b = 64; $this->b = 64;
$this->hash = array($this, '_sha1'); $this->hash = array($this, '_sha1');

View File

@ -14,7 +14,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/RC2.php'); * include 'Crypt/RC2.php';
* *
* $rc2 = new Crypt_RC2(); * $rc2 = new Crypt_RC2();
* *
@ -117,7 +117,6 @@ define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* Pure-PHP implementation of RC2. * Pure-PHP implementation of RC2.
* *
* @package Crypt_RC2 * @package Crypt_RC2
* @version 0.1.1
* @access public * @access public
*/ */
class Crypt_RC2 extends Crypt_Base class Crypt_RC2 extends Crypt_Base
@ -178,7 +177,7 @@ class Crypt_RC2 extends Crypt_Base
*/ */
var $cfb_init_len = 500; var $cfb_init_len = 500;
/** /**
* The key length in bits. * The key length in bits.
* *
* @see Crypt_RC2::setKeyLength() * @see Crypt_RC2::setKeyLength()
@ -333,7 +332,7 @@ class Crypt_RC2 extends Crypt_Base
* *
* - CRYPT_RC2_MODE_OFB * - CRYPT_RC2_MODE_OFB
* *
* If not explictly set, CRYPT_RC2_MODE_CBC will be used. * If not explicitly set, CRYPT_RC2_MODE_CBC will be used.
* *
* @see Crypt_Base::Crypt_Base() * @see Crypt_Base::Crypt_Base()
* @param optional Integer $mode * @param optional Integer $mode
@ -386,7 +385,7 @@ class Crypt_RC2 extends Crypt_Base
$t1 = 1024; $t1 = 1024;
} }
// 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);
// The mcrypt RC2 implementation only supports effective key length // The mcrypt RC2 implementation only supports effective key length
@ -445,8 +444,8 @@ class Crypt_RC2 extends Crypt_Base
$r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
$r3 |= $r3 >> 16; $r3 |= $r3 >> 16;
if ($j == $limit) { if ($j === $limit) {
if ($limit == 64) { if ($limit === 64) {
break; break;
} }
@ -490,8 +489,8 @@ class Crypt_RC2 extends Crypt_Base
$r0 = ($r0 | ($r0 << 16)) >> 1; $r0 = ($r0 | ($r0 << 16)) >> 1;
$r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF; $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
if ($j == $limit) { if ($j === $limit) {
if (!$limit) { if ($limit === 0) {
break; break;
} }
@ -582,8 +581,8 @@ class Crypt_RC2 extends Crypt_Base
((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
$r3 |= $r3 >> 16;'; $r3 |= $r3 >> 16;';
if ($j == $limit) { if ($j === $limit) {
if ($limit == 64) { if ($limit === 64) {
break; break;
} }
@ -620,8 +619,8 @@ class Crypt_RC2 extends Crypt_Base
$r0 = ($r0 - ' . $keys[--$j] . ' - $r0 = ($r0 - ' . $keys[--$j] . ' -
((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;'; ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
if ($j == $limit) { if ($j === $limit) {
if (!$limit) { if ($limit === 0) {
break; break;
} }

View File

@ -18,7 +18,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/RC4.php'); * include 'Crypt/RC4.php';
* *
* $rc4 = new Crypt_RC4(); * $rc4 = new Crypt_RC4();
* *
@ -55,7 +55,7 @@
* @category Crypt * @category Crypt
* @package Crypt_RC4 * @package Crypt_RC4
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -96,7 +96,6 @@ define('CRYPT_RC4_DECRYPT', 1);
* *
* @package Crypt_RC4 * @package Crypt_RC4
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Crypt_RC4 extends Crypt_Base class Crypt_RC4 extends Crypt_Base
@ -241,7 +240,7 @@ class Crypt_RC4 extends Crypt_Base
* Decrypts a message. * Decrypts a message.
* *
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
* Atleast if the continuous buffer is disabled. * At least if the continuous buffer is disabled.
* *
* @see Crypt_Base::encrypt() * @see Crypt_Base::encrypt()
* @see Crypt_RC4::_crypt() * @see Crypt_RC4::_crypt()
@ -268,10 +267,7 @@ class Crypt_RC4 extends Crypt_Base
{ {
$key = $this->key; $key = $this->key;
$keyLength = strlen($key); $keyLength = strlen($key);
$keyStream = array(); $keyStream = range(0, 255);
for ($i = 0; $i < 256; $i++) {
$keyStream[$i] = $i;
}
$j = 0; $j = 0;
for ($i = 0; $i < 256; $i++) { for ($i = 0; $i < 256; $i++) {
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
@ -325,7 +321,7 @@ class Crypt_RC4 extends Crypt_Base
$keyStream[$i] = $ksj; $keyStream[$i] = $ksj;
$keyStream[$j] = $ksi; $keyStream[$j] = $ksi;
$text[$k] = chr(ord($text[$k]) ^ $keyStream[($ksj + $ksi) & 255]); $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
} }
return $text; return $text;

View File

@ -8,7 +8,7 @@
* Here's an example of how to encrypt and decrypt text with this library: * Here's an example of how to encrypt and decrypt text with this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/RSA.php'); * include 'Crypt/RSA.php';
* *
* $rsa = new Crypt_RSA(); * $rsa = new Crypt_RSA();
* extract($rsa->createKey()); * extract($rsa->createKey());
@ -26,7 +26,7 @@
* Here's an example of how to create signatures and verify signatures with this library: * Here's an example of how to create signatures and verify signatures with this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/RSA.php'); * include 'Crypt/RSA.php';
* *
* $rsa = new Crypt_RSA(); * $rsa = new Crypt_RSA();
* extract($rsa->createKey()); * extract($rsa->createKey());
@ -62,7 +62,7 @@
* @category Crypt * @category Crypt
* @package Crypt_RSA * @package Crypt_RSA
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMIX Jim Wigginton * @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -104,7 +104,7 @@ define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
* Use PKCS#1 padding. * Use PKCS#1 padding.
* *
* Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
* compatability 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);
/**#@-*/ /**#@-*/
@ -128,7 +128,7 @@ define('CRYPT_RSA_SIGNATURE_PSS', 1);
* Use the PKCS#1 scheme by default. * Use the PKCS#1 scheme by default.
* *
* Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
* compatability with protocols (like SSH-2) written before PSS's introduction. * compatibility with protocols (like SSH-2) written before PSS's introduction.
*/ */
define('CRYPT_RSA_SIGNATURE_PKCS1', 2); define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
/**#@-*/ /**#@-*/
@ -140,15 +140,23 @@ define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
/** /**
* ASN1 Integer * ASN1 Integer
*/ */
define('CRYPT_RSA_ASN1_INTEGER', 2); define('CRYPT_RSA_ASN1_INTEGER', 2);
/** /**
* ASN1 Bit String * ASN1 Bit String
*/ */
define('CRYPT_RSA_ASN1_BITSTRING', 3); define('CRYPT_RSA_ASN1_BITSTRING', 3);
/**
* ASN1 Octet String
*/
define('CRYPT_RSA_ASN1_OCTETSTRING', 4);
/**
* ASN1 Object Identifier
*/
define('CRYPT_RSA_ASN1_OBJECT', 6);
/** /**
* ASN1 Sequence (with the constucted bit set) * ASN1 Sequence (with the constucted bit set)
*/ */
define('CRYPT_RSA_ASN1_SEQUENCE', 48); define('CRYPT_RSA_ASN1_SEQUENCE', 48);
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -191,6 +199,10 @@ define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
* XML formatted private key * XML formatted private key
*/ */
define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2); define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
/**
* PKCS#8 formatted private key
*/
define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 3);
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -216,7 +228,14 @@ define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
* PKCS#1 formatted public key (raw) * PKCS#1 formatted public key (raw)
* *
* Used by File/X509.php * Used by File/X509.php
*
* Has the following header:
*
* -----BEGIN RSA PUBLIC KEY-----
*
* Analogous to ssh-keygen's pem format (as specified by -m)
*/ */
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4); define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
/** /**
* XML formatted public key * XML formatted public key
@ -232,8 +251,16 @@ define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
* PKCS#1 formatted public key (encapsulated) * PKCS#1 formatted public key (encapsulated)
* *
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
*
* Has the following header:
*
* -----BEGIN PUBLIC KEY-----
*
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
* is specific to private keys it's basically creating a DER-encoded wrapper
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
*/ */
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7); define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7);
/**#@-*/ /**#@-*/
/** /**
@ -241,7 +268,6 @@ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7);
* *
* @package Crypt_RSA * @package Crypt_RSA
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Crypt_RSA class Crypt_RSA
@ -276,7 +302,7 @@ class Crypt_RSA
* @var Integer * @var Integer
* @access public * @access public
*/ */
var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1; var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8;
/** /**
* Modulus (ie. n) * Modulus (ie. n)
@ -467,18 +493,21 @@ class Crypt_RSA
$this->configFile = CRYPT_RSA_OPENSSL_CONFIG; $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
if ( !defined('CRYPT_RSA_MODE') ) { if ( !defined('CRYPT_RSA_MODE') ) {
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, switch (true) {
// Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
if ( defined('MATH_BIGINTEGER_OPENSSL_DISABLE') ) { // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
} define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
break;
switch ( !defined('CRYPT_RSA_MODE') ) { // ie. only run this if the above didn't set CRYPT_RSA_MODE already // openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0
case !function_exists('openssl_pkey_get_details'):
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
break;
case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile): case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start(); ob_start();
phpinfo(); @phpinfo();
$content = ob_get_contents(); $content = ob_get_contents();
ob_end_clean(); ob_end_clean();
@ -486,9 +515,16 @@ class Crypt_RSA
$versions = array(); $versions = array();
if (!empty($matches[1])) { if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) { for ($i = 0; $i < count($matches[1]); $i++) {
$versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
}
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
}
} }
// it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
@ -503,7 +539,7 @@ class Crypt_RSA
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
} }
break; break;
case true: default:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
} }
} }
@ -713,17 +749,18 @@ class Crypt_RSA
*/ */
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
{ {
$signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML;
$num_primes = count($primes); $num_primes = count($primes);
$raw = array( $raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
'modulus' => $n->toBytes(true), 'modulus' => $n->toBytes($signed),
'publicExponent' => $e->toBytes(true), 'publicExponent' => $e->toBytes($signed),
'privateExponent' => $d->toBytes(true), 'privateExponent' => $d->toBytes($signed),
'prime1' => $primes[1]->toBytes(true), 'prime1' => $primes[1]->toBytes($signed),
'prime2' => $primes[2]->toBytes(true), 'prime2' => $primes[2]->toBytes($signed),
'exponent1' => $exponents[1]->toBytes(true), 'exponent1' => $exponents[1]->toBytes($signed),
'exponent2' => $exponents[2]->toBytes(true), 'exponent2' => $exponents[2]->toBytes($signed),
'coefficient' => $coefficients[2]->toBytes(true) 'coefficient' => $coefficients[2]->toBytes($signed)
); );
// if the format in question does not support multi-prime rsa and multi-prime rsa was used, // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
@ -756,8 +793,8 @@ class Crypt_RSA
strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus'] strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
); );
$source = pack('Na*Na*Na*Na*', $source = pack('Na*Na*Na*Na*',
strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
strlen($this->comment), $this->comment, strlen($public), $public 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";
@ -829,6 +866,52 @@ class Crypt_RSA
$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 ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) {
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPrivateKey = pack('Ca*a*Ca*a*',
CRYPT_RSA_ASN1_INTEGER, "\01\00", $rsaOID, 4, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey
);
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
if (!empty($this->password) || is_string($this->password)) {
$salt = crypt_random_string(8);
$iterationCount = 2048;
if (!class_exists('Crypt_DES')) {
include_once 'Crypt/DES.php';
}
$crypto = new Crypt_DES();
$crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
$RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
$parameters = pack('Ca*a*Ca*N',
CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($salt)), $salt,
CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(4), $iterationCount
);
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
$encryptionAlgorithm = pack('Ca*a*Ca*a*',
CRYPT_RSA_ASN1_OBJECT, $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), $pbeWithMD5AndDES_CBC,
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($parameters)), $parameters
);
$RSAPrivateKey = pack('Ca*a*Ca*a*',
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($encryptionAlgorithm)), $encryptionAlgorithm,
CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey
);
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
$RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END ENCRYPTED PRIVATE KEY-----';
} else {
$RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END PRIVATE KEY-----';
}
return $RSAPrivateKey;
}
if (!empty($this->password) || is_string($this->password)) { if (!empty($this->password) || is_string($this->password)) {
$iv = crypt_random_string(8); $iv = crypt_random_string(8);
$symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
@ -866,8 +949,10 @@ class Crypt_RSA
*/ */
function _convertPublicKey($n, $e) function _convertPublicKey($n, $e)
{ {
$modulus = $n->toBytes(true); $signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML;
$publicExponent = $e->toBytes(true);
$modulus = $n->toBytes($signed);
$publicExponent = $e->toBytes($signed);
switch ($this->publicKeyFormat) { switch ($this->publicKeyFormat) {
case CRYPT_RSA_PUBLIC_FORMAT_RAW: case CRYPT_RSA_PUBLIC_FORMAT_RAW:
@ -903,7 +988,11 @@ class Crypt_RSA
$components['modulus'], $components['publicExponent'] $components['modulus'], $components['publicExponent']
); );
if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) {
$RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END RSA PUBLIC KEY-----';
} else {
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption. // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPublicKey = chr(0) . $RSAPublicKey; $RSAPublicKey = chr(0) . $RSAPublicKey;
@ -912,11 +1001,11 @@ class Crypt_RSA
$RSAPublicKey = pack('Ca*a*', $RSAPublicKey = pack('Ca*a*',
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
); );
}
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) . chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END PUBLIC KEY-----'; '-----END PUBLIC KEY-----';
}
return $RSAPublicKey; return $RSAPublicKey;
} }
@ -972,6 +1061,7 @@ class Crypt_RSA
} }
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false; return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
case CRYPT_RSA_PRIVATE_FORMAT_PKCS8:
case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
@ -1062,7 +1152,9 @@ class Crypt_RSA
7:d=1 hl=2 l= 13 cons: SEQUENCE 7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
20:d=2 hl=2 l= 0 prim: NULL 20:d=2 hl=2 l= 0 prim: NULL
22:d=1 hl=4 l= 609 prim: OCTET STRING */ 22:d=1 hl=4 l= 609 prim: OCTET STRING
ie. PKCS8 keys*/
if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") { if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
$this->_string_shift($key, 3); $this->_string_shift($key, 3);
@ -1070,6 +1162,52 @@ class Crypt_RSA
} }
if ($tag == CRYPT_RSA_ASN1_SEQUENCE) { if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
$temp = $this->_string_shift($key, $this->_decodeLength($key));
if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_OBJECT) {
return false;
}
$length = $this->_decodeLength($temp);
switch ($this->_string_shift($temp, $length)) {
case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
break;
case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
/*
PBEParameter ::= SEQUENCE {
salt OCTET STRING (SIZE(8)),
iterationCount INTEGER }
*/
if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($temp) != strlen($temp)) {
return false;
}
$this->_string_shift($temp); // assume it's an octet string
$salt = $this->_string_shift($temp, $this->_decodeLength($temp));
if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$this->_decodeLength($temp);
list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
$this->_string_shift($key); // assume it's an octet string
$length = $this->_decodeLength($key);
if (strlen($key) != $length) {
return false;
}
if (!class_exists('Crypt_DES')) {
include_once 'Crypt/DES.php';
}
$crypto = new Crypt_DES();
$crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
$key = $crypto->decrypt($key);
if ($key === false) {
return false;
}
return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
default:
return false;
}
/* intended for keys for which OpenSSL's asn1parse returns the following: /* intended for keys for which OpenSSL's asn1parse returns the following:
0:d=0 hl=4 l= 290 cons: SEQUENCE 0:d=0 hl=4 l= 290 cons: SEQUENCE
@ -1077,7 +1215,6 @@ class Crypt_RSA
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
17:d=2 hl=2 l= 0 prim: NULL 17:d=2 hl=2 l= 0 prim: NULL
19:d=1 hl=4 l= 271 prim: BIT STRING */ 19:d=1 hl=4 l= 271 prim: BIT STRING */
$this->_string_shift($key, $this->_decodeLength($key));
$tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
$this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
@ -1479,6 +1616,19 @@ class Crypt_RSA
$this->publicExponent = false; $this->publicExponent = false;
} }
switch ($type) {
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
$this->setPublicKey();
break;
case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
switch (true) {
case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
$this->setPublicKey();
}
}
return true; return true;
} }
@ -1505,7 +1655,9 @@ class Crypt_RSA
* used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
* message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
* and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
* exponent this won't work unless you manually add the public exponent. * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
* is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
* public.
* *
* Do note that when a new key is loaded the index will be cleared. * Do note that when a new key is loaded the index will be cleared.
* *
@ -1561,6 +1713,40 @@ class Crypt_RSA
return true; return true;
} }
/**
* Defines the private key
*
* If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
* phpseclib to treat the key as a private key. This function will do that.
*
* Do note that when a new key is loaded the index will be cleared.
*
* Returns true on success, false on failure
*
* @see getPublicKey()
* @access public
* @param String $key optional
* @param Integer $type optional
* @return Boolean
*/
function setPrivateKey($key = false, $type = false)
{
if ($key === false && !empty($this->publicExponent)) {
unset($this->publicExponent);
return true;
}
$rsa = new Crypt_RSA();
if (!$rsa->loadKey($key, $type)) {
return false;
}
unset($rsa->publicExponent);
// don't overwrite the old key if the new key is invalid
$this->loadKey($rsa);
return true;
}
/** /**
* Returns the public key * Returns the public key
* *
@ -1573,7 +1759,7 @@ class Crypt_RSA
* @param String $key * @param String $key
* @param Integer $type optional * @param Integer $type optional
*/ */
function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
{ {
if (empty($this->modulus) || empty($this->publicExponent)) { if (empty($this->modulus) || empty($this->publicExponent)) {
return false; return false;
@ -1620,7 +1806,7 @@ class Crypt_RSA
* @param String $key * @param String $key
* @param Integer $type optional * @param Integer $type optional
*/ */
function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
{ {
if (empty($this->modulus) || empty($this->exponent)) { if (empty($this->modulus) || empty($this->exponent)) {
return false; return false;
@ -2275,11 +2461,11 @@ class Crypt_RSA
* *
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
* *
* For compatability purposes, this function departs slightly from the description given in RFC3447. * For compatibility purposes, this function departs slightly from the description given in RFC3447.
* The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
* private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
* public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
* to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the
* second byte is 2 or less. If it is, we'll accept the decrypted string as valid. * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
* *
* As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt

View File

@ -3,12 +3,15 @@
/** /**
* Random Number Generator * Random Number Generator
* *
* The idea behind this function is that it can be easily replaced with your own crypt_random_string()
* function. eg. maybe you have a better source of entropy for creating the initial states or whatever.
*
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/Random.php'); * include 'Crypt/Random.php';
* *
* echo bin2hex(crypt_random_string(8)); * echo bin2hex(crypt_random_string(8));
* ?> * ?>
@ -35,181 +38,210 @@
* @category Crypt * @category Crypt
* @package Crypt_Random * @package Crypt_Random
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
/** // laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
* "Is Windows" test // have phpseclib as a requirement as well. if you're developing such a program you may encounter
* // a "Cannot redeclare crypt_random_string()" error.
* @access private if (!function_exists('crypt_random_string')) {
*/ /**
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); * "Is Windows" test
*
* @access private
*/
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
/** /**
* Generate a random string. * Generate a random string.
* *
* Although microoptimizations are generally discouraged as they impair readability this function is ripe with * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
* microoptimizations because this function has the potential of being called a huge number of times. * microoptimizations because this function has the potential of being called a huge number of times.
* eg. for RSA key generation. * eg. for RSA key generation.
* *
* @param Integer $length * @param Integer $length
* @return String * @return String
* @access public * @access public
*/ */
function crypt_random_string($length) function crypt_random_string($length)
{ {
if (CRYPT_RANDOM_IS_WINDOWS) { if (CRYPT_RANDOM_IS_WINDOWS) {
// method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call. // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
// ie. class_alias is a function that was introduced in PHP 5.3 // ie. class_alias is a function that was introduced in PHP 5.3
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
return mcrypt_create_iv($length); return mcrypt_create_iv($length);
} }
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was, // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
// to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4 // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
// openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
// call php_win32_get_random_bytes(): // call php_win32_get_random_bytes():
// //
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008 // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392 // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
// //
// php_win32_get_random_bytes() is defined thusly: // php_win32_get_random_bytes() is defined thusly:
// //
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80 // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
// //
// we're calling it, all the same, in the off chance that the mcrypt extension is not available // we're calling it, all the same, in the off chance that the mcrypt extension is not available
if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) { if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
return openssl_random_pseudo_bytes($length); return openssl_random_pseudo_bytes($length);
} }
} else {
// method 1. the fastest
if (function_exists('openssl_random_pseudo_bytes')) {
return openssl_random_pseudo_bytes($length);
}
// method 2
static $fp = true;
if ($fp === 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.
$fp = @fopen('/dev/urandom', 'rb');
}
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
return fread($fp, $length);
}
// method 3. pretty much does the same thing as method 2 per the following url:
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
// restrictions or some such
if (function_exists('mcrypt_create_iv')) {
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
}
// at this point we have no choice but to use a pure-PHP CSPRNG
// cascade entropy across multiple PHP instances by fixing the session and collecting all
// environmental variables, including the previous session data and the current session
// data.
//
// mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
// easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
// PHP isn't low level to be able to use those as sources and on a web server there's not likely
// going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
// however. a ton of people visiting the website. obviously you don't want to base your seeding
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
// by the user and (2) this isn't just looking at the data sent by the current user - it's based
// on the data sent by all users. one user requests the page and a hash of their info is saved.
// another user visits the page and the serialization of their data is utilized along with the
// server envirnment stuff and a hash of the previous http request data (which itself utilizes
// a hash of the session data before that). certainly an attacker should be assumed to have
// full control over his own http requests. he, however, is not going to have control over
// everyone's http requests.
static $crypto = false, $v;
if ($crypto === false) {
// save old session data
$old_session_id = session_id();
$old_use_cookies = ini_get('session.use_cookies');
$old_session_cache_limiter = session_cache_limiter();
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
if ($old_session_id != '') {
session_write_close();
}
session_id(1);
ini_set('session.use_cookies', 0);
session_cache_limiter('');
session_start();
$v = $seed = $_SESSION['seed'] = pack('H*', sha1(
serialize($_SERVER) .
serialize($_POST) .
serialize($_GET) .
serialize($_COOKIE) .
serialize($GLOBALS) .
serialize($_SESSION) .
serialize($_OLD_SESSION)
));
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
}
$_SESSION['count']++;
session_write_close();
// restore old session data
if ($old_session_id != '') {
session_id($old_session_id);
session_start();
ini_set('session.use_cookies', $old_use_cookies);
session_cache_limiter($old_session_cache_limiter);
} else { } else {
if ($_OLD_SESSION !== false) { // method 1. the fastest
$_SESSION = $_OLD_SESSION; if (function_exists('openssl_random_pseudo_bytes')) {
unset($_OLD_SESSION); return openssl_random_pseudo_bytes($length);
} else { }
unset($_SESSION); // method 2
static $fp = true;
if ($fp === 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.
$fp = @fopen('/dev/urandom', 'rb');
}
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
return fread($fp, $length);
}
// method 3. pretty much does the same thing as method 2 per the following url:
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
// restrictions or some such
if (function_exists('mcrypt_create_iv')) {
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
} }
} }
// at this point we have no choice but to use a pure-PHP CSPRNG
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process. // cascade entropy across multiple PHP instances by fixing the session and collecting all
// the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C. // environmental variables, including the previous session data and the current session
// if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the // data.
// original hash and the current hash. we'll be emulating that. for more info see the following URL:
// //
// http://tools.ietf.org/html/rfc4253#section-7.2 // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
// // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
// see the is_string($crypto) part for an example of how to expand the keys // PHP isn't low level to be able to use those as sources and on a web server there's not likely
$key = pack('H*', sha1($seed . 'A')); // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
$iv = pack('H*', sha1($seed . 'C')); // however, a ton of people visiting the website. obviously you don't want to base your seeding
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
// by the user and (2) this isn't just looking at the data sent by the current user - it's based
// on the data sent by all users. one user requests the page and a hash of their info is saved.
// another user visits the page and the serialization of their data is utilized along with the
// server envirnment stuff and a hash of the previous http request data (which itself utilizes
// a hash of the session data before that). certainly an attacker should be assumed to have
// full control over his own http requests. he, however, is not going to have control over
// everyone's http requests.
static $crypto = false, $v;
if ($crypto === false) {
// save old session data
$old_session_id = session_id();
$old_use_cookies = ini_get('session.use_cookies');
$old_session_cache_limiter = session_cache_limiter();
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
if ($old_session_id != '') {
session_write_close();
}
// ciphers are used as per the nist.gov link below. also, see this link: session_id(1);
// ini_set('session.use_cookies', 0);
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives session_cache_limiter('');
switch (true) { session_start();
case class_exists('Crypt_AES'):
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
break; serialize($_SERVER) .
case class_exists('Crypt_TripleDES'): serialize($_POST) .
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); serialize($_GET) .
break; serialize($_COOKIE) .
case class_exists('Crypt_DES'): serialize($GLOBALS) .
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); serialize($_SESSION) .
break; serialize($_OLD_SESSION)
case class_exists('Crypt_RC4'): ));
$crypto = new Crypt_RC4(); if (!isset($_SESSION['count'])) {
break; $_SESSION['count'] = 0;
default: }
$crypto = $seed; $_SESSION['count']++;
return crypt_random_string($length);
session_write_close();
// restore old session data
if ($old_session_id != '') {
session_id($old_session_id);
session_start();
ini_set('session.use_cookies', $old_use_cookies);
session_cache_limiter($old_session_cache_limiter);
} else {
if ($_OLD_SESSION !== false) {
$_SESSION = $_OLD_SESSION;
unset($_OLD_SESSION);
} else {
unset($_SESSION);
}
}
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
// the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
// if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
// original hash and the current hash. we'll be emulating that. for more info see the following URL:
//
// http://tools.ietf.org/html/rfc4253#section-7.2
//
// see the is_string($crypto) part for an example of how to expand the keys
$key = pack('H*', sha1($seed . 'A'));
$iv = pack('H*', sha1($seed . 'C'));
// ciphers are used as per the nist.gov link below. also, see this link:
//
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
switch (true) {
case phpseclib_resolve_include_path('Crypt/AES.php'):
if (!class_exists('Crypt_AES')) {
include_once 'AES.php';
}
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/Twofish.php'):
if (!class_exists('Crypt_Twofish')) {
include_once 'Twofish.php';
}
$crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/Blowfish.php'):
if (!class_exists('Crypt_Blowfish')) {
include_once 'Blowfish.php';
}
$crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/TripleDES.php'):
if (!class_exists('Crypt_TripleDES')) {
include_once 'TripleDES.php';
}
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/DES.php'):
if (!class_exists('Crypt_DES')) {
include_once 'DES.php';
}
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/RC4.php'):
if (!class_exists('Crypt_RC4')) {
include_once 'RC4.php';
}
$crypto = new Crypt_RC4();
break;
default:
user_error('crypt_random_string requires at least one symmetric cipher be loaded');
return false;
}
$crypto->setKey($key);
$crypto->setIV($iv);
$crypto->enableContinuousBuffer();
} }
$crypto->setKey($key); //return $crypto->encrypt(str_repeat("\0", $length));
$crypto->setIV($iv);
$crypto->enableContinuousBuffer();
}
if (is_string($crypto)) {
// the following is based off of ANSI X9.31: // the following is based off of ANSI X9.31:
// //
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
@ -218,29 +250,51 @@ function crypt_random_string($length)
// //
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
// (do a search for "ANS X9.31 A.2.4") // (do a search for "ANS X9.31 A.2.4")
//
// ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see
// later on in the code) but if they're not we'll use sha1
$result = ''; $result = '';
while (strlen($result) < $length) { // each loop adds 20 bytes while (strlen($result) < $length) {
// microtime() isn't packed as "densely" as it could be but then neither is that the idea. $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
// the idea is simply to ensure that each "block" has a unique element to it. $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
$i = pack('H*', sha1(microtime())); $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
$r = pack('H*', sha1($i ^ $v));
$v = pack('H*', sha1($r ^ $i));
$result.= $r; $result.= $r;
} }
return substr($result, 0, $length); return substr($result, 0, $length);
} }
}
//return $crypto->encrypt(str_repeat("\0", $length));
if (!function_exists('phpseclib_resolve_include_path')) {
$result = ''; /**
while (strlen($result) < $length) { * Resolve filename against the include path.
$i = $crypto->encrypt(microtime()); *
$r = $crypto->encrypt($i ^ $v); * Wrapper around stream_resolve_include_path() (which was introduced in
$v = $crypto->encrypt($r ^ $i); * PHP 5.3.2) with fallback implementation for earlier PHP versions.
$result.= $r; *
} * @param string $filename
return substr($result, 0, $length); * @return mixed Filename (string) on success, false otherwise.
* @access public
*/
function phpseclib_resolve_include_path($filename)
{
if (function_exists('stream_resolve_include_path')) {
return stream_resolve_include_path($filename);
}
// handle non-relative paths
if (file_exists($filename)) {
return realpath($filename);
}
$paths = PATH_SEPARATOR == ':' ?
preg_split('#(?<!phar):#', get_include_path()) :
explode(PATH_SEPARATOR, get_include_path());
foreach ($paths as $prefix) {
// path's specified in include_path don't always end in /
$ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR;
$file = $prefix . $ds . $filename;
if (file_exists($file)) {
return realpath($file);
}
}
return false;
}
} }

View File

@ -28,7 +28,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/Rijndael.php'); * include 'Crypt/Rijndael.php';
* *
* $rijndael = new Crypt_Rijndael(); * $rijndael = new Crypt_Rijndael();
* *
@ -65,7 +65,7 @@
* @category Crypt * @category Crypt
* @package Crypt_Rijndael * @package Crypt_Rijndael
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton * @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -120,7 +120,7 @@ define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_Rijndael::Crypt_Rijndael() * @see Crypt_Base::Crypt_Base()
*/ */
/** /**
* Toggles the internal implementation * Toggles the internal implementation
@ -137,7 +137,6 @@ define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* *
* @package Crypt_Rijndael * @package Crypt_Rijndael
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Crypt_Rijndael extends Crypt_Base class Crypt_Rijndael extends Crypt_Base
@ -167,7 +166,7 @@ class Crypt_Rijndael extends Crypt_Base
* Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not. * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not.
* Crypt_Rijndael determines automatically whether mcrypt is useable * Crypt_Rijndael determines automatically whether mcrypt is useable
* or not for the current $block_size/$key_size. * or not for the current $block_size/$key_size.
* In case of, $cipher_name_mcrypt will be set dynamicaly at run time accordingly. * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
* *
* @see Crypt_Base::cipher_name_mcrypt * @see Crypt_Base::cipher_name_mcrypt
* @see Crypt_Base::engine * @see Crypt_Base::engine
@ -676,34 +675,6 @@ class Crypt_Rijndael extends Crypt_Base
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
); );
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_RIJNDAEL_MODE_ECB
*
* - CRYPT_RIJNDAEL_MODE_CBC
*
* - CRYPT_RIJNDAEL_MODE_CTR
*
* - CRYPT_RIJNDAEL_MODE_CFB
*
* - CRYPT_RIJNDAEL_MODE_OFB
*
* If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
*
* @see Crypt_Base::Crypt_Base()
* @param optional Integer $mode
* @access public
*/
function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
{
parent::Crypt_Base($mode);
}
/** /**
* Sets the key. * Sets the key.
* *
@ -731,9 +702,15 @@ class Crypt_Rijndael extends Crypt_Base
case $length <= 16: case $length <= 16:
$this->key_size = 16; $this->key_size = 16;
break; break;
case $length <= 20:
$this->key_size = 20;
break;
case $length <= 24: case $length <= 24:
$this->key_size = 24; $this->key_size = 24;
break; break;
case $length <= 28:
$this->key_size = 28;
break;
default: default:
$this->key_size = 32; $this->key_size = 32;
} }
@ -755,7 +732,7 @@ class Crypt_Rijndael extends Crypt_Base
* you should not setKeyLength(160) or setKeyLength(224). * you should not setKeyLength(160) or setKeyLength(224).
* *
* Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
* the mcrypt php extention, even if available. * the mcrypt php extension, even if available.
* This results then in slower encryption. * This results then in slower encryption.
* *
* @access public * @access public

View File

@ -10,7 +10,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/TripleDES.php'); * include 'Crypt/TripleDES.php';
* *
* $des = new Crypt_TripleDES(); * $des = new Crypt_TripleDES();
* *
@ -47,7 +47,7 @@
* @category Crypt * @category Crypt
* @package Crypt_TripleDES * @package Crypt_TripleDES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -78,7 +78,6 @@ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
* *
* @package Crypt_TripleDES * @package Crypt_TripleDES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Crypt_TripleDES extends Crypt_DES class Crypt_TripleDES extends Crypt_DES
@ -180,7 +179,7 @@ class Crypt_TripleDES extends Crypt_DES
* *
* - CRYPT_DES_MODE_3CBC * - CRYPT_DES_MODE_3CBC
* *
* If not explictly set, CRYPT_DES_MODE_CBC will be used. * If not explicitly set, CRYPT_DES_MODE_CBC will be used.
* *
* @see Crypt_DES::Crypt_DES() * @see Crypt_DES::Crypt_DES()
* @see Crypt_Base::Crypt_Base() * @see Crypt_Base::Crypt_Base()
@ -193,7 +192,7 @@ class Crypt_TripleDES extends Crypt_DES
// 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_DES(CRYPT_DES_MODE_CBC); parent::Crypt_Base(CRYPT_DES_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)
@ -210,14 +209,14 @@ class Crypt_TripleDES extends Crypt_DES
break; break;
// If not 3CBC, we init as usual // If not 3CBC, we init as usual
default: default:
parent::Crypt_DES($mode); parent::Crypt_Base($mode);
} }
} }
/** /**
* Sets the initialization vector. (optional) * Sets the initialization vector. (optional)
* *
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed
* to be all zero's. * to be all zero's.
* *
* @see Crypt_Base::setIV() * @see Crypt_Base::setIV()
@ -289,8 +288,12 @@ class Crypt_TripleDES extends Crypt_DES
// 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) {
return $this->des[2]->encrypt( return $this->des[2]->encrypt(
$this->des[1]->decrypt( $this->des[1]->decrypt(
$this->des[0]->encrypt($this->_pad($plaintext)))); $this->des[0]->encrypt(
$this->_pad($plaintext)
)
)
);
} }
return parent::encrypt($plaintext); return parent::encrypt($plaintext);
@ -307,9 +310,15 @@ class Crypt_TripleDES extends Crypt_DES
function decrypt($ciphertext) function decrypt($ciphertext)
{ {
if ($this->mode_3cbc && strlen($this->key) > 8) { if ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->_unpad($this->des[0]->decrypt( return $this->_unpad(
$this->des[1]->encrypt( $this->des[0]->decrypt(
$this->des[2]->decrypt(str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0"))))); $this->des[1]->encrypt(
$this->des[2]->decrypt(
str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
)
)
)
);
} }
return parent::decrypt($ciphertext); return parent::decrypt($ciphertext);

View File

@ -14,7 +14,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/Twofish.php'); * include 'Crypt/Twofish.php';
* *
* $twofish = new Crypt_Twofish(); * $twofish = new Crypt_Twofish();
* *
@ -48,9 +48,8 @@
* @package Crypt_Twofish * @package Crypt_Twofish
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 1.0
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -104,7 +103,7 @@ define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@+ /**#@+
* @access private * @access private
* @see Crypt_Twofish::Crypt_Twofish() * @see Crypt_Base::Crypt_Base()
*/ */
/** /**
* Toggles the internal implementation * Toggles the internal implementation
@ -122,7 +121,6 @@ define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* @package Crypt_Twofish * @package Crypt_Twofish
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @version 1.0
* @access public * @access public
*/ */
class Crypt_Twofish extends Crypt_Base class Crypt_Twofish extends Crypt_Base
@ -448,34 +446,6 @@ class Crypt_Twofish extends Crypt_Base
*/ */
var $kl; var $kl;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_TWOFISH_MODE_ECB
*
* - CRYPT_TWOFISH_MODE_CBC
*
* - CRYPT_TWOFISH_MODE_CTR
*
* - CRYPT_TWOFISH_MODE_CFB
*
* - CRYPT_TWOFISH_MODE_OFB
*
* If not explictly set, CRYPT_TWOFISH_MODE_CBC will be used.
*
* @see Crypt_Base::Crypt_Base()
* @param optional Integer $mode
* @access public
*/
function Crypt_Twofish($mode = CRYPT_TWOFISH_MODE_CBC)
{
parent::Crypt_Base($mode);
}
/** /**
* Sets the key. * Sets the key.
* *
@ -709,10 +679,12 @@ class Crypt_Twofish extends Crypt_Base
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]); $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
} }
// @codingStandardsIgnoreStart
return pack("V4", $K[4] ^ $R2, return pack("V4", $K[4] ^ $R2,
$K[5] ^ $R3, $K[5] ^ $R3,
$K[6] ^ $R0, $K[6] ^ $R0,
$K[7] ^ $R1); $K[7] ^ $R1);
// @codingStandardsIgnoreEnd
} }
/** /**
@ -763,10 +735,12 @@ class Crypt_Twofish extends Crypt_Base
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]); $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
} }
// @codingStandardsIgnoreStart
return pack("V4", $K[0] ^ $R2, return pack("V4", $K[0] ^ $R2,
$K[1] ^ $R3, $K[1] ^ $R3,
$K[2] ^ $R0, $K[2] ^ $R0,
$K[3] ^ $R1); $K[3] ^ $R1);
// @codingStandardsIgnoreEnd
} }
/** /**

View File

@ -31,7 +31,7 @@
* @category File * @category File
* @package File_ANSI * @package File_ANSI
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -41,7 +41,6 @@
* *
* @package File_ANSI * @package File_ANSI
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.0
* @access public * @access public
*/ */
class File_ANSI class File_ANSI

View File

@ -34,7 +34,7 @@
* @category File * @category File
* @package File_ASN1 * @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -112,7 +112,6 @@ define('FILE_ASN1_TYPE_ANY', -2);
* *
* @package File_ASN1 * @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.0
* @access public * @access public
*/ */
class File_ASN1_Element class File_ASN1_Element
@ -143,7 +142,6 @@ class File_ASN1_Element
* *
* @package File_ASN1 * @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.0
* @access public * @access public
*/ */
class File_ASN1 class File_ASN1
@ -164,7 +162,7 @@ class File_ASN1
* @access private * @access private
* @link http://php.net/class.datetime * @link http://php.net/class.datetime
*/ */
var $format = 'D, d M y H:i:s O'; var $format = 'D, d M Y H:i:s O';
/** /**
* Default date format * Default date format
@ -274,7 +272,8 @@ class File_ASN1
} }
$this->encoded = $encoded; $this->encoded = $encoded;
return $this->_decode_ber($encoded); // encapsulate in an array for BC with the old decodeBER
return array($this->_decode_ber($encoded));
} }
/** /**
@ -289,215 +288,245 @@ class File_ASN1
* @return Array * @return Array
* @access private * @access private
*/ */
function _decode_ber(&$encoded, $start = 0) function _decode_ber($encoded, $start = 0)
{ {
$decoded = array(); $current = array('start' => $start);
while ( strlen($encoded) ) { $type = ord($this->_string_shift($encoded));
$current = array('start' => $start); $start++;
$type = ord($this->_string_shift($encoded)); $constructed = ($type >> 5) & 1;
$start++;
$constructed = ($type >> 5) & 1; $tag = $type & 0x1F;
if ($tag == 0x1F) {
$tag = $type & 0x1F; $tag = 0;
if ($tag == 0x1F) { // process septets (since the eighth bit is ignored, it's not an octet)
$tag = 0; do {
// process septets (since the eighth bit is ignored, it's not an octet) $loop = ord($encoded[0]) >> 7;
do { $tag <<= 7;
$loop = ord($encoded[0]) >> 7; $tag |= ord($this->_string_shift($encoded)) & 0x7F;
$tag <<= 7; $start++;
$tag |= ord($this->_string_shift($encoded)) & 0x7F; } while ( $loop );
$start++;
} while ( $loop );
}
// Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
$length = ord($this->_string_shift($encoded));
$start++;
if ( $length == 0x80 ) { // indefinite length
// "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
// immediately available." -- paragraph 8.1.3.2.c
//if ( !$constructed ) {
// return false;
//}
$length = strlen($encoded);
} elseif ( $length & 0x80 ) { // definite length, long form
// technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
// support it up to four.
$length&= 0x7F;
$temp = $this->_string_shift($encoded, $length);
// tags of indefinite length don't really have a header length; this length includes the tag
$current+= array('headerlength' => $length + 2);
$start+= $length;
extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
} else {
$current+= array('headerlength' => 2);
}
// End-of-content, see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
if (!$type && !$length) {
return $decoded;
}
$content = $this->_string_shift($encoded, $length);
/* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
built-in types. It defines an application-independent data type that must be distinguishable from all other
data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
data type; the term CONTEXT-SPECIFIC does not appear.
-- http://www.obj-sys.com/asn1tutorial/node12.html */
$class = ($type >> 6) & 3;
switch ($class) {
case FILE_ASN1_CLASS_APPLICATION:
case FILE_ASN1_CLASS_PRIVATE:
case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
$decoded[] = array(
'type' => $class,
'constant' => $tag,
'content' => $constructed ? $this->_decode_ber($content, $start) : $content,
'length' => $length + $start - $current['start']
) + $current;
$start+= $length;
continue 2;
}
$current+= array('type' => $tag);
// decode UNIVERSAL tags
switch ($tag) {
case FILE_ASN1_TYPE_BOOLEAN:
// "The contents octets shall consist of a single octet." -- paragraph 8.2.1
//if (strlen($content) != 1) {
// return false;
//}
$current['content'] = (bool) ord($content[0]);
break;
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
$current['content'] = new Math_BigInteger($content, -256);
break;
case FILE_ASN1_TYPE_REAL: // not currently supported
return false;
case FILE_ASN1_TYPE_BIT_STRING:
// The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
// the number of unused bits in the final subsequent octet. The number shall be in the range zero to
// seven.
if (!$constructed) {
$current['content'] = $content;
} else {
$temp = $this->_decode_ber($content, $start);
$length-= strlen($content);
$last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) {
// all subtags should be bit strings
//if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
// return false;
//}
$current['content'].= substr($temp[$i]['content'], 1);
}
// all subtags should be bit strings
//if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
// return false;
//}
$current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
}
break;
case FILE_ASN1_TYPE_OCTET_STRING:
if (!$constructed) {
$current['content'] = $content;
} else {
$temp = $this->_decode_ber($content, $start);
$length-= strlen($content);
for ($i = 0, $size = count($temp); $i < $size; $i++) {
// all subtags should be octet strings
//if ($temp[$i]['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
// return false;
//}
$current['content'].= $temp[$i]['content'];
}
// $length =
}
break;
case FILE_ASN1_TYPE_NULL:
// "The contents octets shall not contain any octets." -- paragraph 8.8.2
//if (strlen($content)) {
// return false;
//}
break;
case FILE_ASN1_TYPE_SEQUENCE:
case FILE_ASN1_TYPE_SET:
$current['content'] = $this->_decode_ber($content, $start);
break;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
$temp = ord($this->_string_shift($content));
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
$valuen = 0;
// process septets
while (strlen($content)) {
$temp = ord($this->_string_shift($content));
$valuen <<= 7;
$valuen |= $temp & 0x7F;
if (~$temp & 0x80) {
$current['content'].= ".$valuen";
$valuen = 0;
}
}
// the eighth bit of the last byte should not be 1
//if ($temp >> 7) {
// return false;
//}
break;
/* Each character string type shall be encoded as if it had been declared:
[UNIVERSAL x] IMPLICIT OCTET STRING
-- X.690-0207.pdf#page=23 (paragraph 8.21.3)
Per that, we're not going to do any validation. If there are any illegal characters in the string,
we don't really care */
case FILE_ASN1_TYPE_NUMERIC_STRING:
// 0,1,2,3,4,5,6,7,8,9, and space
case FILE_ASN1_TYPE_PRINTABLE_STRING:
// Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
// hyphen, full stop, solidus, colon, equal sign, question mark
case FILE_ASN1_TYPE_TELETEX_STRING:
// The Teletex character set in CCITT's T61, space, and delete
// see http://en.wikipedia.org/wiki/Teletex#Character_sets
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
// The Videotex character set in CCITT's T.100 and T.101, space, and delete
case FILE_ASN1_TYPE_VISIBLE_STRING:
// Printing character sets of international ASCII, and space
case FILE_ASN1_TYPE_IA5_STRING:
// International Alphabet 5 (International ASCII)
case FILE_ASN1_TYPE_GRAPHIC_STRING:
// All registered G sets, and space
case FILE_ASN1_TYPE_GENERAL_STRING:
// All registered C and G sets, space and delete
case FILE_ASN1_TYPE_UTF8_STRING:
// ????
case FILE_ASN1_TYPE_BMP_STRING:
$current['content'] = $content;
break;
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
$current['content'] = $this->_decodeTime($content, $tag);
default:
}
$start+= $length;
$decoded[] = $current + array('length' => $start - $current['start']);
} }
return $decoded; // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
$length = ord($this->_string_shift($encoded));
$start++;
if ( $length == 0x80 ) { // indefinite length
// "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
// immediately available." -- paragraph 8.1.3.2.c
$length = strlen($encoded);
} elseif ( $length & 0x80 ) { // definite length, long form
// technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
// support it up to four.
$length&= 0x7F;
$temp = $this->_string_shift($encoded, $length);
// tags of indefinte length don't really have a header length; this length includes the tag
$current+= array('headerlength' => $length + 2);
$start+= $length;
extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
} else {
$current+= array('headerlength' => 2);
}
$content = $this->_string_shift($encoded, $length);
// at this point $length can be overwritten. it's only accurate for definite length things as is
/* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
built-in types. It defines an application-independent data type that must be distinguishable from all other
data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
data type; the term CONTEXT-SPECIFIC does not appear.
-- http://www.obj-sys.com/asn1tutorial/node12.html */
$class = ($type >> 6) & 3;
switch ($class) {
case FILE_ASN1_CLASS_APPLICATION:
case FILE_ASN1_CLASS_PRIVATE:
case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
if (!$constructed) {
return array(
'type' => $class,
'constant' => $tag,
'content' => $content,
'length' => $length + $start - $current['start']
);
}
$newcontent = array();
if (strlen($content)) {
$newcontent = $this->_decode_ber($content, $start);
$length = $newcontent['length'];
if (substr($content, $length, 2) == "\0\0") {
$length+= 2;
}
$start+= $length;
$newcontent = array($newcontent);
}
return array(
'type' => $class,
'constant' => $tag,
// the array encapsulation is for BC with the old format
'content' => $newcontent,
// the only time when $content['headerlength'] isn't defined is when the length is indefinite.
// the absence of $content['headerlength'] is how we know if something is indefinite or not.
// technically, it could be defined to be 2 and then another indicator could be used but whatever.
'length' => $start - $current['start']
) + $current;
}
$current+= array('type' => $tag);
// decode UNIVERSAL tags
switch ($tag) {
case FILE_ASN1_TYPE_BOOLEAN:
// "The contents octets shall consist of a single octet." -- paragraph 8.2.1
//if (strlen($content) != 1) {
// return false;
//}
$current['content'] = (bool) ord($content[0]);
break;
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
$current['content'] = new Math_BigInteger($content, -256);
break;
case FILE_ASN1_TYPE_REAL: // not currently supported
return false;
case FILE_ASN1_TYPE_BIT_STRING:
// The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
// the number of unused bits in the final subsequent octet. The number shall be in the range zero to
// seven.
if (!$constructed) {
$current['content'] = $content;
} else {
$temp = $this->_decode_ber($content, $start);
$length-= strlen($content);
$last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) {
// all subtags should be bit strings
//if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
// return false;
//}
$current['content'].= substr($temp[$i]['content'], 1);
}
// all subtags should be bit strings
//if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
// return false;
//}
$current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
}
break;
case FILE_ASN1_TYPE_OCTET_STRING:
if (!$constructed) {
$current['content'] = $content;
} else {
$current['content'] = '';
$length = 0;
while (substr($content, 0, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start);
$this->_string_shift($content, $temp['length']);
// all subtags should be octet strings
//if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
// return false;
//}
$current['content'].= $temp['content'];
$length+= $temp['length'];
}
if (substr($content, 0, 2) == "\0\0") {
$length+= 2; // +2 for the EOC
}
}
break;
case FILE_ASN1_TYPE_NULL:
// "The contents octets shall not contain any octets." -- paragraph 8.8.2
//if (strlen($content)) {
// return false;
//}
break;
case FILE_ASN1_TYPE_SEQUENCE:
case FILE_ASN1_TYPE_SET:
$offset = 0;
$current['content'] = array();
while (strlen($content)) {
// if indefinite length construction was used and we have an end-of-content string next
// see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
if (!isset($current['headerlength']) && substr($content, 0, 2) == "\0\0") {
$length = $offset + 2; // +2 for the EOC
break 2;
}
$temp = $this->_decode_ber($content, $start + $offset);
$this->_string_shift($content, $temp['length']);
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
$temp = ord($this->_string_shift($content));
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
$valuen = 0;
// process septets
while (strlen($content)) {
$temp = ord($this->_string_shift($content));
$valuen <<= 7;
$valuen |= $temp & 0x7F;
if (~$temp & 0x80) {
$current['content'].= ".$valuen";
$valuen = 0;
}
}
// the eighth bit of the last byte should not be 1
//if ($temp >> 7) {
// return false;
//}
break;
/* Each character string type shall be encoded as if it had been declared:
[UNIVERSAL x] IMPLICIT OCTET STRING
-- X.690-0207.pdf#page=23 (paragraph 8.21.3)
Per that, we're not going to do any validation. If there are any illegal characters in the string,
we don't really care */
case FILE_ASN1_TYPE_NUMERIC_STRING:
// 0,1,2,3,4,5,6,7,8,9, and space
case FILE_ASN1_TYPE_PRINTABLE_STRING:
// Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
// hyphen, full stop, solidus, colon, equal sign, question mark
case FILE_ASN1_TYPE_TELETEX_STRING:
// The Teletex character set in CCITT's T61, space, and delete
// see http://en.wikipedia.org/wiki/Teletex#Character_sets
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
// The Videotex character set in CCITT's T.100 and T.101, space, and delete
case FILE_ASN1_TYPE_VISIBLE_STRING:
// Printing character sets of international ASCII, and space
case FILE_ASN1_TYPE_IA5_STRING:
// International Alphabet 5 (International ASCII)
case FILE_ASN1_TYPE_GRAPHIC_STRING:
// All registered G sets, and space
case FILE_ASN1_TYPE_GENERAL_STRING:
// All registered C and G sets, space and delete
case FILE_ASN1_TYPE_UTF8_STRING:
// ????
case FILE_ASN1_TYPE_BMP_STRING:
$current['content'] = $content;
break;
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
$current['content'] = $this->_decodeTime($content, $tag);
default:
}
$start+= $length;
// ie. length is the length of the full TLV encoding - it's not just the length of the value
return $current + array('length' => $start - $current['start']);
} }
/** /**
* ASN.1 Decode * ASN.1 Map
* *
* Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format. * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
* *
@ -511,7 +540,7 @@ class File_ASN1
*/ */
function asn1map($decoded, $mapping, $special = array()) function asn1map($decoded, $mapping, $special = array())
{ {
if (isset($mapping['explicit'])) { if (isset($mapping['explicit']) && is_array($decoded['content'])) {
$decoded = $decoded['content'][0]; $decoded = $decoded['content'][0];
} }
@ -552,7 +581,15 @@ class File_ASN1
case $decoded['type'] == $mapping['type']: case $decoded['type'] == $mapping['type']:
break; break;
default: default:
return null; // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
// let it through
switch (true) {
case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18
case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30
case $mapping['type'] < 18:
case $mapping['type'] > 30:
return null;
}
} }
if (isset($mapping['implicit'])) { if (isset($mapping['implicit'])) {
@ -799,16 +836,6 @@ class File_ASN1
return $this->_encode_der($source, $mapping, null, $special); return $this->_encode_der($source, $mapping, null, $special);
} }
/**
* ASN.1 Encode (Helper function)
*
* @param String $source
* @param Array $mapping
* @param Integer $idx
* @param Array $special
* @return String
* @access private
*/
/** /**
* ASN.1 Encode (Helper function) * ASN.1 Encode (Helper function)
* *
@ -944,6 +971,9 @@ class File_ASN1
case FILE_ASN1_TYPE_INTEGER: case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED: case FILE_ASN1_TYPE_ENUMERATED:
if (!isset($mapping['mapping'])) { if (!isset($mapping['mapping'])) {
if (is_numeric($source)) {
$source = new Math_BigInteger($source);
}
$value = $source->toBytes(true); $value = $source->toBytes(true);
} else { } else {
$value = array_search($source, $mapping['mapping']); $value = array_search($source, $mapping['mapping']);
@ -974,6 +1004,10 @@ class File_ASN1
} }
} }
if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
$size = $mapping['min'] - 1;
}
$offset = 8 - (($size + 1) & 7); $offset = 8 - (($size + 1) & 7);
$offset = $offset !== 8 ? $offset : 0; $offset = $offset !== 8 ? $offset : 0;
@ -1087,7 +1121,12 @@ class File_ASN1
} }
if (isset($mapping['cast'])) { if (isset($mapping['cast'])) {
$tag = ($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']; if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) {
$value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
$tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
} else {
$tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
}
} }
return chr($tag) . $this->_encodeLength(strlen($value)) . $value; return chr($tag) . $this->_encodeLength(strlen($value)) . $value;

View File

@ -37,7 +37,7 @@
* @category File * @category File
* @package File_X509 * @package File_X509
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -125,7 +125,6 @@ define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value.
* *
* @package File_X509 * @package File_X509
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.1
* @access public * @access public
*/ */
class File_X509 class File_X509
@ -298,6 +297,14 @@ class File_X509
*/ */
var $caFlag = false; var $caFlag = false;
/**
* SPKAC Challenge
*
* @var String
* @access private
*/
var $challenge;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -2166,12 +2173,12 @@ class File_X509
switch ($algorithm) { switch ($algorithm) {
case 'rsaEncryption': case 'rsaEncryption':
return return
"-----BEGIN PUBLIC KEY-----\r\n" . "-----BEGIN RSA PUBLIC KEY-----\r\n" .
// subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
// in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
// uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do. // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) . chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
'-----END PUBLIC KEY-----'; '-----END RSA PUBLIC KEY-----';
default: default:
return $key; return $key;
} }
@ -2502,7 +2509,8 @@ class File_X509
$asn1->loadFilters($filters); $asn1->loadFilters($filters);
$result = ''; $result = '';
foreach ($dn['rdnSequence'] as $rdn) { foreach ($dn['rdnSequence'] as $rdn) {
foreach ($rdn as &$attr) { foreach ($rdn as $i=>$attr) {
$attr = &$rdn[$i];
if (is_array($attr['value'])) { if (is_array($attr['value'])) {
foreach ($attr['value'] as $type => $v) { foreach ($attr['value'] as $type => $v) {
$type = array_search($type, $asn1->ANYmap, true); $type = array_search($type, $asn1->ANYmap, true);
@ -2531,7 +2539,7 @@ class File_X509
return strtolower(bin2hex(pack('N', $hash))); return strtolower(bin2hex(pack('N', $hash)));
} }
// Defaut is to return a string. // Default is to return a string.
$start = true; $start = true;
$output = ''; $output = '';
$asn1 = new File_ASN1(); $asn1 = new File_ASN1();
@ -2760,6 +2768,19 @@ class File_X509
$this->privateKey = $key; $this->privateKey = $key;
} }
/**
* Set challenge
*
* Used for SPKAC CSR's
*
* @param String $challenge
* @access public
*/
function setChallenge($challenge)
{
$this->challenge = $challenge;
}
/** /**
* Gets the public key * Gets the public key
* *
@ -2953,7 +2974,8 @@ class File_X509
$asn1 = new File_ASN1(); $asn1 = new File_ASN1();
$temp = preg_replace('#(?:^[^=]+=)|[\r\n\\\]#', '', $spkac); // OpenSSL produces SPKAC's that are preceeded by the string SPKAC=
$temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
if ($temp != false) { if ($temp != false) {
$spkac = $temp; $spkac = $temp;
@ -3005,6 +3027,49 @@ class File_X509
return $spkac; return $spkac;
} }
/**
* Save a SPKAC CSR request
*
* @param Array $csr
* @param Integer $format optional
* @access public
* @return String
*/
function saveSPKAC($spkac, $format = FILE_X509_FORMAT_PEM)
{
if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
return false;
}
$algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
switch (true) {
case !$algorithm:
case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']);
break;
default:
switch ($algorithm) {
case 'rsaEncryption':
$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
}
}
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge);
switch ($format) {
case FILE_X509_FORMAT_DER:
return $spkac;
// case FILE_X509_FORMAT_PEM:
default:
// OpenSSL's implementation of SPKAC requires the SPKAC be preceeded by SPKAC= and since there are pretty much
// no other SPKAC decoders phpseclib will use that same format
return 'SPKAC=' . base64_encode($spkac);
}
}
/** /**
* Load a Certificate Revocation List * Load a Certificate Revocation List
* *
@ -3117,6 +3182,28 @@ class File_X509
} }
} }
/**
* Helper function to build a time field according to RFC 3280 section
* - 4.1.2.5 Validity
* - 5.1.2.4 This Update
* - 5.1.2.5 Next Update
* - 5.1.2.6 Revoked Certificates
* by choosing utcTime iff year of date given is before 2050 and generalTime else.
*
* @param String $date in format date('D, d M Y H:i:s O')
* @access private
* @return Array
*/
function _timeField($date)
{
$year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
if ($year < 2050) {
return array('utcTime' => $date);
} else {
return array('generalTime' => $date);
}
}
/** /**
* Sign an X.509 certificate * Sign an X.509 certificate
* *
@ -3149,12 +3236,10 @@ class File_X509
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
if (!empty($this->startDate)) { if (!empty($this->startDate)) {
$this->currentCert['tbsCertificate']['validity']['notBefore']['generalTime'] = $this->startDate; $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
unset($this->currentCert['tbsCertificate']['validity']['notBefore']['utcTime']);
} }
if (!empty($this->endDate)) { if (!empty($this->endDate)) {
$this->currentCert['tbsCertificate']['validity']['notAfter']['generalTime'] = $this->endDate; $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
unset($this->currentCert['tbsCertificate']['validity']['notAfter']['utcTime']);
} }
if (!empty($this->serialNumber)) { if (!empty($this->serialNumber)) {
$this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber; $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
@ -3176,8 +3261,8 @@ class File_X509
return false; return false;
} }
$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(); $serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new Math_BigInteger();
$this->currentCert = array( $this->currentCert = array(
@ -3188,8 +3273,8 @@ class File_X509
'signature' => array('algorithm' => $signatureAlgorithm), 'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, // this is going to be overwritten later 'issuer' => false, // this is going to be overwritten later
'validity' => array( 'validity' => array(
'notBefore' => array('generalTime' => $startDate), // $this->setStartDate() 'notBefore' => $this->_timeField($startDate), // $this->setStartDate()
'notAfter' => array('generalTime' => $endDate) // $this->setEndDate() 'notAfter' => $this->_timeField($endDate) // $this->setEndDate()
), ),
'subject' => $subject->dn, 'subject' => $subject->dn,
'subjectPublicKeyInfo' => $subjectPublicKey 'subjectPublicKeyInfo' => $subjectPublicKey
@ -3349,6 +3434,71 @@ class File_X509
return $result; return $result;
} }
/**
* Sign a SPKAC
*
* @access public
* @return Mixed
*/
function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($this->privateKey)) {
return false;
}
$origPublicKey = $this->publicKey;
$class = get_class($this->privateKey);
$this->publicKey = new $class();
$this->publicKey->loadKey($this->privateKey->getPublicKey());
$this->publicKey->setPublicKey();
$publicKey = $this->_formatSubjectPublicKey();
if (!$publicKey) {
return false;
}
$this->publicKey = $origPublicKey;
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
// re-signing a SPKAC seems silly but since everything else supports re-signing why not?
if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
$this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
if (!empty($this->challenge)) {
// the bitwise AND ensures that the output is a valid IA5String
$this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
}
} else {
$this->currentCert = array(
'publicKeyAndChallenge' =>
array(
'spki' => $publicKey,
// quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>,
// "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified."
// both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way
// we could alternatively do this instead if we ignored the specs:
// crypt_random_string(8) & str_repeat("\x7F", 8)
'challenge' => !empty($this->challenge) ? $this->challenge : ''
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false // this is going to be overwritten later
);
}
// resync $this->signatureSubject
// save $publicKeyAndChallenge in case there are any File_ASN1_Element objects in it
$publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
$this->loadSPKAC($this->saveSPKAC($this->currentCert));
$result = $this->_sign($this->privateKey, $signatureAlgorithm);
$result['publicKeyAndChallenge'] = $publicKeyAndChallenge;
$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;
return $result;
}
/** /**
* Sign a CRL * Sign a CRL
* *
@ -3368,7 +3518,7 @@ class File_X509
$currentCert = isset($this->currentCert) ? $this->currentCert : null; $currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
$thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M y H:i:s O'); $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) { if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
$this->currentCert = $crl->currentCert; $this->currentCert = $crl->currentCert;
@ -3381,7 +3531,7 @@ class File_X509
'version' => 'v2', 'version' => 'v2',
'signature' => array('algorithm' => $signatureAlgorithm), 'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, // this is going to be overwritten later 'issuer' => false, // this is going to be overwritten later
'thisUpdate' => array('generalTime' => $thisUpdate) // $this->setStartDate() 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate()
), ),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false // this is going to be overwritten later 'signature' => false // this is going to be overwritten later
@ -3390,10 +3540,10 @@ class File_X509
$tbsCertList = &$this->currentCert['tbsCertList']; $tbsCertList = &$this->currentCert['tbsCertList'];
$tbsCertList['issuer'] = $issuer->dn; $tbsCertList['issuer'] = $issuer->dn;
$tbsCertList['thisUpdate'] = array('generalTime' => $thisUpdate); $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);
if (!empty($this->endDate)) { if (!empty($this->endDate)) {
$tbsCertList['nextUpdate'] = array('generalTime' => $this->endDate); // $this->setEndDate() $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate()
} else { } else {
unset($tbsCertList['nextUpdate']); unset($tbsCertList['nextUpdate']);
} }
@ -3516,7 +3666,7 @@ class File_X509
*/ */
function setStartDate($date) function setStartDate($date)
{ {
$this->startDate = @date('D, d M y H:i:s O', @strtotime($date)); $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
} }
/** /**
@ -3540,7 +3690,7 @@ class File_X509
$temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp; $temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
$this->endDate = new File_ASN1_Element($temp); $this->endDate = new File_ASN1_Element($temp);
} else { } else {
$this->endDate = @date('D, d M y H:i:s O', @strtotime($date)); $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
} }
} }
@ -4085,7 +4235,7 @@ class File_X509
} }
return false; return false;
default: // Should be a key object (i.e.: Crypt_RSA). default: // Should be a key object (i.e.: Crypt_RSA).
$key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW); $key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
break; break;
} }
@ -4126,7 +4276,7 @@ class File_X509
//return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey()))); //return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
return array( return array(
'algorithm' => array('algorithm' => 'rsaEncryption'), 'algorithm' => array('algorithm' => 'rsaEncryption'),
'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) 'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
); );
default: default:
return false; return false;
@ -4214,7 +4364,7 @@ class File_X509
$i = count($rclist); $i = count($rclist);
$rclist[] = array('userCertificate' => $serial, $rclist[] = array('userCertificate' => $serial,
'revocationDate' => array('generalTime' => @date('D, d M y H:i:s O'))); 'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O')));
return $i; return $i;
} }
@ -4234,7 +4384,7 @@ class File_X509
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'] = array('generalTime' => $date); $rclist[$i]['revocationDate'] = $this->_timeField($date);
} }
return true; return true;

View File

@ -19,10 +19,6 @@
* which only supports integers. Although this fact will slow this library down, the fact that such a high * which only supports integers. Although this fact will slow this library down, the fact that such a high
* base is being used should more than compensate. * base is being used should more than compensate.
* *
* When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again,
* allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
* subtraction).
*
* Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie. * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
* (new Math_BigInteger(pow(2, 26)))->value = array(0, 1) * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
* *
@ -35,7 +31,7 @@
* Here's an example of how to use this library: * Here's an example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger(2); * $a = new Math_BigInteger(2);
* $b = new Math_BigInteger(3); * $b = new Math_BigInteger(3);
@ -67,7 +63,7 @@
* @category Math * @category Math
* @package Math_BigInteger * @package Math_BigInteger
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVI Jim Wigginton * @copyright 2006 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger * @link http://pear.php.net/package/Math_BigInteger
*/ */
@ -175,7 +171,6 @@ define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
* *
* @package Math_BigInteger * @package Math_BigInteger
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 1.0.0RC4
* @access public * @access public
*/ */
class Math_BigInteger class Math_BigInteger
@ -242,13 +237,13 @@ class Math_BigInteger
* *
* Here's an example: * Here's an example:
* <code> * <code>
* &lt;?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('0x32', 16); // 50 in base-16 * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
* *
* echo $a->toString(); // outputs 50 * echo $a->toString(); // outputs 50
* ?&gt; * ?>
* </code> * </code>
* *
* @param optional $x base-10 number or base-$base number if $base set. * @param optional $x base-10 number or base-$base number if $base set.
@ -274,7 +269,7 @@ class Math_BigInteger
if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start(); ob_start();
phpinfo(); @phpinfo();
$content = ob_get_contents(); $content = ob_get_contents();
ob_end_clean(); ob_end_clean();
@ -283,7 +278,14 @@ class Math_BigInteger
$versions = array(); $versions = array();
if (!empty($matches[1])) { if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) { for ($i = 0; $i < count($matches[1]); $i++) {
$versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
} }
} }
@ -334,9 +336,12 @@ class Math_BigInteger
switch ( MATH_BIGINTEGER_MODE ) { switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP: case MATH_BIGINTEGER_MODE_GMP:
if (is_resource($x) && get_resource_type($x) == 'GMP integer') { switch (true) {
$this->value = $x; case is_resource($x) && get_resource_type($x) == 'GMP integer':
return; // PHP 5.6 switched GMP from using resources to objects
case is_object($x) && get_class($x) == 'GMP':
$this->value = $x;
return;
} }
$this->value = gmp_init(0); $this->value = gmp_init(0);
break; break;
@ -511,7 +516,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('65'); * $a = new Math_BigInteger('65');
* *
@ -608,7 +613,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('65'); * $a = new Math_BigInteger('65');
* *
@ -635,7 +640,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('65'); * $a = new Math_BigInteger('65');
* *
@ -673,7 +678,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('50'); * $a = new Math_BigInteger('50');
* *
@ -826,7 +831,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('10'); * $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20'); * $b = new Math_BigInteger('20');
@ -917,7 +922,7 @@ class Math_BigInteger
$value = $x_value; $value = $x_value;
} }
$value[] = 0; // just in case the carry adds an extra digit $value[count($value)] = 0; // just in case the carry adds an extra digit
$carry = 0; $carry = 0;
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
@ -925,7 +930,7 @@ class Math_BigInteger
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum; $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
$value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
$value[$j] = $temp; $value[$j] = $temp;
@ -957,7 +962,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('10'); * $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20'); * $b = new Math_BigInteger('20');
@ -1061,7 +1066,7 @@ class Math_BigInteger
$carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum; $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL); $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
$x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
$x_value[$j] = $temp; $x_value[$j] = $temp;
@ -1093,7 +1098,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('10'); * $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20'); * $b = new Math_BigInteger('20');
@ -1209,7 +1214,7 @@ class Math_BigInteger
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
@ -1222,7 +1227,7 @@ class Math_BigInteger
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
@ -1310,13 +1315,13 @@ class Math_BigInteger
$i2 = $i << 1; $i2 = $i << 1;
$temp = $square_value[$i2] + $value[$i] * $value[$i]; $temp = $square_value[$i2] + $value[$i] * $value[$i];
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
// note how we start from $i+1 instead of 0 as we do in multiplication. // note how we start from $i+1 instead of 0 as we do in multiplication.
for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
@ -1377,7 +1382,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('10'); * $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20'); * $b = new Math_BigInteger('20');
@ -1514,9 +1519,8 @@ class Math_BigInteger
if ($x_window[0] == $y_window[0]) { if ($x_window[0] == $y_window[0]) {
$quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT; $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
} else { } else {
$quotient_value[$q_index] = (int) ( $quotient_value[$q_index] = $this->_safe_divide(
($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1]) $x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1],
/
$y_window[0] $y_window[0]
); );
} }
@ -1584,7 +1588,7 @@ class Math_BigInteger
for ($i = count($dividend) - 1; $i >= 0; --$i) { for ($i = count($dividend) - 1; $i >= 0; --$i) {
$temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i]; $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
$result[$i] = (int) ($temp / $divisor); $result[$i] = $this->_safe_divide($temp, $divisor);
$carry = (int) ($temp - $divisor * $result[$i]); $carry = (int) ($temp - $divisor * $result[$i]);
} }
@ -1597,7 +1601,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger('10'); * $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20'); * $b = new Math_BigInteger('20');
@ -1722,6 +1726,11 @@ class Math_BigInteger
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
// the following code, although not callable, can be run independently of the above code
// although the above code performed better in my benchmarks the following could might
// perform better under different circumstances. in lieu of deleting it it's just been
// made uncallable
// is the modulo odd? // is the modulo odd?
if ( $n->value[0] & 1 ) { if ( $n->value[0] & 1 ) {
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
@ -2135,7 +2144,7 @@ class Math_BigInteger
if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
$corrector_value = $this->_array_repeat(0, $n_length + 1); $corrector_value = $this->_array_repeat(0, $n_length + 1);
$corrector_value[] = 1; $corrector_value[count($corrector_value)] = 1;
$result = $this->_add($result, false, $corrector_value, false); $result = $this->_add($result, false, $corrector_value, false);
$result = $result[MATH_BIGINTEGER_VALUE]; $result = $result[MATH_BIGINTEGER_VALUE];
} }
@ -2196,7 +2205,7 @@ class Math_BigInteger
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
@ -2212,7 +2221,7 @@ class Math_BigInteger
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry); $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
} }
@ -2261,7 +2270,7 @@ class Math_BigInteger
for ($i = 0; $i < $k; ++$i) { for ($i = 0; $i < $k; ++$i) {
$temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $this->_regularMultiply(array($temp), $n); $temp = $this->_regularMultiply(array($temp), $n);
$temp = array_merge($this->_array_repeat(0, $i), $temp); $temp = array_merge($this->_array_repeat(0, $i), $temp);
$result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
@ -2295,6 +2304,11 @@ class Math_BigInteger
$temp = $this->_multiply($x, false, $y, false); $temp = $this->_multiply($x, false, $y, false);
return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
// the following code, although not callable, can be run independently of the above code
// although the above code performed better in my benchmarks the following could might
// perform better under different circumstances. in lieu of deleting it it's just been
// made uncallable
static $cache = array( static $cache = array(
MATH_BIGINTEGER_VARIABLE => array(), MATH_BIGINTEGER_VARIABLE => array(),
MATH_BIGINTEGER_DATA => array() MATH_BIGINTEGER_DATA => array()
@ -2313,9 +2327,9 @@ class Math_BigInteger
$a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
for ($i = 0; $i < $n; ++$i) { for ($i = 0; $i < $n; ++$i) {
$temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL))); $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
$a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
$a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
@ -2392,7 +2406,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger(30); * $a = new Math_BigInteger(30);
* $b = new Math_BigInteger(17); * $b = new Math_BigInteger(17);
@ -2460,7 +2474,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger(693); * $a = new Math_BigInteger(693);
* $b = new Math_BigInteger(609); * $b = new Math_BigInteger(609);
@ -2595,7 +2609,7 @@ class Math_BigInteger
* Here's an example: * Here's an example:
* <code> * <code>
* <?php * <?php
* include('Math/BigInteger.php'); * include 'Math/BigInteger.php';
* *
* $a = new Math_BigInteger(693); * $a = new Math_BigInteger(693);
* $b = new Math_BigInteger(609); * $b = new Math_BigInteger(609);
@ -2900,7 +2914,7 @@ class Math_BigInteger
$leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3); $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
$this->_base256_lshift($leading_ones, $current_bits); $this->_base256_lshift($leading_ones, $current_bits);
$temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT); $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
} }
@ -3062,8 +3076,7 @@ class Math_BigInteger
*/ */
function _random_number_helper($size) function _random_number_helper($size)
{ {
$crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string')); if (function_exists('crypt_random_string')) {
if ($crypt_random) {
$random = crypt_random_string($size); $random = crypt_random_string($size);
} else { } else {
$random = ''; $random = '';
@ -3085,19 +3098,31 @@ class Math_BigInteger
/** /**
* Generate a random number * Generate a random number
* *
* @param optional Integer $min * Returns a random number between $min and $max where $min and $max
* @param optional Integer $max * can be defined using one of the two methods:
*
* $min->random($max)
* $max->random($min)
*
* @param Math_BigInteger $arg1
* @param optional Math_BigInteger $arg2
* @return Math_BigInteger * @return Math_BigInteger
* @access public * @access public
* @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a Math_BigInteger object.
* That method is still supported for BC purposes.
*/ */
function random($min = false, $max = false) function random($arg1, $arg2 = false)
{ {
if ($min === false) { if ($arg1 === false) {
$min = new Math_BigInteger(0); return false;
} }
if ($max === false) { if ($arg2 === false) {
$max = new Math_BigInteger(0x7FFFFFFF); $max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
} }
$compare = $max->compare($min); $compare = $max->compare($min);
@ -3160,21 +3185,25 @@ class Math_BigInteger
* If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed, * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed,
* give up and return false. * give up and return false.
* *
* @param optional Integer $min * @param Math_BigInteger $arg1
* @param optional Integer $max * @param optional Math_BigInteger $arg2
* @param optional Integer $timeout * @param optional Integer $timeout
* @return Math_BigInteger * @return Mixed
* @access public * @access public
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}. * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
*/ */
function randomPrime($min = false, $max = false, $timeout = false) function randomPrime($arg1, $arg2 = false, $timeout = false)
{ {
if ($min === false) { if ($arg1 === false) {
$min = new Math_BigInteger(0); return false;
} }
if ($max === false) { if ($arg2 === false) {
$max = new Math_BigInteger(0x7FFFFFFF); $max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
} }
$compare = $max->compare($min); $compare = $max->compare($min);
@ -3283,10 +3312,10 @@ class Math_BigInteger
* Checks a numer to see if it's prime * Checks a numer to see if it's prime
* *
* Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
* $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed across multiple pageloads
* on a website instead of just one. * on a website instead of just one.
* *
* @param optional Integer $t * @param optional Math_BigInteger $t
* @return Boolean * @return Boolean
* @access public * @access public
* @internal Uses the * @internal Uses the
@ -3455,12 +3484,12 @@ class Math_BigInteger
for ($i = 0; $i < count($this->value); ++$i) { for ($i = 0; $i < count($this->value); ++$i) {
$temp = $this->value[$i] * $shift + $carry; $temp = $this->value[$i] * $shift + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL); $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL); $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
} }
if ( $carry ) { if ( $carry ) {
$this->value[] = $carry; $this->value[count($this->value)] = $carry;
} }
while ($num_digits--) { while ($num_digits--) {
@ -3703,4 +3732,27 @@ class Math_BigInteger
$temp = ltrim(pack('N', $length), chr(0)); $temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp); return pack('Ca*', 0x80 | strlen($temp), $temp);
} }
/**
* Single digit division
*
* Even if int64 is being used the division operator will return a float64 value
* if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
* have the precision of int64 this is a problem so, when int64 is being used,
* we'll guarantee that the dividend is divisible by first subtracting the remainder.
*
* @access private
* @param Integer $x
* @param Integer $y
* @return Integer
*/
function _safe_divide($x, $y)
{
if (MATH_BIGINTEGER_BASE === 26) {
return (int) ($x / $y);
}
// MATH_BIGINTEGER_BASE === 31
return ($x - ($x % $y)) / $y;
}
} }

View File

@ -10,8 +10,8 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Net/SCP.php'); * include 'Net/SCP.php';
* include('Net/SSH2.php'); * include 'Net/SSH2.php';
* *
* $ssh = new Net_SSH2('www.domain.tld'); * $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', 'password')) { * if (!$ssh->login('username', 'password')) {
@ -44,7 +44,7 @@
* @category Net * @category Net
* @package Net_SCP * @package Net_SCP
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMX Jim Wigginton * @copyright 2010 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -83,7 +83,6 @@ define('NET_SCP_SSH2', 2);
* *
* @package Net_SCP * @package Net_SCP
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Net_SCP class Net_SCP
@ -130,7 +129,7 @@ class Net_SCP
} }
switch (strtolower(get_class($ssh))) { switch (strtolower(get_class($ssh))) {
case'net_ssh2': case 'net_ssh2':
$this->mode = NET_SCP_SSH2; $this->mode = NET_SCP_SSH2;
break; break;
case 'net_ssh1': case 'net_ssh1':
@ -171,7 +170,7 @@ class Net_SCP
return false; return false;
} }
if (!$this->ssh->exec('scp -t ' . $remote_file, false)) { // -t = to if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
return false; return false;
} }
@ -196,7 +195,6 @@ class Net_SCP
$fp = @fopen($data, 'rb'); $fp = @fopen($data, 'rb');
if (!$fp) { if (!$fp) {
fclose($fp);
return false; return false;
} }
$size = filesize($data); $size = filesize($data);
@ -216,7 +214,7 @@ class Net_SCP
$sent+= strlen($temp); $sent+= strlen($temp);
if (is_callable($callback)) { if (is_callable($callback)) {
$callback($sent); call_user_func($callback, $sent);
} }
} }
$this->_close(); $this->_close();
@ -246,7 +244,7 @@ class Net_SCP
return false; return false;
} }
if (!$this->ssh->exec('scp -f ' . $remote_file, false)) { // -f = from if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
return false; return false;
} }

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@
* @category Net * @category Net
* @package Net_SFTP_Stream * @package Net_SFTP_Stream
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXIII Jim Wigginton * @copyright 2013 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -38,7 +38,6 @@
* *
* @package Net_SFTP_Stream * @package Net_SFTP_Stream
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.2
* @access public * @access public
*/ */
class Net_SFTP_Stream class Net_SFTP_Stream
@ -49,7 +48,6 @@ class Net_SFTP_Stream
* Rather than re-create the connection we re-use instances if possible * Rather than re-create the connection we re-use instances if possible
* *
* @var Array * @var Array
* @access static
*/ */
static $instances; static $instances;
@ -127,6 +125,22 @@ class Net_SFTP_Stream
*/ */
var $notification; var $notification;
/**
* Registers this class as a URL wrapper.
*
* @param optional String $protocol The wrapper name to be registered.
* @return Boolean True on success, false otherwise.
* @access public
*/
static function register($protocol = 'sftp')
{
if (in_array($protocol, stream_get_wrappers(), true)) {
return false;
}
$class = function_exists('get_called_class') ? get_called_class() : __CLASS__;
return stream_wrapper_register($protocol, $class);
}
/** /**
* The Constructor * The Constructor
* *
@ -181,24 +195,24 @@ class Net_SFTP_Stream
if (isset($this->context)) { if (isset($this->context)) {
$context = stream_context_get_options($this->context); $context = stream_context_get_options($this->context);
} }
if (isset($context['sftp']['session'])) { if (isset($context[$scheme]['session'])) {
$sftp = $context['sftp']['session']; $sftp = $context[$scheme]['session'];
} }
if (isset($context['sftp']['sftp'])) { if (isset($context[$scheme]['sftp'])) {
$sftp = $context['sftp']['sftp']; $sftp = $context[$scheme]['sftp'];
} }
if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') { if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') {
$this->sftp = $sftp; $this->sftp = $sftp;
return $path; return $path;
} }
if (isset($context['sftp']['username'])) { if (isset($context[$scheme]['username'])) {
$user = $context['sftp']['username']; $user = $context[$scheme]['username'];
} }
if (isset($context['sftp']['password'])) { if (isset($context[$scheme]['password'])) {
$pass = $context['sftp']['password']; $pass = $context[$scheme]['password'];
} }
if (isset($context['sftp']['privkey']) && is_object($context['sftp']['privkey']) && get_Class($context['sftp']['privkey']) == 'Crypt_RSA') { if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') {
$pass = $context['sftp']['privkey']; $pass = $context[$scheme]['privkey'];
} }
if (!isset($user) || !isset($pass)) { if (!isset($user) || !isset($pass)) {
@ -210,6 +224,7 @@ class Net_SFTP_Stream
$this->sftp = self::$instances[$host][$port][$user][(string) $pass]; $this->sftp = self::$instances[$host][$port][$user][(string) $pass];
} else { } else {
$this->sftp = new Net_SFTP($host, $port); $this->sftp = new Net_SFTP($host, $port);
$this->sftp->disableStatCache();
if (isset($this->notification) && is_callable($this->notification)) { if (isset($this->notification) && is_callable($this->notification)) {
/* if !is_callable($this->notification) we could do this: /* if !is_callable($this->notification) we could do this:
@ -517,7 +532,20 @@ class Net_SFTP_Stream
* Open directory handle * Open directory handle
* *
* The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and
* removed in 5.4 I'm just going to ignore it * removed in 5.4 I'm just going to ignore it.
*
* Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client
* sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting
* the SFTP specs:
*
* The SSH_FXP_NAME response has the following format:
*
* uint32 id
* uint32 count
* repeats count times:
* string filename
* string longname
* ATTRS attrs
* *
* @param String $path * @param String $path
* @param Integer $options * @param Integer $options
@ -770,6 +798,4 @@ class Net_SFTP_Stream
} }
} }
if (function_exists('stream_wrapper_register')) { Net_SFTP_Stream::register();
stream_wrapper_register('sftp', 'Net_SFTP_Stream');
}

View File

@ -8,7 +8,7 @@
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Net/SSH1.php'); * include 'Net/SSH1.php';
* *
* $ssh = new Net_SSH1('www.domain.tld'); * $ssh = new Net_SSH1('www.domain.tld');
* if (!$ssh->login('username', 'password')) { * if (!$ssh->login('username', 'password')) {
@ -22,7 +22,7 @@
* Here's another short example: * Here's another short example:
* <code> * <code>
* <?php * <?php
* include('Net/SSH1.php'); * include 'Net/SSH1.php';
* *
* $ssh = new Net_SSH1('www.domain.tld'); * $ssh = new Net_SSH1('www.domain.tld');
* if (!$ssh->login('username', 'password')) { * if (!$ssh->login('username', 'password')) {
@ -59,7 +59,7 @@
* @category Net * @category Net
* @package Net_SSH1 * @package Net_SSH1
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -182,8 +182,9 @@ define('NET_SSH1_RESPONSE_DATA', 2);
* @access private * @access private
*/ */
define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001); define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
define('NET_SSH1_MASK_LOGIN', 0x00000002); define('NET_SSH1_MASK_CONNECTED', 0x00000002);
define('NET_SSH1_MASK_SHELL', 0x00000004); define('NET_SSH1_MASK_LOGIN', 0x00000004);
define('NET_SSH1_MASK_SHELL', 0x00000008);
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -227,7 +228,6 @@ define('NET_SSH1_READ_REGEX', 2);
* *
* @package Net_SSH1 * @package Net_SSH1
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Net_SSH1 class Net_SSH1
@ -458,6 +458,51 @@ class Net_SSH1
*/ */
var $log_short_width = 16; var $log_short_width = 16;
/**
* Hostname
*
* @see Net_SSH1::Net_SSH1()
* @see Net_SSH1::_connect()
* @var String
* @access private
*/
var $host;
/**
* Port Number
*
* @see Net_SSH1::Net_SSH1()
* @see Net_SSH1::_connect()
* @var Integer
* @access private
*/
var $port;
/**
* Timeout for initial connection
*
* Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
* exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
* however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
* 10 seconds. It is used by fsockopen() in that function.
*
* @see Net_SSH1::Net_SSH1()
* @see Net_SSH1::_connect()
* @var Integer
* @access private
*/
var $connectionTimeout;
/**
* Default cipher
*
* @see Net_SSH1::Net_SSH1()
* @see Net_SSH1::_connect()
* @var Integer
* @access private
*/
var $cipher;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -506,10 +551,24 @@ class Net_SSH1
$this->_define_array($this->protocol_flags); $this->_define_array($this->protocol_flags);
$this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); $this->host = $host;
$this->port = $port;
$this->connectionTimeout = $timeout;
$this->cipher = $cipher;
}
/**
* Connect to an SSHv1 server
*
* @return Boolean
* @access private
*/
function _connect()
{
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
if (!$this->fsock) { if (!$this->fsock) {
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
return; return false;
} }
$this->server_identification = $init_line = fgets($this->fsock, 255); $this->server_identification = $init_line = fgets($this->fsock, 255);
@ -521,11 +580,11 @@ class Net_SSH1
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) { if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
user_error('Can only connect to SSH servers'); user_error('Can only connect to SSH servers');
return; return false;
} }
if ($parts[1][0] != 1) { if ($parts[1][0] != 1) {
user_error("Cannot connect to SSH $parts[1] servers"); user_error("Cannot connect to SSH $parts[1] servers");
return; return false;
} }
fputs($this->fsock, $this->identifier."\r\n"); fputs($this->fsock, $this->identifier."\r\n");
@ -533,7 +592,7 @@ class Net_SSH1
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) { if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
user_error('Expected SSH_SMSG_PUBLIC_KEY'); user_error('Expected SSH_SMSG_PUBLIC_KEY');
return; return false;
} }
$anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8); $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
@ -613,12 +672,12 @@ class Net_SSH1
); );
} }
$cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : NET_SSH1_CIPHER_3DES; $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : NET_SSH1_CIPHER_3DES;
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0); $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_SESSION_KEY'); user_error('Error sending SSH_CMSG_SESSION_KEY');
return; return false;
} }
switch ($cipher) { switch ($cipher) {
@ -645,7 +704,7 @@ class Net_SSH1
break; break;
//case NET_SSH1_CIPHER_RC4: //case NET_SSH1_CIPHER_RC4:
// if (!class_exists('Crypt_RC4')) { // if (!class_exists('Crypt_RC4')) {
// include_once('Crypt/RC4.php'); // include_once 'Crypt/RC4.php';
// } // }
// $this->crypto = new Crypt_RC4(); // $this->crypto = new Crypt_RC4();
// $this->crypto->enableContinuousBuffer(); // $this->crypto->enableContinuousBuffer();
@ -657,10 +716,12 @@ class Net_SSH1
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS'); user_error('Expected SSH_SMSG_SUCCESS');
return; return false;
} }
$this->bitmap = NET_SSH1_MASK_CONSTRUCTOR; $this->bitmap = NET_SSH1_MASK_CONNECTED;
return true;
} }
/** /**
@ -674,6 +735,13 @@ class Net_SSH1
function login($username, $password = '') function login($username, $password = '')
{ {
if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) { if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
$this->bitmap |= NET_SSH1_MASK_CONSTRUCTOR;
if (!$this->_connect()) {
return false;
}
}
if (!($this->bitmap & NET_SSH1_MASK_CONNECTED)) {
return false; return false;
} }
@ -1060,6 +1128,7 @@ class Net_SSH1
$padding_length = 8 - ($temp['length'] & 7); $padding_length = 8 - ($temp['length'] & 7);
$length = $temp['length'] + $padding_length; $length = $temp['length'] + $padding_length;
$raw = '';
while ($length > 0) { while ($length > 0) {
$temp = fread($this->fsock, $length); $temp = fread($this->fsock, $length);

View File

@ -8,7 +8,7 @@
* Here are some examples of how to use this library: * Here are some examples of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Net/SSH2.php'); * include 'Net/SSH2.php';
* *
* $ssh = new Net_SSH2('www.domain.tld'); * $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', 'password')) { * if (!$ssh->login('username', 'password')) {
@ -22,8 +22,8 @@
* *
* <code> * <code>
* <?php * <?php
* include('Crypt/RSA.php'); * include 'Crypt/RSA.php';
* include('Net/SSH2.php'); * include 'Net/SSH2.php';
* *
* $key = new Crypt_RSA(); * $key = new Crypt_RSA();
* //$key->setPassword('whatever'); * //$key->setPassword('whatever');
@ -61,7 +61,7 @@
* @category Net * @category Net
* @package Net_SSH2 * @package Net_SSH2
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -73,10 +73,11 @@
* @access private * @access private
*/ */
define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
define('NET_SSH2_MASK_LOGIN_REQ', 0x00000002); define('NET_SSH2_MASK_CONNECTED', 0x00000002);
define('NET_SSH2_MASK_LOGIN', 0x00000004); define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004);
define('NET_SSH2_MASK_SHELL', 0x00000008); define('NET_SSH2_MASK_LOGIN', 0x00000008);
define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000010); define('NET_SSH2_MASK_SHELL', 0x00000010);
define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020);
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -145,7 +146,6 @@ define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024);
* *
* @package Net_SSH2 * @package Net_SSH2
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public * @access public
*/ */
class Net_SSH2 class Net_SSH2
@ -191,100 +191,100 @@ class Net_SSH2
* Server Identifier * Server Identifier
* *
* @see Net_SSH2::getServerIdentification() * @see Net_SSH2::getServerIdentification()
* @var String * @var mixed false or Array
* @access private * @access private
*/ */
var $server_identifier = ''; var $server_identifier = false;
/** /**
* Key Exchange Algorithms * Key Exchange Algorithms
* *
* @see Net_SSH2::getKexAlgorithims() * @see Net_SSH2::getKexAlgorithims()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $kex_algorithms; var $kex_algorithms = false;
/** /**
* Server Host Key Algorithms * Server Host Key Algorithms
* *
* @see Net_SSH2::getServerHostKeyAlgorithms() * @see Net_SSH2::getServerHostKeyAlgorithms()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $server_host_key_algorithms; var $server_host_key_algorithms = false;
/** /**
* Encryption Algorithms: Client to Server * Encryption Algorithms: Client to Server
* *
* @see Net_SSH2::getEncryptionAlgorithmsClient2Server() * @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $encryption_algorithms_client_to_server; var $encryption_algorithms_client_to_server = false;
/** /**
* Encryption Algorithms: Server to Client * Encryption Algorithms: Server to Client
* *
* @see Net_SSH2::getEncryptionAlgorithmsServer2Client() * @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $encryption_algorithms_server_to_client; var $encryption_algorithms_server_to_client = false;
/** /**
* MAC Algorithms: Client to Server * MAC Algorithms: Client to Server
* *
* @see Net_SSH2::getMACAlgorithmsClient2Server() * @see Net_SSH2::getMACAlgorithmsClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $mac_algorithms_client_to_server; var $mac_algorithms_client_to_server = false;
/** /**
* MAC Algorithms: Server to Client * MAC Algorithms: Server to Client
* *
* @see Net_SSH2::getMACAlgorithmsServer2Client() * @see Net_SSH2::getMACAlgorithmsServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $mac_algorithms_server_to_client; var $mac_algorithms_server_to_client = false;
/** /**
* Compression Algorithms: Client to Server * Compression Algorithms: Client to Server
* *
* @see Net_SSH2::getCompressionAlgorithmsClient2Server() * @see Net_SSH2::getCompressionAlgorithmsClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $compression_algorithms_client_to_server; var $compression_algorithms_client_to_server = false;
/** /**
* Compression Algorithms: Server to Client * Compression Algorithms: Server to Client
* *
* @see Net_SSH2::getCompressionAlgorithmsServer2Client() * @see Net_SSH2::getCompressionAlgorithmsServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $compression_algorithms_server_to_client; var $compression_algorithms_server_to_client = false;
/** /**
* Languages: Server to Client * Languages: Server to Client
* *
* @see Net_SSH2::getLanguagesServer2Client() * @see Net_SSH2::getLanguagesServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $languages_server_to_client; var $languages_server_to_client = false;
/** /**
* Languages: Client to Server * Languages: Client to Server
* *
* @see Net_SSH2::getLanguagesClient2Server() * @see Net_SSH2::getLanguagesClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $languages_client_to_server; var $languages_client_to_server = false;
/** /**
* Block Size for Server to Client Encryption * Block Size for Server to Client Encryption
@ -670,6 +670,7 @@ class Net_SSH2
/** /**
* Time of first network activity * Time of first network activity
* *
* @var Integer
* @access private * @access private
*/ */
var $last_packet; var $last_packet;
@ -685,6 +686,7 @@ class Net_SSH2
/** /**
* Flag to request a PTY when using exec() * Flag to request a PTY when using exec()
* *
* @var Boolean
* @see Net_SSH2::enablePTY() * @see Net_SSH2::enablePTY()
* @access private * @access private
*/ */
@ -693,6 +695,7 @@ class Net_SSH2
/** /**
* Flag set while exec() is running when using enablePTY() * Flag set while exec() is running when using enablePTY()
* *
* @var Boolean
* @access private * @access private
*/ */
var $in_request_pty_exec = false; var $in_request_pty_exec = false;
@ -700,6 +703,7 @@ class Net_SSH2
/** /**
* Flag set after startSubsystem() is called * Flag set after startSubsystem() is called
* *
* @var Boolean
* @access private * @access private
*/ */
var $in_subsystem; var $in_subsystem;
@ -707,6 +711,7 @@ class Net_SSH2
/** /**
* Contents of stdError * Contents of stdError
* *
* @var String
* @access private * @access private
*/ */
var $stdErrorLog; var $stdErrorLog;
@ -715,6 +720,7 @@ class Net_SSH2
* The Last Interactive Response * The Last Interactive Response
* *
* @see Net_SSH2::_keyboard_interactive_process() * @see Net_SSH2::_keyboard_interactive_process()
* @var String
* @access private * @access private
*/ */
var $last_interactive_response = ''; var $last_interactive_response = '';
@ -723,6 +729,7 @@ class Net_SSH2
* Keyboard Interactive Request / Responses * Keyboard Interactive Request / Responses
* *
* @see Net_SSH2::_keyboard_interactive_process() * @see Net_SSH2::_keyboard_interactive_process()
* @var Array
* @access private * @access private
*/ */
var $keyboard_requests_responses = array(); var $keyboard_requests_responses = array();
@ -735,6 +742,7 @@ class Net_SSH2
* *
* @see Net_SSH2::_filter() * @see Net_SSH2::_filter()
* @see Net_SSH2::getBannerMessage() * @see Net_SSH2::getBannerMessage()
* @var String
* @access private * @access private
*/ */
var $banner_message = ''; var $banner_message = '';
@ -742,7 +750,8 @@ class Net_SSH2
/** /**
* Did read() timeout or return normally? * Did read() timeout or return normally?
* *
* @see Net_SSH2::isTimeout * @see Net_SSH2::isTimeout()
* @var Boolean
* @access private * @access private
*/ */
var $is_timeout = false; var $is_timeout = false;
@ -750,7 +759,8 @@ class Net_SSH2
/** /**
* Log Boundary * Log Boundary
* *
* @see Net_SSH2::_format_log * @see Net_SSH2::_format_log()
* @var String
* @access private * @access private
*/ */
var $log_boundary = ':'; var $log_boundary = ':';
@ -758,7 +768,8 @@ class Net_SSH2
/** /**
* Log Long Width * Log Long Width
* *
* @see Net_SSH2::_format_log * @see Net_SSH2::_format_log()
* @var Integer
* @access private * @access private
*/ */
var $log_long_width = 65; var $log_long_width = 65;
@ -766,19 +777,76 @@ class Net_SSH2
/** /**
* Log Short Width * Log Short Width
* *
* @see Net_SSH2::_format_log * @see Net_SSH2::_format_log()
* @var Integer
* @access private * @access private
*/ */
var $log_short_width = 16; var $log_short_width = 16;
/** /**
* Default Constructor. * Hostname
* *
* Connects to an SSHv2 server * @see Net_SSH2::Net_SSH2()
* @see Net_SSH2::_connect()
* @var String
* @access private
*/
var $host;
/**
* Port Number
*
* @see Net_SSH2::Net_SSH2()
* @see Net_SSH2::_connect()
* @var Integer
* @access private
*/
var $port;
/**
* Timeout for initial connection
*
* Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
* exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
* however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
* 10 seconds. It is used by fsockopen() and the initial stream_select in that function.
*
* @see Net_SSH2::Net_SSH2()
* @see Net_SSH2::_connect()
* @var Integer
* @access private
*/
var $connectionTimeout;
/**
* Number of columns for terminal window size
*
* @see Net_SSH2::getWindowColumns()
* @see Net_SSH2::setWindowColumns()
* @see Net_SSH2::setWindowSize()
* @var Integer
* @access private
*/
var $windowColumns = 80;
/**
* Number of columns for terminal window size
*
* @see Net_SSH2::getWindowRows()
* @see Net_SSH2::setWindowRows()
* @see Net_SSH2::setWindowSize()
* @var Integer
* @access private
*/
var $windowRows = 24;
/**
* Default Constructor.
* *
* @param String $host * @param String $host
* @param optional Integer $port * @param optional Integer $port
* @param optional Integer $timeout * @param optional Integer $timeout
* @see Net_SSH2::login()
* @return Net_SSH2 * @return Net_SSH2
* @access public * @access public
*/ */
@ -798,7 +866,6 @@ class Net_SSH2
include_once 'Crypt/Hash.php'; include_once 'Crypt/Hash.php';
} }
$this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5
$this->message_numbers = array( $this->message_numbers = array(
1 => 'NET_SSH2_MSG_DISCONNECT', 1 => 'NET_SSH2_MSG_DISCONNECT',
2 => 'NET_SSH2_MSG_IGNORE', 2 => 'NET_SSH2_MSG_IGNORE',
@ -869,19 +936,43 @@ class Net_SSH2
61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE') 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE')
); );
$this->host = $host;
$this->port = $port;
$this->connectionTimeout = $timeout;
}
/**
* Connect to an SSHv2 server
*
* @return Boolean
* @access private
*/
function _connect()
{
if ($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) {
return false;
}
$this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR;
$timeout = $this->connectionTimeout;
$host = $this->host . ':' . $this->port;
$this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $timeout);
if (!$this->fsock) { if (!$this->fsock) {
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
return; return false;
} }
$elapsed = strtok(microtime(), ' ') + strtok('') - $start; $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
$timeout-= $elapsed; $timeout-= $elapsed;
if ($timeout <= 0) { if ($timeout <= 0) {
user_error(rtrim("Cannot connect to $host. Timeout error")); user_error("Cannot connect to $host. Timeout error");
return; return false;
} }
$read = array($this->fsock); $read = array($this->fsock);
@ -893,8 +984,8 @@ class Net_SSH2
// on windows this returns a "Warning: Invalid CRT parameters detected" error // on windows this returns a "Warning: Invalid CRT parameters detected" error
// the !count() is done as a workaround for <https://bugs.php.net/42682> // the !count() is done as a workaround for <https://bugs.php.net/42682>
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
user_error(rtrim("Cannot connect to $host. Banner timeout")); user_error("Cannot connect to $host. Banner timeout");
return; return false;
} }
/* According to the SSH2 specs, /* According to the SSH2 specs,
@ -933,7 +1024,7 @@ class Net_SSH2
if ($matches[1] != '1.99' && $matches[1] != '2.0') { if ($matches[1] != '1.99' && $matches[1] != '2.0') {
user_error("Cannot connect to SSH $matches[1] servers"); user_error("Cannot connect to SSH $matches[1] servers");
return; return false;
} }
fputs($this->fsock, $this->identifier . "\r\n"); fputs($this->fsock, $this->identifier . "\r\n");
@ -941,19 +1032,21 @@ class Net_SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
user_error('Connection closed by server'); user_error('Connection closed by server');
return; return false;
} }
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
user_error('Expected SSH_MSG_KEXINIT'); user_error('Expected SSH_MSG_KEXINIT');
return; return false;
} }
if (!$this->_key_exchange($response)) { if (!$this->_key_exchange($response)) {
return; return false;
} }
$this->bitmap = NET_SSH2_MASK_CONSTRUCTOR; $this->bitmap|= NET_SSH2_MASK_CONNECTED;
return true;
} }
/** /**
@ -1011,7 +1104,7 @@ class Net_SSH2
'arcfour256', 'arcfour256',
'arcfour128', 'arcfour128',
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
// CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>: // CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>:
'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
@ -1039,34 +1132,34 @@ class Net_SSH2
'3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
'3des-cbc', // REQUIRED three-key 3DES in CBC mode '3des-cbc', // REQUIRED three-key 3DES in CBC mode
'none' // OPTIONAL no encryption; NOT RECOMMENDED //'none' // OPTIONAL no encryption; NOT RECOMMENDED
); );
if (!$this->_is_includable('Crypt/RC4.php')) { if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) {
$encryption_algorithms = array_diff( $encryption_algorithms = array_diff(
$encryption_algorithms, $encryption_algorithms,
array('arcfour256', 'arcfour128', 'arcfour') array('arcfour256', 'arcfour128', 'arcfour')
); );
} }
if (!$this->_is_includable('Crypt/Rijndael.php')) { if (phpseclib_resolve_include_path('Crypt/Rijndael.php') === false) {
$encryption_algorithms = array_diff( $encryption_algorithms = array_diff(
$encryption_algorithms, $encryption_algorithms,
array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc') array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc')
); );
} }
if (!$this->_is_includable('Crypt/Twofish.php')) { if (phpseclib_resolve_include_path('Crypt/Twofish.php') === false) {
$encryption_algorithms = array_diff( $encryption_algorithms = array_diff(
$encryption_algorithms, $encryption_algorithms,
array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc') array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc')
); );
} }
if (!$this->_is_includable('Crypt/Blowfish.php')) { if (phpseclib_resolve_include_path('Crypt/Blowfish.php') === false) {
$encryption_algorithms = array_diff( $encryption_algorithms = array_diff(
$encryption_algorithms, $encryption_algorithms,
array('blowfish-ctr', 'blowfish-cbc') array('blowfish-ctr', 'blowfish-cbc')
); );
} }
if (!$this->_is_includable('Crypt/TripleDES.php')) { if (phpseclib_resolve_include_path('Crypt/TripleDES.php') === false) {
$encryption_algorithms = array_diff( $encryption_algorithms = array_diff(
$encryption_algorithms, $encryption_algorithms,
array('3des-ctr', '3des-cbc') array('3des-ctr', '3des-cbc')
@ -1075,12 +1168,15 @@ class Net_SSH2
$encryption_algorithms = array_values($encryption_algorithms); $encryption_algorithms = array_values($encryption_algorithms);
} }
static $mac_algorithms = array( $mac_algorithms = array(
// from <http://www.ietf.org/rfc/rfc6668.txt>:
'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32)
'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20) 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20) 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16) 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16) 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
'none' // OPTIONAL no MAC; NOT RECOMMENDED //'none' // OPTIONAL no MAC; NOT RECOMMENDED
); );
static $compression_algorithms = array( static $compression_algorithms = array(
@ -1605,6 +1701,10 @@ class Net_SSH2
$createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none' $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
switch ($mac_algorithms[$i]) { switch ($mac_algorithms[$i]) {
case 'hmac-sha2-256':
$this->hmac_create = new Crypt_Hash('sha256');
$createKeyLength = 32;
break;
case 'hmac-sha1': case 'hmac-sha1':
$this->hmac_create = new Crypt_Hash('sha1'); $this->hmac_create = new Crypt_Hash('sha1');
$createKeyLength = 20; $createKeyLength = 20;
@ -1631,6 +1731,11 @@ class Net_SSH2
$checkKeyLength = 0; $checkKeyLength = 0;
$this->hmac_size = 0; $this->hmac_size = 0;
switch ($mac_algorithms[$i]) { switch ($mac_algorithms[$i]) {
case 'hmac-sha2-256':
$this->hmac_check = new Crypt_Hash('sha256');
$checkKeyLength = 32;
$this->hmac_size = 32;
break;
case 'hmac-sha1': case 'hmac-sha1':
$this->hmac_check = new Crypt_Hash('sha1'); $this->hmac_check = new Crypt_Hash('sha1');
$checkKeyLength = 20; $checkKeyLength = 20;
@ -1711,6 +1816,12 @@ class Net_SSH2
*/ */
function _login($username) function _login($username)
{ {
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}
$args = array_slice(func_get_args(), 1); $args = array_slice(func_get_args(), 1);
if (empty($args)) { if (empty($args)) {
return $this->_login_helper($username); return $this->_login_helper($username);
@ -1736,7 +1847,7 @@ class Net_SSH2
*/ */
function _login_helper($username, $password = null) function _login_helper($username, $password = null)
{ {
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { if (!($this->bitmap & NET_SSH2_MASK_CONNECTED)) {
return false; return false;
} }
@ -1968,7 +2079,6 @@ class Net_SSH2
if (!count($responses) && $num_prompts) { if (!count($responses) && $num_prompts) {
$this->last_interactive_response = $orig; $this->last_interactive_response = $orig;
$this->bitmap |= NET_SSH_MASK_LOGIN_INTERACTIVE;
return false; return false;
} }
@ -2151,11 +2261,11 @@ class Net_SSH2
/** /**
* Execute Command * Execute Command
* *
* If $block is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually. * If $callback is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually.
* In all likelihood, this is not a feature you want to be taking advantage of. * In all likelihood, this is not a feature you want to be taking advantage of.
* *
* @param String $command * @param String $command
* @param optional Boolean $block * @param optional Callback $callback
* @return String * @return String
* @access public * @access public
*/ */
@ -2173,7 +2283,7 @@ class Net_SSH2
// be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but,
// honestly, if you're transfering more than 2GB, you probably shouldn't be using phpseclib, anyway. // honestly, if you're transfering more than 2GB, you probably shouldn't be using phpseclib, anyway.
// see http://tools.ietf.org/html/rfc4254#section-5.2 for more info // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
$this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; $this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = $this->window_size;
// 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
// uses 0x4000, that's what will be used here, as well. // uses 0x4000, that's what will be used here, as well.
$packet_size = 0x4000; $packet_size = 0x4000;
@ -2196,7 +2306,7 @@ class Net_SSH2
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack('CNNa*CNa*N5a*', $packet = pack('CNNa*CNa*N5a*',
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100',
80, 24, 0, 0, strlen($terminal_modes), $terminal_modes); $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes);
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
return false; return false;
@ -2258,7 +2368,10 @@ class Net_SSH2
return false; return false;
default: default:
if (is_callable($callback)) { if (is_callable($callback)) {
$callback($temp); if (call_user_func($callback, $temp) === true) {
$this->_close_channel(NET_SSH2_CHANNEL_EXEC);
return true;
}
} else { } else {
$output.= $temp; $output.= $temp;
} }
@ -2280,7 +2393,7 @@ class Net_SSH2
return true; return true;
} }
$this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF; $this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = $this->window_size;
$packet_size = 0x4000; $packet_size = 0x4000;
$packet = pack('CNa*N3', $packet = pack('CNa*N3',
@ -2300,7 +2413,7 @@ class Net_SSH2
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack('CNNa*CNa*N5a*', $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', 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); $this->windowColumns, $this->windowRows, 0, 0, strlen($terminal_modes), $terminal_modes);
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
return false; return false;
@ -2557,11 +2670,12 @@ class Net_SSH2
/** /**
* Is the connection still active? * Is the connection still active?
* *
* @return boolean
* @access public * @access public
*/ */
function isConnected() function isConnected()
{ {
return $this->bitmap & NET_SSH2_MASK_LOGIN; return (bool) ($this->bitmap & NET_SSH2_MASK_CONNECTED);
} }
/** /**
@ -2611,6 +2725,11 @@ class Net_SSH2
$buffer = ''; $buffer = '';
while ($remaining_length > 0) { while ($remaining_length > 0) {
$temp = fread($this->fsock, $remaining_length); $temp = fread($this->fsock, $remaining_length);
if ($temp === false || feof($this->fsock)) {
user_error('Error reading from socket');
$this->bitmap = 0;
return false;
}
$buffer.= $temp; $buffer.= $temp;
$remaining_length-= strlen($temp); $remaining_length-= strlen($temp);
} }
@ -2624,7 +2743,11 @@ class Net_SSH2
if ($this->hmac_check !== false) { if ($this->hmac_check !== false) {
$hmac = fread($this->fsock, $this->hmac_size); $hmac = fread($this->fsock, $this->hmac_size);
if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { if ($hmac === false || strlen($hmac) != $this->hmac_size) {
user_error('Error reading socket');
$this->bitmap = 0;
return false;
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
user_error('Invalid HMAC'); user_error('Invalid HMAC');
return false; return false;
} }
@ -2688,7 +2811,7 @@ class Net_SSH2
} }
// see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
$this->_string_shift($payload, 1); $this->_string_shift($payload, 1);
extract(unpack('Nlength', $this->_string_shift($payload, 4))); extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->banner_message = utf8_decode($this->_string_shift($payload, $length)); $this->banner_message = utf8_decode($this->_string_shift($payload, $length));
@ -2696,7 +2819,7 @@ class Net_SSH2
} }
// only called when we've already logged in // only called when we've already logged in
if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) {
switch (ord($payload[0])) { switch (ord($payload[0])) {
case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
$this->_string_shift($payload, 1); $this->_string_shift($payload, 1);
@ -2763,6 +2886,20 @@ class Net_SSH2
$this->quiet_mode = false; $this->quiet_mode = false;
} }
/**
* Returns whether Quiet Mode is enabled or not
*
* @see Net_SSH2::enableQuietMode()
* @see Net_SSH2::disableQuietMode()
*
* @access public
* @return boolean
*/
function isQuietModeEnabled()
{
return $this->quiet_mode;
}
/** /**
* Enable request-pty when using exec() * Enable request-pty when using exec()
* *
@ -2783,6 +2920,20 @@ class Net_SSH2
$this->request_pty = false; $this->request_pty = false;
} }
/**
* Returns whether request-pty is enabled or not
*
* @see Net_SSH2::enablePTY()
* @see Net_SSH2::disablePTY()
*
* @access public
* @return boolean
*/
function isPTYEnabled()
{
return $this->request_pty;
}
/** /**
* Gets channel data * Gets channel data
* *
@ -2834,7 +2985,7 @@ class Net_SSH2
extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5)));
$this->window_size_server_to_client[$channel]-= strlen($response) + 4; $this->window_size_server_to_client[$channel]-= strlen($response);
// resize the window, if appropriate // resize the window, if appropriate
if ($this->window_size_server_to_client[$channel] < 0) { if ($this->window_size_server_to_client[$channel] < 0) {
@ -2908,7 +3059,7 @@ class Net_SSH2
// currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR // 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))); extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
$data = $this->_string_shift($response, $length); $data = $this->_string_shift($response, $length);
$this->stdErrorLog .= $data; $this->stdErrorLog.= $data;
if ($skip_extended || $this->quiet_mode) { if ($skip_extended || $this->quiet_mode) {
break; break;
} }
@ -3124,54 +3275,37 @@ class Net_SSH2
*/ */
function _send_channel_packet($client_channel, $data) function _send_channel_packet($client_channel, $data)
{ {
/* The maximum amount of data allowed is determined by the maximum while (strlen($data)) {
packet size for the channel, and the current window size, whichever
is smaller.
-- http://tools.ietf.org/html/rfc4254#section-5.2 */
$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
) - 4;
while (strlen($data) > $max_size) {
if (!$this->window_size_client_to_server[$client_channel]) { if (!$this->window_size_client_to_server[$client_channel]) {
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
// using an invalid channel will let the buffers be built up for the valid channels // using an invalid channel will let the buffers be built up for the valid channels
$output = $this->_get_channel_packet(-1); $this->_get_channel_packet(-1);
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST; $this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
) - 4;
} }
/* The maximum amount of data allowed is determined by the maximum
packet size for the channel, and the current window size, whichever
is smaller.
-- http://tools.ietf.org/html/rfc4254#section-5.2 */
$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
);
$temp = $this->_string_shift($data, $max_size);
$packet = pack('CN2a*', $packet = pack('CN2a*',
NET_SSH2_MSG_CHANNEL_DATA, NET_SSH2_MSG_CHANNEL_DATA,
$this->server_channels[$client_channel], $this->server_channels[$client_channel],
$max_size, strlen($temp),
$this->_string_shift($data, $max_size) $temp
); );
$this->window_size_client_to_server[$client_channel]-= strlen($temp);
$this->window_size_client_to_server[$client_channel]-= $max_size + 4;
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
return false; return false;
} }
} }
if (strlen($data) >= $this->window_size_client_to_server[$client_channel] - 4) { return true;
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
$this->_get_channel_packet(-1);
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
}
$this->window_size_client_to_server[$client_channel]-= strlen($data) + 4;
return $this->_send_binary_packet(pack('CN2a*',
NET_SSH2_MSG_CHANNEL_DATA,
$this->server_channels[$client_channel],
strlen($data),
$data));
} }
/** /**
@ -3220,7 +3354,7 @@ class Net_SSH2
*/ */
function _disconnect($reason) function _disconnect($reason)
{ {
if ($this->bitmap) { if ($this->bitmap & NET_SSH2_MASK_CONNECTED) {
$data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
$this->_send_binary_packet($data); $this->_send_binary_packet($data);
$this->bitmap = 0; $this->bitmap = 0;
@ -3374,6 +3508,8 @@ class Net_SSH2
*/ */
function getServerIdentification() function getServerIdentification()
{ {
$this->_connect();
return $this->server_identifier; return $this->server_identifier;
} }
@ -3385,6 +3521,8 @@ class Net_SSH2
*/ */
function getKexAlgorithms() function getKexAlgorithms()
{ {
$this->_connect();
return $this->kex_algorithms; return $this->kex_algorithms;
} }
@ -3396,6 +3534,8 @@ class Net_SSH2
*/ */
function getServerHostKeyAlgorithms() function getServerHostKeyAlgorithms()
{ {
$this->_connect();
return $this->server_host_key_algorithms; return $this->server_host_key_algorithms;
} }
@ -3407,6 +3547,8 @@ class Net_SSH2
*/ */
function getEncryptionAlgorithmsClient2Server() function getEncryptionAlgorithmsClient2Server()
{ {
$this->_connect();
return $this->encryption_algorithms_client_to_server; return $this->encryption_algorithms_client_to_server;
} }
@ -3418,6 +3560,8 @@ class Net_SSH2
*/ */
function getEncryptionAlgorithmsServer2Client() function getEncryptionAlgorithmsServer2Client()
{ {
$this->_connect();
return $this->encryption_algorithms_server_to_client; return $this->encryption_algorithms_server_to_client;
} }
@ -3429,6 +3573,8 @@ class Net_SSH2
*/ */
function getMACAlgorithmsClient2Server() function getMACAlgorithmsClient2Server()
{ {
$this->_connect();
return $this->mac_algorithms_client_to_server; return $this->mac_algorithms_client_to_server;
} }
@ -3440,6 +3586,8 @@ class Net_SSH2
*/ */
function getMACAlgorithmsServer2Client() function getMACAlgorithmsServer2Client()
{ {
$this->_connect();
return $this->mac_algorithms_server_to_client; return $this->mac_algorithms_server_to_client;
} }
@ -3451,6 +3599,8 @@ class Net_SSH2
*/ */
function getCompressionAlgorithmsClient2Server() function getCompressionAlgorithmsClient2Server()
{ {
$this->_connect();
return $this->compression_algorithms_client_to_server; return $this->compression_algorithms_client_to_server;
} }
@ -3462,6 +3612,8 @@ class Net_SSH2
*/ */
function getCompressionAlgorithmsServer2Client() function getCompressionAlgorithmsServer2Client()
{ {
$this->_connect();
return $this->compression_algorithms_server_to_client; return $this->compression_algorithms_server_to_client;
} }
@ -3473,6 +3625,8 @@ class Net_SSH2
*/ */
function getLanguagesServer2Client() function getLanguagesServer2Client()
{ {
$this->_connect();
return $this->languages_server_to_client; return $this->languages_server_to_client;
} }
@ -3484,6 +3638,8 @@ class Net_SSH2
*/ */
function getLanguagesClient2Server() function getLanguagesClient2Server()
{ {
$this->_connect();
return $this->languages_client_to_server; return $this->languages_client_to_server;
} }
@ -3512,6 +3668,12 @@ class Net_SSH2
*/ */
function getServerPublicHostKey() function getServerPublicHostKey()
{ {
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}
$signature = $this->signature; $signature = $this->signature;
$server_public_host_key = $this->server_public_host_key; $server_public_host_key = $this->server_public_host_key;
@ -3589,8 +3751,9 @@ class Net_SSH2
$e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $rawN = $this->_string_shift($server_public_host_key, $temp['length']);
$nLength = $temp['length']; $n = new Math_BigInteger($rawN, -256);
$nLength = strlen(ltrim($rawN, "\0"));
/* /*
$temp = unpack('Nlength', $this->_string_shift($signature, 4)); $temp = unpack('Nlength', $this->_string_shift($signature, 4));
@ -3627,7 +3790,7 @@ class Net_SSH2
$s = $s->toBytes(); $s = $s->toBytes();
$h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h; $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) { if ($s != $h) {
user_error('Bad server signature'); user_error('Bad server signature');
@ -3657,30 +3820,59 @@ class Net_SSH2
} }
/** /**
* Is a path includable? * Returns the number of columns for the terminal window size.
* *
* @return Boolean * @return Integer
* @access private * @access public
*/ */
function _is_includable($suffix) function getWindowColumns()
{ {
// stream_resolve_include_path was introduced in PHP 5.3.2 return $this->windowColumns;
if (function_exists('stream_resolve_include_path')) { }
return stream_resolve_include_path($suffix) !== false;
}
$paths = PATH_SEPARATOR == ':' ? /**
preg_split('#(?<!phar):#', get_include_path()) : * Returns the number of rows for the terminal window size.
explode(PATH_SEPARATOR, get_include_path()); *
foreach ($paths as $prefix) { * @return Integer
$ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR; * @access public
$file = $prefix . $ds . $suffix; */
function getWindowRows()
{
return $this->windowRows;
}
if (file_exists($file)) { /**
return true; * Sets the number of columns for the terminal window size.
} *
} * @param Integer $value
* @access public
*/
function setWindowColumns($value)
{
$this->windowColumns = $value;
}
return false; /**
* Sets the number of rows for the terminal window size.
*
* @param Integer $value
* @access public
*/
function setWindowRows($value)
{
$this->windowRows = $value;
}
/**
* Sets the number of columns and rows for the terminal window size.
*
* @param Integer $columns
* @param Integer $rows
* @access public
*/
function setWindowSize($columns = 80, $rows = 24)
{
$this->windowColumns = $columns;
$this->windowRows = $rows;
} }
} }

View File

@ -0,0 +1,313 @@
<?php
/**
* Pure-PHP ssh-agent client.
*
* PHP versions 4 and 5
*
* Here are some examples of how to use this library:
* <code>
* <?php
* include 'System/SSH/Agent.php';
* include 'Net/SSH2.php';
*
* $agent = new System_SSH_Agent();
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', $agent)) {
* exit('Login Failed');
* }
*
* echo $ssh->exec('pwd');
* echo $ssh->exec('ls -la');
* ?>
* </code>
*
* 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 System
* @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/
/**#@+
* Message numbers
*
* @access private
*/
// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
define('SYSTEM_SSH_AGENT_FAILURE', 5);
// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
/**#@-*/
/**
* Pure-PHP ssh-agent client identity object
*
* Instantiation should only be performed by System_SSH_Agent class.
* This could be thought of as implementing an interface that Crypt_RSA
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
* The methods in this interface would be getPublicKey, setSignatureMode
* and sign since those are the methods phpseclib looks for to perform
* public key authentication.
*
* @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net>
* @access internal
*/
class System_SSH_Agent_Identity
{
/**
* Key Object
*
* @var Crypt_RSA
* @access private
* @see System_SSH_Agent_Identity::getPublicKey()
*/
var $key;
/**
* Key Blob
*
* @var String
* @access private
* @see System_SSH_Agent_Identity::sign()
*/
var $key_blob;
/**
* Socket Resource
*
* @var Resource
* @access private
* @see System_SSH_Agent_Identity::sign()
*/
var $fsock;
/**
* Default Constructor.
*
* @param Resource $fsock
* @return System_SSH_Agent_Identity
* @access private
*/
function System_SSH_Agent_Identity($fsock)
{
$this->fsock = $fsock;
}
/**
* Set Public Key
*
* Called by System_SSH_Agent::requestIdentities()
*
* @param Crypt_RSA $key
* @access private
*/
function setPublicKey($key)
{
$this->key = $key;
$this->key->setPublicKey();
}
/**
* Set Public Key
*
* Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key
* but this saves a small amount of computation.
*
* @param String $key_blob
* @access private
*/
function setPublicKeyBlob($key_blob)
{
$this->key_blob = $key_blob;
}
/**
* Get Public Key
*
* Wrapper for $this->key->getPublicKey()
*
* @param Integer $format optional
* @return Mixed
* @access public
*/
function getPublicKey($format = null)
{
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
}
/**
* Set Signature Mode
*
* Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
* ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1
*
* @param Integer $mode
* @access public
*/
function setSignatureMode($mode)
{
}
/**
* Create a signature
*
* See "2.6.2 Protocol 2 private key signature request"
*
* @param String $message
* @return String
* @access public
*/
function sign($message)
{
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
$packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed during signing');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) {
user_error('Unable to retreive signature');
}
$signature_blob = fread($this->fsock, $length - 1);
// the only other signature format defined - ssh-dss - is the same length as ssh-rsa
// the + 12 is for the other various SSH added length fields
return substr($signature_blob, strlen('ssh-rsa') + 12);
}
}
/**
* Pure-PHP ssh-agent client identity factory
*
* requestIdentities() method pumps out System_SSH_Agent_Identity objects
*
* @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net>
* @access internal
*/
class System_SSH_Agent
{
/**
* Socket Resource
*
* @var Resource
* @access private
*/
var $fsock;
/**
* Default Constructor
*
* @return System_SSH_Agent
* @access public
*/
function System_SSH_Agent()
{
switch (true) {
case isset($_SERVER['SSH_AUTH_SOCK']):
$address = $_SERVER['SSH_AUTH_SOCK'];
break;
case isset($_ENV['SSH_AUTH_SOCK']):
$address = $_ENV['SSH_AUTH_SOCK'];
break;
default:
user_error('SSH_AUTH_SOCK not found');
return false;
}
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
if (!$this->fsock) {
user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
}
}
/**
* Request Identities
*
* See "2.5.2 Requesting a list of protocol 2 keys"
* Returns an array containing zero or more System_SSH_Agent_Identity objects
*
* @return Array
* @access public
*/
function requestIdentities()
{
if (!$this->fsock) {
return array();
}
$packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed while requesting identities');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities');
}
$identities = array();
$keyCount = current(unpack('N', fread($this->fsock, 4)));
for ($i = 0; $i < $keyCount; $i++) {
$length = current(unpack('N', fread($this->fsock, 4)));
$key_blob = fread($this->fsock, $length);
$length = current(unpack('N', fread($this->fsock, 4)));
$key_comment = fread($this->fsock, $length);
$length = current(unpack('N', substr($key_blob, 0, 4)));
$key_type = substr($key_blob, 4, $length);
switch ($key_type) {
case 'ssh-rsa':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$key = new Crypt_RSA();
$key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment);
break;
case 'ssh-dss':
// not currently supported
break;
}
// resources are passed by reference by default
if (isset($key)) {
$identity = new System_SSH_Agent_Identity($this->fsock);
$identity->setPublicKey($key);
$identity->setPublicKeyBlob($key_blob);
$identities[] = $identity;
unset($key);
}
}
return $identities;
}
}

View File

@ -1,26 +1,13 @@
<?php <?php
/** /**
* Pure-PHP ssh-agent client. * Pure-PHP ssh-agent client wrapper
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* Here are some examples of how to use this library: * Originally System_SSH_Agent was accessed as System/SSH_Agent.php instead of
* <code> * System/SSH/Agent.php. The problem with this is that PSR0 compatible autoloaders
* <?php * don't support that kind of directory layout hence the package being moved and
* include('System/SSH_Agent.php'); * this "alias" being created to maintain backwards compatibility.
* include('Net/SSH2.php');
*
* $agent = new System_SSH_Agent();
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', $agent)) {
* exit('Login Failed');
* }
*
* echo $ssh->exec('pwd');
* echo $ssh->exec('ls -la');
* ?>
* </code>
* *
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * 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 * of this software and associated documentation files (the "Software"), to deal
@ -43,273 +30,10 @@
* @category System * @category System
* @package System_SSH_Agent * @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXIV Jim Wigginton * @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/ */
/**#@+ require_once 'SSH/Agent.php';
* Message numbers
*
* @access private
*/
// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
define('SYSTEM_SSH_AGENT_FAILURE', 5);
// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
/**#@-*/
/**
* Pure-PHP ssh-agent client identity object
*
* Instantiation should only be performed by System_SSH_Agent class.
* This could be thought of as implementing an interface that Crypt_RSA
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
* The methods in this interface would be getPublicKey, setSignatureMode
* and sign since those are the methods phpseclib looks for to perform
* public key authentication.
*
* @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access internal
*/
class System_SSH_Agent_Identity
{
/**
* Key Object
*
* @var Crypt_RSA
* @access private
* @see System_SSH_Agent_Identity::getPublicKey()
*/
var $key;
/**
* Key Blob
*
* @var String
* @access private
* @see System_SSH_Agent_Identity::sign()
*/
var $key_blob;
/**
* Socket Resource
*
* @var Resource
* @access private
* @see System_SSH_Agent_Identity::sign()
*/
var $fsock;
/**
* Default Constructor.
*
* @param Resource $fsock
* @return System_SSH_Agent_Identity
* @access private
*/
function System_SSH_Agent_Identity($fsock)
{
$this->fsock = $fsock;
}
/**
* Set Public Key
*
* Called by System_SSH_Agent::requestIdentities()
*
* @param Crypt_RSA $key
* @access private
*/
function setPublicKey($key)
{
$this->key = $key;
$this->key->setPublicKey();
}
/**
* Set Public Key
*
* Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key
* but this saves a small amount of computation.
*
* @param String $key_blob
* @access private
*/
function setPublicKeyBlob($key_blob)
{
$this->key_blob = $key_blob;
}
/**
* Get Public Key
*
* Wrapper for $this->key->getPublicKey()
*
* @param Integer $format optional
* @return Mixed
* @access public
*/
function getPublicKey($format = null)
{
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
}
/**
* Set Signature Mode
*
* Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
* ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1
*
* @param Integer $mode
* @access public
*/
function setSignatureMode($mode)
{
}
/**
* Create a signature
*
* See "2.6.2 Protocol 2 private key signature request"
*
* @param String $message
* @return String
* @access public
*/
function sign($message)
{
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
$packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed during signing');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) {
user_error('Unable to retreive signature');
}
$signature_blob = fread($this->fsock, $length - 1);
// the only other signature format defined - ssh-dss - is the same length as ssh-rsa
// the + 12 is for the other various SSH added length fields
return substr($signature_blob, strlen('ssh-rsa') + 12);
}
}
/**
* Pure-PHP ssh-agent client identity factory
*
* requestIdentities() method pumps out System_SSH_Agent_Identity objects
*
* @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access internal
*/
class System_SSH_Agent
{
/**
* Socket Resource
*
* @var Resource
* @access private
*/
var $fsock;
/**
* Default Constructor
*
* @return System_SSH_Agent
* @access public
*/
function System_SSH_Agent()
{
switch (true) {
case isset($_SERVER['SSH_AUTH_SOCK']):
$address = $_SERVER['SSH_AUTH_SOCK'];
break;
case isset($_ENV['SSH_AUTH_SOCK']):
$address = $_ENV['SSH_AUTH_SOCK'];
break;
default:
user_error('SSH_AUTH_SOCK not found');
return false;
}
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
if (!$this->fsock) {
user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
}
}
/**
* Request Identities
*
* See "2.5.2 Requesting a list of protocol 2 keys"
* Returns an array containing zero or more System_SSH_Agent_Identity objects
*
* @return Array
* @access public
*/
function requestIdentities()
{
if (!$this->fsock) {
return array();
}
$packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed while requesting identities');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities');
}
$identities = array();
$keyCount = current(unpack('N', fread($this->fsock, 4)));
for ($i = 0; $i < $keyCount; $i++) {
$length = current(unpack('N', fread($this->fsock, 4)));
$key_blob = fread($this->fsock, $length);
$length = current(unpack('N', fread($this->fsock, 4)));
$key_comment = fread($this->fsock, $length);
$length = current(unpack('N', substr($key_blob, 0, 4)));
$key_type = substr($key_blob, 4, $length);
switch ($key_type) {
case 'ssh-rsa':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$key = new Crypt_RSA();
$key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment);
break;
case 'ssh-dss':
// not currently supported
break;
}
// resources are passed by reference by default
if (isset($key)) {
$identity = new System_SSH_Agent_Identity($this->fsock);
$identity->setPublicKey($key);
$identity->setPublicKeyBlob($key_blob);
$identities[] = $identity;
unset($key);
}
}
return $identities;
}
}