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:
* <code>
* <?php
* include('Crypt/AES.php');
* include 'Crypt/AES.php';
*
* $aes = new Crypt_AES();
*
@ -56,7 +56,7 @@
* @category Crypt
* @package Crypt_AES
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -109,7 +109,7 @@ define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
/**#@+
* @access private
* @see Crypt_AES::Crypt_AES()
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
@ -126,7 +126,6 @@ define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
*
* @package Crypt_AES
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Crypt_AES extends Crypt_Rijndael
@ -140,35 +139,6 @@ class Crypt_AES extends Crypt_Rijndael
*/
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
*
@ -182,4 +152,56 @@ class Crypt_AES extends Crypt_Rijndael
{
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
* @author Jim Wigginton <terrafrost@php.net>
* @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
* @version 1.0.1
* @link http://phpseclib.sourceforge.net
*/
@ -117,7 +116,6 @@ define('CRYPT_MODE_MCRYPT', 2);
* @package Crypt_Base
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @version 1.0.0
* @access public
*/
class Crypt_Base
@ -279,7 +277,7 @@ class Crypt_Base
* $buffer bytes > $cfb_init_len than
* 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
* initialization [by mcrypt_generic_init()]
* which, typically, depends on the complexity
@ -438,9 +436,9 @@ class Crypt_Base
*
* - 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
* @access public
@ -500,7 +498,7 @@ class Crypt_Base
/**
* 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.
*
* Note: Could, but not must, extend by the child Crypt_* class
@ -543,7 +541,7 @@ class Crypt_Base
* Sets the password.
*
* 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
*
* Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
@ -553,6 +551,7 @@ class Crypt_Base
* @see Crypt/Hash.php
* @param String $password
* @param optional String $method
* @return Boolean
* @access public
*/
function setPassword($password, $method = 'pbkdf2')
@ -560,7 +559,7 @@ class Crypt_Base
$key = '';
switch ($method) {
default: // 'pbkdf2'
default: // 'pbkdf2' or 'pbkdf1'
$func_args = func_get_args();
// Hash function
@ -574,10 +573,34 @@ class Crypt_Base
$count = isset($func_args[4]) ? $func_args[4] : 1000;
// 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) {
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_algos'):
case !in_array($hash, hash_algos()):
@ -604,6 +627,8 @@ class Crypt_Base
}
$this->setKey($key);
return true;
}
/**
@ -1446,7 +1471,7 @@ class Crypt_Base
* - 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
* where, for example, the keys allready expanded,
* keys/block_size calculated and such.

View File

@ -14,7 +14,7 @@
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/Blowfish.php');
* include 'Crypt/Blowfish.php';
*
* $blowfish = new Crypt_Blowfish();
*
@ -48,9 +48,8 @@
* @package Crypt_Blowfish
* @author Jim Wigginton <terrafrost@php.net>
* @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
* @version 1.0
* @link http://phpseclib.sourceforge.net
*/
@ -104,7 +103,7 @@ define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@+
* @access private
* @see Crypt_Blowfish::Crypt_Blowfish()
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
@ -122,7 +121,6 @@ define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* @package Crypt_Blowfish
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @version 1.0
* @access public
*/
class Crypt_Blowfish extends Crypt_Base
@ -369,34 +367,6 @@ class Crypt_Blowfish extends Crypt_Base
*/
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.
*

View File

@ -16,7 +16,7 @@
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/DES.php');
* include 'Crypt/DES.php';
*
* $des = new Crypt_DES();
*
@ -53,7 +53,7 @@
* @category Crypt
* @package Crypt_DES
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -123,7 +123,7 @@ define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB);
/**#@+
* @access private
* @see Crypt_DES::Crypt_DES()
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
@ -140,7 +140,6 @@ define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
*
* @package Crypt_DES
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Crypt_DES extends Crypt_Base
@ -662,34 +661,6 @@ class Crypt_DES extends Crypt_Base
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.
*

View File

@ -5,7 +5,7 @@
*
* 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
* 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:
* <code>
* <?php
* include('Crypt/Hash.php');
* include 'Crypt/Hash.php';
*
* $hash = new Crypt_Hash('sha1');
*
@ -49,7 +49,7 @@
* @category Crypt
* @package Crypt_Hash
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -77,7 +77,6 @@ define('CRYPT_HASH_MODE_HASH', 3);
*
* @package Crypt_Hash
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Crypt_Hash
@ -208,6 +207,9 @@ class Crypt_Hash
switch ($hash) {
case 'md5-96':
case 'sha1-96':
case 'sha256-96':
case 'sha512-96':
$hash = substr($hash, 0, -3);
$this->l = 12; // 96 / 8 = 12
break;
case 'md2':
@ -244,14 +246,12 @@ class Crypt_Hash
case CRYPT_HASH_MODE_MHASH:
switch ($hash) {
case 'md5':
case 'md5-96':
$this->hash = MHASH_MD5;
break;
case 'sha256':
$this->hash = MHASH_SHA256;
break;
case 'sha1':
case 'sha1-96':
default:
$this->hash = MHASH_SHA1;
}
@ -259,7 +259,6 @@ class Crypt_Hash
case CRYPT_HASH_MODE_HASH:
switch ($hash) {
case 'md5':
case 'md5-96':
$this->hash = 'md5';
return;
case 'md2':
@ -269,7 +268,6 @@ class Crypt_Hash
$this->hash = $hash;
return;
case 'sha1':
case 'sha1-96':
default:
$this->hash = 'sha1';
}
@ -282,7 +280,6 @@ class Crypt_Hash
$this->hash = array($this, '_md2');
break;
case 'md5':
case 'md5-96':
$this->b = 64;
$this->hash = array($this, '_md5');
break;
@ -296,7 +293,6 @@ class Crypt_Hash
$this->hash = array($this, '_sha512');
break;
case 'sha1':
case 'sha1-96':
default:
$this->b = 64;
$this->hash = array($this, '_sha1');

View File

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

View File

@ -18,7 +18,7 @@
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/RC4.php');
* include 'Crypt/RC4.php';
*
* $rc4 = new Crypt_RC4();
*
@ -55,7 +55,7 @@
* @category Crypt
* @package Crypt_RC4
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -96,7 +96,6 @@ define('CRYPT_RC4_DECRYPT', 1);
*
* @package Crypt_RC4
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Crypt_RC4 extends Crypt_Base
@ -241,7 +240,7 @@ class Crypt_RC4 extends Crypt_Base
* Decrypts a message.
*
* $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_RC4::_crypt()
@ -268,10 +267,7 @@ class Crypt_RC4 extends Crypt_Base
{
$key = $this->key;
$keyLength = strlen($key);
$keyStream = array();
for ($i = 0; $i < 256; $i++) {
$keyStream[$i] = $i;
}
$keyStream = range(0, 255);
$j = 0;
for ($i = 0; $i < 256; $i++) {
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
@ -325,7 +321,7 @@ class Crypt_RC4 extends Crypt_Base
$keyStream[$i] = $ksj;
$keyStream[$j] = $ksi;
$text[$k] = chr(ord($text[$k]) ^ $keyStream[($ksj + $ksi) & 255]);
$text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
}
return $text;

View File

@ -8,7 +8,7 @@
* Here's an example of how to encrypt and decrypt text with this library:
* <code>
* <?php
* include('Crypt/RSA.php');
* include 'Crypt/RSA.php';
*
* $rsa = new Crypt_RSA();
* extract($rsa->createKey());
@ -26,7 +26,7 @@
* Here's an example of how to create signatures and verify signatures with this library:
* <code>
* <?php
* include('Crypt/RSA.php');
* include 'Crypt/RSA.php';
*
* $rsa = new Crypt_RSA();
* extract($rsa->createKey());
@ -62,7 +62,7 @@
* @category Crypt
* @package Crypt_RSA
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -104,7 +104,7 @@ define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
* Use PKCS#1 padding.
*
* 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);
/**#@-*/
@ -128,7 +128,7 @@ define('CRYPT_RSA_SIGNATURE_PSS', 1);
* 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
* 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);
/**#@-*/
@ -140,15 +140,23 @@ define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
/**
* ASN1 Integer
*/
define('CRYPT_RSA_ASN1_INTEGER', 2);
define('CRYPT_RSA_ASN1_INTEGER', 2);
/**
* 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)
*/
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
*/
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)
*
* 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);
/**
* XML formatted public key
@ -232,8 +251,16 @@ define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
* PKCS#1 formatted public key (encapsulated)
*
* 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
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Crypt_RSA
@ -276,7 +302,7 @@ class Crypt_RSA
* @var Integer
* @access public
*/
var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8;
/**
* Modulus (ie. n)
@ -467,18 +493,21 @@ class Crypt_RSA
$this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
if ( !defined('CRYPT_RSA_MODE') ) {
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
// Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
if ( defined('MATH_BIGINTEGER_OPENSSL_DISABLE') ) {
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
}
switch ( !defined('CRYPT_RSA_MODE') ) { // ie. only run this if the above didn't set CRYPT_RSA_MODE already
switch (true) {
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
// Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
break;
// 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):
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start();
phpinfo();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();
@ -486,9 +515,16 @@ class Crypt_RSA
$versions = array();
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
}
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
}
}
// it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
@ -503,7 +539,7 @@ class Crypt_RSA
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
}
break;
case true:
default:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
}
}
@ -713,17 +749,18 @@ class Crypt_RSA
*/
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
{
$signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML;
$num_primes = count($primes);
$raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
'modulus' => $n->toBytes(true),
'publicExponent' => $e->toBytes(true),
'privateExponent' => $d->toBytes(true),
'prime1' => $primes[1]->toBytes(true),
'prime2' => $primes[2]->toBytes(true),
'exponent1' => $exponents[1]->toBytes(true),
'exponent2' => $exponents[2]->toBytes(true),
'coefficient' => $coefficients[2]->toBytes(true)
'modulus' => $n->toBytes($signed),
'publicExponent' => $e->toBytes($signed),
'privateExponent' => $d->toBytes($signed),
'prime1' => $primes[1]->toBytes($signed),
'prime2' => $primes[2]->toBytes($signed),
'exponent1' => $exponents[1]->toBytes($signed),
'exponent2' => $exponents[2]->toBytes($signed),
'coefficient' => $coefficients[2]->toBytes($signed)
);
// 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']
);
$source = pack('Na*Na*Na*Na*',
strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
strlen($this->comment), $this->comment, strlen($public), $public
strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
strlen($this->comment), $this->comment, strlen($public), $public
);
$public = base64_encode($public);
$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);
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)) {
$iv = crypt_random_string(8);
$symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
@ -866,8 +949,10 @@ class Crypt_RSA
*/
function _convertPublicKey($n, $e)
{
$modulus = $n->toBytes(true);
$publicExponent = $e->toBytes(true);
$signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML;
$modulus = $n->toBytes($signed);
$publicExponent = $e->toBytes($signed);
switch ($this->publicKeyFormat) {
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
@ -903,7 +988,11 @@ class Crypt_RSA
$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.
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPublicKey = chr(0) . $RSAPublicKey;
@ -912,11 +1001,11 @@ class Crypt_RSA
$RSAPublicKey = pack('Ca*a*',
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
);
}
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END PUBLIC KEY-----';
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END PUBLIC KEY-----';
}
return $RSAPublicKey;
}
@ -972,6 +1061,7 @@ class Crypt_RSA
}
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
case CRYPT_RSA_PRIVATE_FORMAT_PKCS8:
case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
/* 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
@ -1062,7 +1152,9 @@ class Crypt_RSA
7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
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") {
$this->_string_shift($key, 3);
@ -1070,6 +1162,52 @@ class Crypt_RSA
}
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:
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
17:d=2 hl=2 l= 0 prim: NULL
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
$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
@ -1479,6 +1616,19 @@ class Crypt_RSA
$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;
}
@ -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
* 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
* 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.
*
@ -1561,6 +1713,40 @@ class Crypt_RSA
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
*
@ -1573,7 +1759,7 @@ class Crypt_RSA
* @param String $key
* @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)) {
return false;
@ -1620,7 +1806,7 @@ class Crypt_RSA
* @param String $key
* @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)) {
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}.
*
* 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
* 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
* 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.
*
* 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
*
* 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
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/Random.php');
* include 'Crypt/Random.php';
*
* echo bin2hex(crypt_random_string(8));
* ?>
@ -35,181 +38,210 @@
* @category Crypt
* @package Crypt_Random
* @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
* @link http://phpseclib.sourceforge.net
*/
/**
* "Is Windows" test
*
* @access private
*/
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
// laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
// have phpseclib as a requirement as well. if you're developing such a program you may encounter
// a "Cannot redeclare crypt_random_string()" error.
if (!function_exists('crypt_random_string')) {
/**
* "Is Windows" test
*
* @access private
*/
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
/**
* Generate a random string.
*
* 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.
* eg. for RSA key generation.
*
* @param Integer $length
* @return String
* @access public
*/
function crypt_random_string($length)
{
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.
// ie. class_alias is a function that was introduced in PHP 5.3
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
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,
// 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
// 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/mcrypt/mcrypt.c#L1392
//
// php_win32_get_random_bytes() is defined thusly:
//
// 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
if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
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);
/**
* Generate a random string.
*
* 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.
* eg. for RSA key generation.
*
* @param Integer $length
* @return String
* @access public
*/
function crypt_random_string($length)
{
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.
// ie. class_alias is a function that was introduced in PHP 5.3
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
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,
// 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
// 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/mcrypt/mcrypt.c#L1392
//
// php_win32_get_random_bytes() is defined thusly:
//
// 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
if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
return openssl_random_pseudo_bytes($length);
}
} else {
if ($_OLD_SESSION !== false) {
$_SESSION = $_OLD_SESSION;
unset($_OLD_SESSION);
} else {
unset($_SESSION);
// 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
// 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:
// 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.
//
// 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'));
// 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();
}
// 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 class_exists('Crypt_AES'):
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
break;
case class_exists('Crypt_TripleDES'):
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
break;
case class_exists('Crypt_DES'):
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
break;
case class_exists('Crypt_RC4'):
$crypto = new Crypt_RC4();
break;
default:
$crypto = $seed;
return crypt_random_string($length);
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 {
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);
$crypto->setIV($iv);
$crypto->enableContinuousBuffer();
}
//return $crypto->encrypt(str_repeat("\0", $length));
if (is_string($crypto)) {
// the following is based off of ANSI X9.31:
//
// 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
// (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 = '';
while (strlen($result) < $length) { // each loop adds 20 bytes
// microtime() isn't packed as "densely" as it could be but then neither is that the idea.
// the idea is simply to ensure that each "block" has a unique element to it.
$i = pack('H*', sha1(microtime()));
$r = pack('H*', sha1($i ^ $v));
$v = pack('H*', sha1($r ^ $i));
while (strlen($result) < $length) {
$i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
$r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
$v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
$result.= $r;
}
return substr($result, 0, $length);
}
//return $crypto->encrypt(str_repeat("\0", $length));
$result = '';
while (strlen($result) < $length) {
$i = $crypto->encrypt(microtime());
$r = $crypto->encrypt($i ^ $v);
$v = $crypto->encrypt($r ^ $i);
$result.= $r;
}
return substr($result, 0, $length);
}
if (!function_exists('phpseclib_resolve_include_path')) {
/**
* Resolve filename against the include path.
*
* Wrapper around stream_resolve_include_path() (which was introduced in
* PHP 5.3.2) with fallback implementation for earlier PHP versions.
*
* @param string $filename
* @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:
* <code>
* <?php
* include('Crypt/Rijndael.php');
* include 'Crypt/Rijndael.php';
*
* $rijndael = new Crypt_Rijndael();
*
@ -65,7 +65,7 @@
* @category Crypt
* @package Crypt_Rijndael
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -120,7 +120,7 @@ define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
/**#@+
* @access private
* @see Crypt_Rijndael::Crypt_Rijndael()
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
@ -137,7 +137,6 @@ define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
*
* @package Crypt_Rijndael
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
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.
* Crypt_Rijndael determines automatically whether mcrypt is useable
* 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::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
);
/**
* 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.
*
@ -731,9 +702,15 @@ class Crypt_Rijndael extends Crypt_Base
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 20:
$this->key_size = 20;
break;
case $length <= 24:
$this->key_size = 24;
break;
case $length <= 28:
$this->key_size = 28;
break;
default:
$this->key_size = 32;
}
@ -755,7 +732,7 @@ class Crypt_Rijndael extends Crypt_Base
* 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
* the mcrypt php extention, even if available.
* the mcrypt php extension, even if available.
* This results then in slower encryption.
*
* @access public

View File

@ -10,7 +10,7 @@
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/TripleDES.php');
* include 'Crypt/TripleDES.php';
*
* $des = new Crypt_TripleDES();
*
@ -47,7 +47,7 @@
* @category Crypt
* @package Crypt_TripleDES
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -78,7 +78,6 @@ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
*
* @package Crypt_TripleDES
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Crypt_TripleDES extends Crypt_DES
@ -180,7 +179,7 @@ class Crypt_TripleDES extends Crypt_DES
*
* - 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_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
// and additional flag us internally as 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 three $des'es will do the 3CBC work (if $key > 64bits)
@ -210,14 +209,14 @@ class Crypt_TripleDES extends Crypt_DES
break;
// If not 3CBC, we init as usual
default:
parent::Crypt_DES($mode);
parent::Crypt_Base($mode);
}
}
/**
* 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.
*
* @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 ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->des[2]->encrypt(
$this->des[1]->decrypt(
$this->des[0]->encrypt($this->_pad($plaintext))));
$this->des[1]->decrypt(
$this->des[0]->encrypt(
$this->_pad($plaintext)
)
)
);
}
return parent::encrypt($plaintext);
@ -307,9 +310,15 @@ class Crypt_TripleDES extends Crypt_DES
function decrypt($ciphertext)
{
if ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->_unpad($this->des[0]->decrypt(
$this->des[1]->encrypt(
$this->des[2]->decrypt(str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")))));
return $this->_unpad(
$this->des[0]->decrypt(
$this->des[1]->encrypt(
$this->des[2]->decrypt(
str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
)
)
)
);
}
return parent::decrypt($ciphertext);

View File

@ -14,7 +14,7 @@
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Crypt/Twofish.php');
* include 'Crypt/Twofish.php';
*
* $twofish = new Crypt_Twofish();
*
@ -48,9 +48,8 @@
* @package Crypt_Twofish
* @author Jim Wigginton <terrafrost@php.net>
* @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
* @version 1.0
* @link http://phpseclib.sourceforge.net
*/
@ -104,7 +103,7 @@ define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@+
* @access private
* @see Crypt_Twofish::Crypt_Twofish()
* @see Crypt_Base::Crypt_Base()
*/
/**
* Toggles the internal implementation
@ -122,7 +121,6 @@ define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
* @package Crypt_Twofish
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @version 1.0
* @access public
*/
class Crypt_Twofish extends Crypt_Base
@ -448,34 +446,6 @@ class Crypt_Twofish extends Crypt_Base
*/
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.
*
@ -709,10 +679,12 @@ class Crypt_Twofish extends Crypt_Base
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
}
// @codingStandardsIgnoreStart
return pack("V4", $K[4] ^ $R2,
$K[5] ^ $R3,
$K[6] ^ $R0,
$K[7] ^ $R1);
// @codingStandardsIgnoreEnd
}
/**
@ -763,10 +735,12 @@ class Crypt_Twofish extends Crypt_Base
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
}
// @codingStandardsIgnoreStart
return pack("V4", $K[0] ^ $R2,
$K[1] ^ $R3,
$K[2] ^ $R0,
$K[3] ^ $R1);
// @codingStandardsIgnoreEnd
}
/**

View File

@ -31,7 +31,7 @@
* @category File
* @package File_ANSI
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -41,7 +41,6 @@
*
* @package File_ANSI
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.0
* @access public
*/
class File_ANSI

View File

@ -34,7 +34,7 @@
* @category File
* @package File_ASN1
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -112,7 +112,6 @@ define('FILE_ASN1_TYPE_ANY', -2);
*
* @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.0
* @access public
*/
class File_ASN1_Element
@ -143,7 +142,6 @@ class File_ASN1_Element
*
* @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.0
* @access public
*/
class File_ASN1
@ -164,7 +162,7 @@ class File_ASN1
* @access private
* @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
@ -274,7 +272,8 @@ class File_ASN1
}
$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
* @access private
*/
function _decode_ber(&$encoded, $start = 0)
function _decode_ber($encoded, $start = 0)
{
$decoded = array();
$current = array('start' => $start);
while ( strlen($encoded) ) {
$current = array('start' => $start);
$type = ord($this->_string_shift($encoded));
$start++;
$type = ord($this->_string_shift($encoded));
$start++;
$constructed = ($type >> 5) & 1;
$constructed = ($type >> 5) & 1;
$tag = $type & 0x1F;
if ($tag == 0x1F) {
$tag = 0;
// process septets (since the eighth bit is ignored, it's not an octet)
do {
$loop = ord($encoded[0]) >> 7;
$tag <<= 7;
$tag |= ord($this->_string_shift($encoded)) & 0x7F;
$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']);
$tag = $type & 0x1F;
if ($tag == 0x1F) {
$tag = 0;
// process septets (since the eighth bit is ignored, it's not an octet)
do {
$loop = ord($encoded[0]) >> 7;
$tag <<= 7;
$tag |= ord($this->_string_shift($encoded)) & 0x7F;
$start++;
} while ( $loop );
}
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.
*
@ -511,7 +540,7 @@ class File_ASN1
*/
function asn1map($decoded, $mapping, $special = array())
{
if (isset($mapping['explicit'])) {
if (isset($mapping['explicit']) && is_array($decoded['content'])) {
$decoded = $decoded['content'][0];
}
@ -552,7 +581,15 @@ class File_ASN1
case $decoded['type'] == $mapping['type']:
break;
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'])) {
@ -799,16 +836,6 @@ class File_ASN1
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)
*
@ -944,6 +971,9 @@ class File_ASN1
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
if (!isset($mapping['mapping'])) {
if (is_numeric($source)) {
$source = new Math_BigInteger($source);
}
$value = $source->toBytes(true);
} else {
$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 = $offset !== 8 ? $offset : 0;
@ -1087,7 +1121,12 @@ class File_ASN1
}
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;

View File

@ -37,7 +37,7 @@
* @category File
* @package File_X509
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -125,7 +125,6 @@ define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value.
*
* @package File_X509
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.1
* @access public
*/
class File_X509
@ -298,6 +297,14 @@ class File_X509
*/
var $caFlag = false;
/**
* SPKAC Challenge
*
* @var String
* @access private
*/
var $challenge;
/**
* Default Constructor.
*
@ -2166,12 +2173,12 @@ class File_X509
switch ($algorithm) {
case 'rsaEncryption':
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
// 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.
chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
'-----END PUBLIC KEY-----';
'-----END RSA PUBLIC KEY-----';
default:
return $key;
}
@ -2502,7 +2509,8 @@ class File_X509
$asn1->loadFilters($filters);
$result = '';
foreach ($dn['rdnSequence'] as $rdn) {
foreach ($rdn as &$attr) {
foreach ($rdn as $i=>$attr) {
$attr = &$rdn[$i];
if (is_array($attr['value'])) {
foreach ($attr['value'] as $type => $v) {
$type = array_search($type, $asn1->ANYmap, true);
@ -2531,7 +2539,7 @@ class File_X509
return strtolower(bin2hex(pack('N', $hash)));
}
// Defaut is to return a string.
// Default is to return a string.
$start = true;
$output = '';
$asn1 = new File_ASN1();
@ -2760,6 +2768,19 @@ class File_X509
$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
*
@ -2953,7 +2974,8 @@ class File_X509
$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;
if ($temp != false) {
$spkac = $temp;
@ -3005,6 +3027,49 @@ class File_X509
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
*
@ -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
*
@ -3149,12 +3236,10 @@ class File_X509
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
if (!empty($this->startDate)) {
$this->currentCert['tbsCertificate']['validity']['notBefore']['generalTime'] = $this->startDate;
unset($this->currentCert['tbsCertificate']['validity']['notBefore']['utcTime']);
$this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
}
if (!empty($this->endDate)) {
$this->currentCert['tbsCertificate']['validity']['notAfter']['generalTime'] = $this->endDate;
unset($this->currentCert['tbsCertificate']['validity']['notAfter']['utcTime']);
$this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
}
if (!empty($this->serialNumber)) {
$this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
@ -3176,8 +3261,8 @@ class File_X509
return false;
}
$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'));
$startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
$endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
$serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new Math_BigInteger();
$this->currentCert = array(
@ -3188,8 +3273,8 @@ class File_X509
'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, // this is going to be overwritten later
'validity' => array(
'notBefore' => array('generalTime' => $startDate), // $this->setStartDate()
'notAfter' => array('generalTime' => $endDate) // $this->setEndDate()
'notBefore' => $this->_timeField($startDate), // $this->setStartDate()
'notAfter' => $this->_timeField($endDate) // $this->setEndDate()
),
'subject' => $subject->dn,
'subjectPublicKeyInfo' => $subjectPublicKey
@ -3349,6 +3434,71 @@ class File_X509
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
*
@ -3368,7 +3518,7 @@ class File_X509
$currentCert = isset($this->currentCert) ? $this->currentCert : 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'])) {
$this->currentCert = $crl->currentCert;
@ -3381,7 +3531,7 @@ class File_X509
'version' => 'v2',
'signature' => array('algorithm' => $signatureAlgorithm),
'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),
'signature' => false // this is going to be overwritten later
@ -3390,10 +3540,10 @@ class File_X509
$tbsCertList = &$this->currentCert['tbsCertList'];
$tbsCertList['issuer'] = $issuer->dn;
$tbsCertList['thisUpdate'] = array('generalTime' => $thisUpdate);
$tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);
if (!empty($this->endDate)) {
$tbsCertList['nextUpdate'] = array('generalTime' => $this->endDate); // $this->setEndDate()
$tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate()
} else {
unset($tbsCertList['nextUpdate']);
}
@ -3516,7 +3666,7 @@ class File_X509
*/
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;
$this->endDate = new File_ASN1_Element($temp);
} 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;
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;
}
@ -4126,7 +4276,7 @@ class File_X509
//return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
return array(
'algorithm' => array('algorithm' => 'rsaEncryption'),
'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW)
'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
);
default:
return false;
@ -4214,7 +4364,7 @@ class File_X509
$i = count($rclist);
$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;
}
@ -4234,7 +4384,7 @@ class File_X509
if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
if (!empty($date)) {
$rclist[$i]['revocationDate'] = array('generalTime' => $date);
$rclist[$i]['revocationDate'] = $this->_timeField($date);
}
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
* 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.
* (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
*
@ -35,7 +31,7 @@
* Here's an example of how to use this library:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger(2);
* $b = new Math_BigInteger(3);
@ -67,7 +63,7 @@
* @category Math
* @package Math_BigInteger
* @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
* @link http://pear.php.net/package/Math_BigInteger
*/
@ -175,7 +171,6 @@ define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
*
* @package Math_BigInteger
* @author Jim Wigginton <terrafrost@php.net>
* @version 1.0.0RC4
* @access public
*/
class Math_BigInteger
@ -242,13 +237,13 @@ class Math_BigInteger
*
* Here's an example:
* <code>
* &lt;?php
* include('Math/BigInteger.php');
* <?php
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('0x32', 16); // 50 in base-16
*
* echo $a->toString(); // outputs 50
* ?&gt;
* ?>
* </code>
*
* @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')) {
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start();
phpinfo();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();
@ -283,7 +278,14 @@ class Math_BigInteger
$versions = array();
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
}
}
@ -334,9 +336,12 @@ class Math_BigInteger
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
$this->value = $x;
return;
switch (true) {
case is_resource($x) && get_resource_type($x) == 'GMP integer':
// PHP 5.6 switched GMP from using resources to objects
case is_object($x) && get_class($x) == 'GMP':
$this->value = $x;
return;
}
$this->value = gmp_init(0);
break;
@ -511,7 +516,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('65');
*
@ -608,7 +613,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('65');
*
@ -635,7 +640,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('65');
*
@ -673,7 +678,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('50');
*
@ -826,7 +831,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20');
@ -917,7 +922,7 @@ class Math_BigInteger
$value = $x_value;
}
$value[] = 0; // just in case the carry adds an extra digit
$value[count($value)] = 0; // just in case the carry adds an extra digit
$carry = 0;
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
@ -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
$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[$j] = $temp;
@ -957,7 +962,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('10');
* $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
$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[$j] = $temp;
@ -1093,7 +1098,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20');
@ -1209,7 +1214,7 @@ class Math_BigInteger
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 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);
}
@ -1222,7 +1227,7 @@ class Math_BigInteger
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
$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);
}
@ -1310,13 +1315,13 @@ class Math_BigInteger
$i2 = $i << 1;
$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);
// 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) {
$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);
}
@ -1377,7 +1382,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20');
@ -1514,9 +1519,8 @@ class Math_BigInteger
if ($x_window[0] == $y_window[0]) {
$quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
} else {
$quotient_value[$q_index] = (int) (
($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1])
/
$quotient_value[$q_index] = $this->_safe_divide(
$x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1],
$y_window[0]
);
}
@ -1584,7 +1588,7 @@ class Math_BigInteger
for ($i = count($dividend) - 1; $i >= 0; --$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]);
}
@ -1597,7 +1601,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger('10');
* $b = new Math_BigInteger('20');
@ -1722,6 +1726,11 @@ class Math_BigInteger
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?
if ( $n->value[0] & 1 ) {
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) {
$corrector_value = $this->_array_repeat(0, $n_length + 1);
$corrector_value[] = 1;
$corrector_value[count($corrector_value)] = 1;
$result = $this->_add($result, false, $corrector_value, false);
$result = $result[MATH_BIGINTEGER_VALUE];
}
@ -2196,7 +2205,7 @@ class Math_BigInteger
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
$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);
}
@ -2212,7 +2221,7 @@ class Math_BigInteger
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
$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);
}
@ -2261,7 +2270,7 @@ class Math_BigInteger
for ($i = 0; $i < $k; ++$i) {
$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 = array_merge($this->_array_repeat(0, $i), $temp);
$result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
@ -2295,6 +2304,11 @@ class Math_BigInteger
$temp = $this->_multiply($x, false, $y, false);
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(
MATH_BIGINTEGER_VARIABLE => array(),
MATH_BIGINTEGER_DATA => array()
@ -2313,9 +2327,9 @@ class Math_BigInteger
$a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
for ($i = 0; $i < $n; ++$i) {
$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 = (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);
$a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
$a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
@ -2392,7 +2406,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger(30);
* $b = new Math_BigInteger(17);
@ -2460,7 +2474,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger(693);
* $b = new Math_BigInteger(609);
@ -2595,7 +2609,7 @@ class Math_BigInteger
* Here's an example:
* <code>
* <?php
* include('Math/BigInteger.php');
* include 'Math/BigInteger.php';
*
* $a = new Math_BigInteger(693);
* $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);
$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));
}
@ -3062,8 +3076,7 @@ class Math_BigInteger
*/
function _random_number_helper($size)
{
$crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string'));
if ($crypt_random) {
if (function_exists('crypt_random_string')) {
$random = crypt_random_string($size);
} else {
$random = '';
@ -3085,19 +3098,31 @@ class Math_BigInteger
/**
* Generate a random number
*
* @param optional Integer $min
* @param optional Integer $max
* Returns a random number between $min and $max where $min and $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
* @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) {
$min = new Math_BigInteger(0);
if ($arg1 === false) {
return false;
}
if ($max === false) {
$max = new Math_BigInteger(0x7FFFFFFF);
if ($arg2 === false) {
$max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
}
$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,
* give up and return false.
*
* @param optional Integer $min
* @param optional Integer $max
* @param Math_BigInteger $arg1
* @param optional Math_BigInteger $arg2
* @param optional Integer $timeout
* @return Math_BigInteger
* @return Mixed
* @access public
* @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) {
$min = new Math_BigInteger(0);
if ($arg1 === false) {
return false;
}
if ($max === false) {
$max = new Math_BigInteger(0x7FFFFFFF);
if ($arg2 === false) {
$max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
}
$compare = $max->compare($min);
@ -3283,10 +3312,10 @@ class Math_BigInteger
* 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
* $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.
*
* @param optional Integer $t
* @param optional Math_BigInteger $t
* @return Boolean
* @access public
* @internal Uses the
@ -3455,12 +3484,12 @@ class Math_BigInteger
for ($i = 0; $i < count($this->value); ++$i) {
$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);
}
if ( $carry ) {
$this->value[] = $carry;
$this->value[count($this->value)] = $carry;
}
while ($num_digits--) {
@ -3703,4 +3732,27 @@ class Math_BigInteger
$temp = ltrim(pack('N', $length), chr(0));
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:
* <code>
* <?php
* include('Net/SCP.php');
* include('Net/SSH2.php');
* include 'Net/SCP.php';
* include 'Net/SSH2.php';
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
@ -44,7 +44,7 @@
* @category Net
* @package Net_SCP
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -83,7 +83,6 @@ define('NET_SCP_SSH2', 2);
*
* @package Net_SCP
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Net_SCP
@ -130,7 +129,7 @@ class Net_SCP
}
switch (strtolower(get_class($ssh))) {
case'net_ssh2':
case 'net_ssh2':
$this->mode = NET_SCP_SSH2;
break;
case 'net_ssh1':
@ -171,7 +170,7 @@ class Net_SCP
return false;
}
if (!$this->ssh->exec('scp -t ' . $remote_file, false)) { // -t = to
if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
return false;
}
@ -196,7 +195,6 @@ class Net_SCP
$fp = @fopen($data, 'rb');
if (!$fp) {
fclose($fp);
return false;
}
$size = filesize($data);
@ -216,7 +214,7 @@ class Net_SCP
$sent+= strlen($temp);
if (is_callable($callback)) {
$callback($sent);
call_user_func($callback, $sent);
}
}
$this->_close();
@ -246,7 +244,7 @@ class Net_SCP
return false;
}
if (!$this->ssh->exec('scp -f ' . $remote_file, false)) { // -f = from
if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
return false;
}

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@
* @category Net
* @package Net_SFTP_Stream
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -38,7 +38,6 @@
*
* @package Net_SFTP_Stream
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.3.2
* @access public
*/
class Net_SFTP_Stream
@ -49,7 +48,6 @@ class Net_SFTP_Stream
* Rather than re-create the connection we re-use instances if possible
*
* @var Array
* @access static
*/
static $instances;
@ -127,6 +125,22 @@ class Net_SFTP_Stream
*/
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
*
@ -181,24 +195,24 @@ class Net_SFTP_Stream
if (isset($this->context)) {
$context = stream_context_get_options($this->context);
}
if (isset($context['sftp']['session'])) {
$sftp = $context['sftp']['session'];
if (isset($context[$scheme]['session'])) {
$sftp = $context[$scheme]['session'];
}
if (isset($context['sftp']['sftp'])) {
$sftp = $context['sftp']['sftp'];
if (isset($context[$scheme]['sftp'])) {
$sftp = $context[$scheme]['sftp'];
}
if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') {
$this->sftp = $sftp;
return $path;
}
if (isset($context['sftp']['username'])) {
$user = $context['sftp']['username'];
if (isset($context[$scheme]['username'])) {
$user = $context[$scheme]['username'];
}
if (isset($context['sftp']['password'])) {
$pass = $context['sftp']['password'];
if (isset($context[$scheme]['password'])) {
$pass = $context[$scheme]['password'];
}
if (isset($context['sftp']['privkey']) && is_object($context['sftp']['privkey']) && get_Class($context['sftp']['privkey']) == 'Crypt_RSA') {
$pass = $context['sftp']['privkey'];
if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') {
$pass = $context[$scheme]['privkey'];
}
if (!isset($user) || !isset($pass)) {
@ -210,6 +224,7 @@ class Net_SFTP_Stream
$this->sftp = self::$instances[$host][$port][$user][(string) $pass];
} else {
$this->sftp = new Net_SFTP($host, $port);
$this->sftp->disableStatCache();
if (isset($this->notification) && is_callable($this->notification)) {
/* if !is_callable($this->notification) we could do this:
@ -517,7 +532,20 @@ class Net_SFTP_Stream
* Open directory handle
*
* 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 Integer $options
@ -770,6 +798,4 @@ class Net_SFTP_Stream
}
}
if (function_exists('stream_wrapper_register')) {
stream_wrapper_register('sftp', 'Net_SFTP_Stream');
}
Net_SFTP_Stream::register();

View File

@ -8,7 +8,7 @@
* Here's a short example of how to use this library:
* <code>
* <?php
* include('Net/SSH1.php');
* include 'Net/SSH1.php';
*
* $ssh = new Net_SSH1('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
@ -22,7 +22,7 @@
* Here's another short example:
* <code>
* <?php
* include('Net/SSH1.php');
* include 'Net/SSH1.php';
*
* $ssh = new Net_SSH1('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
@ -59,7 +59,7 @@
* @category Net
* @package Net_SSH1
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -182,8 +182,9 @@ define('NET_SSH1_RESPONSE_DATA', 2);
* @access private
*/
define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
define('NET_SSH1_MASK_LOGIN', 0x00000002);
define('NET_SSH1_MASK_SHELL', 0x00000004);
define('NET_SSH1_MASK_CONNECTED', 0x00000002);
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
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Net_SSH1
@ -458,6 +458,51 @@ class Net_SSH1
*/
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.
*
@ -506,10 +551,24 @@ class Net_SSH1
$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) {
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
return;
user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
return false;
}
$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)) {
user_error('Can only connect to SSH servers');
return;
return false;
}
if ($parts[1][0] != 1) {
user_error("Cannot connect to SSH $parts[1] servers");
return;
return false;
}
fputs($this->fsock, $this->identifier."\r\n");
@ -533,7 +592,7 @@ class Net_SSH1
$response = $this->_get_binary_packet();
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_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);
@ -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);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_SESSION_KEY');
return;
return false;
}
switch ($cipher) {
@ -645,7 +704,7 @@ class Net_SSH1
break;
//case NET_SSH1_CIPHER_RC4:
// if (!class_exists('Crypt_RC4')) {
// include_once('Crypt/RC4.php');
// include_once 'Crypt/RC4.php';
// }
// $this->crypto = new Crypt_RC4();
// $this->crypto->enableContinuousBuffer();
@ -657,10 +716,12 @@ class Net_SSH1
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_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 = '')
{
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;
}
@ -1060,6 +1128,7 @@ class Net_SSH1
$padding_length = 8 - ($temp['length'] & 7);
$length = $temp['length'] + $padding_length;
$raw = '';
while ($length > 0) {
$temp = fread($this->fsock, $length);

View File

@ -8,7 +8,7 @@
* Here are some examples of how to use this library:
* <code>
* <?php
* include('Net/SSH2.php');
* include 'Net/SSH2.php';
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
@ -22,8 +22,8 @@
*
* <code>
* <?php
* include('Crypt/RSA.php');
* include('Net/SSH2.php');
* include 'Crypt/RSA.php';
* include 'Net/SSH2.php';
*
* $key = new Crypt_RSA();
* //$key->setPassword('whatever');
@ -61,7 +61,7 @@
* @category Net
* @package Net_SSH2
* @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
* @link http://phpseclib.sourceforge.net
*/
@ -73,10 +73,11 @@
* @access private
*/
define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
define('NET_SSH2_MASK_LOGIN_REQ', 0x00000002);
define('NET_SSH2_MASK_LOGIN', 0x00000004);
define('NET_SSH2_MASK_SHELL', 0x00000008);
define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000010);
define('NET_SSH2_MASK_CONNECTED', 0x00000002);
define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004);
define('NET_SSH2_MASK_LOGIN', 0x00000008);
define('NET_SSH2_MASK_SHELL', 0x00000010);
define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020);
/**#@-*/
/**#@+
@ -145,7 +146,6 @@ define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024);
*
* @package Net_SSH2
* @author Jim Wigginton <terrafrost@php.net>
* @version 0.1.0
* @access public
*/
class Net_SSH2
@ -191,100 +191,100 @@ class Net_SSH2
* Server Identifier
*
* @see Net_SSH2::getServerIdentification()
* @var String
* @var mixed false or Array
* @access private
*/
var $server_identifier = '';
var $server_identifier = false;
/**
* Key Exchange Algorithms
*
* @see Net_SSH2::getKexAlgorithims()
* @var Array
* @var mixed false or Array
* @access private
*/
var $kex_algorithms;
var $kex_algorithms = false;
/**
* Server Host Key Algorithms
*
* @see Net_SSH2::getServerHostKeyAlgorithms()
* @var Array
* @var mixed false or Array
* @access private
*/
var $server_host_key_algorithms;
var $server_host_key_algorithms = false;
/**
* Encryption Algorithms: Client to Server
*
* @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
* @var Array
* @var mixed false or Array
* @access private
*/
var $encryption_algorithms_client_to_server;
var $encryption_algorithms_client_to_server = false;
/**
* Encryption Algorithms: Server to Client
*
* @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
* @var Array
* @var mixed false or Array
* @access private
*/
var $encryption_algorithms_server_to_client;
var $encryption_algorithms_server_to_client = false;
/**
* MAC Algorithms: Client to Server
*
* @see Net_SSH2::getMACAlgorithmsClient2Server()
* @var Array
* @var mixed false or Array
* @access private
*/
var $mac_algorithms_client_to_server;
var $mac_algorithms_client_to_server = false;
/**
* MAC Algorithms: Server to Client
*
* @see Net_SSH2::getMACAlgorithmsServer2Client()
* @var Array
* @var mixed false or Array
* @access private
*/
var $mac_algorithms_server_to_client;
var $mac_algorithms_server_to_client = false;
/**
* Compression Algorithms: Client to Server
*
* @see Net_SSH2::getCompressionAlgorithmsClient2Server()
* @var Array
* @var mixed false or Array
* @access private
*/
var $compression_algorithms_client_to_server;
var $compression_algorithms_client_to_server = false;
/**
* Compression Algorithms: Server to Client
*
* @see Net_SSH2::getCompressionAlgorithmsServer2Client()
* @var Array
* @var mixed false or Array
* @access private
*/
var $compression_algorithms_server_to_client;
var $compression_algorithms_server_to_client = false;
/**
* Languages: Server to Client
*
* @see Net_SSH2::getLanguagesServer2Client()
* @var Array
* @var mixed false or Array
* @access private
*/
var $languages_server_to_client;
var $languages_server_to_client = false;
/**
* Languages: Client to Server
*
* @see Net_SSH2::getLanguagesClient2Server()
* @var Array
* @var mixed false or Array
* @access private
*/
var $languages_client_to_server;
var $languages_client_to_server = false;
/**
* Block Size for Server to Client Encryption
@ -670,6 +670,7 @@ class Net_SSH2
/**
* Time of first network activity
*
* @var Integer
* @access private
*/
var $last_packet;
@ -685,6 +686,7 @@ class Net_SSH2
/**
* Flag to request a PTY when using exec()
*
* @var Boolean
* @see Net_SSH2::enablePTY()
* @access private
*/
@ -693,6 +695,7 @@ class Net_SSH2
/**
* Flag set while exec() is running when using enablePTY()
*
* @var Boolean
* @access private
*/
var $in_request_pty_exec = false;
@ -700,6 +703,7 @@ class Net_SSH2
/**
* Flag set after startSubsystem() is called
*
* @var Boolean
* @access private
*/
var $in_subsystem;
@ -707,6 +711,7 @@ class Net_SSH2
/**
* Contents of stdError
*
* @var String
* @access private
*/
var $stdErrorLog;
@ -715,6 +720,7 @@ class Net_SSH2
* The Last Interactive Response
*
* @see Net_SSH2::_keyboard_interactive_process()
* @var String
* @access private
*/
var $last_interactive_response = '';
@ -723,6 +729,7 @@ class Net_SSH2
* Keyboard Interactive Request / Responses
*
* @see Net_SSH2::_keyboard_interactive_process()
* @var Array
* @access private
*/
var $keyboard_requests_responses = array();
@ -735,6 +742,7 @@ class Net_SSH2
*
* @see Net_SSH2::_filter()
* @see Net_SSH2::getBannerMessage()
* @var String
* @access private
*/
var $banner_message = '';
@ -742,7 +750,8 @@ class Net_SSH2
/**
* Did read() timeout or return normally?
*
* @see Net_SSH2::isTimeout
* @see Net_SSH2::isTimeout()
* @var Boolean
* @access private
*/
var $is_timeout = false;
@ -750,7 +759,8 @@ class Net_SSH2
/**
* Log Boundary
*
* @see Net_SSH2::_format_log
* @see Net_SSH2::_format_log()
* @var String
* @access private
*/
var $log_boundary = ':';
@ -758,7 +768,8 @@ class Net_SSH2
/**
* Log Long Width
*
* @see Net_SSH2::_format_log
* @see Net_SSH2::_format_log()
* @var Integer
* @access private
*/
var $log_long_width = 65;
@ -766,19 +777,76 @@ class Net_SSH2
/**
* Log Short Width
*
* @see Net_SSH2::_format_log
* @see Net_SSH2::_format_log()
* @var Integer
* @access private
*/
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 optional Integer $port
* @param optional Integer $timeout
* @see Net_SSH2::login()
* @return Net_SSH2
* @access public
*/
@ -798,7 +866,6 @@ class Net_SSH2
include_once 'Crypt/Hash.php';
}
$this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5
$this->message_numbers = array(
1 => 'NET_SSH2_MSG_DISCONNECT',
2 => 'NET_SSH2_MSG_IGNORE',
@ -869,19 +936,43 @@ class Net_SSH2
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
$this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $timeout);
if (!$this->fsock) {
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
return;
return false;
}
$elapsed = strtok(microtime(), ' ') + strtok('') - $start;
$timeout-= $elapsed;
if ($timeout <= 0) {
user_error(rtrim("Cannot connect to $host. Timeout error"));
return;
user_error("Cannot connect to $host. Timeout error");
return false;
}
$read = array($this->fsock);
@ -893,8 +984,8 @@ class Net_SSH2
// on windows this returns a "Warning: Invalid CRT parameters detected" error
// the !count() is done as a workaround for <https://bugs.php.net/42682>
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
user_error(rtrim("Cannot connect to $host. Banner timeout"));
return;
user_error("Cannot connect to $host. Banner timeout");
return false;
}
/* According to the SSH2 specs,
@ -933,7 +1024,7 @@ class Net_SSH2
if ($matches[1] != '1.99' && $matches[1] != '2.0') {
user_error("Cannot connect to SSH $matches[1] servers");
return;
return false;
}
fputs($this->fsock, $this->identifier . "\r\n");
@ -941,19 +1032,21 @@ class Net_SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return;
return false;
}
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
user_error('Expected SSH_MSG_KEXINIT');
return;
return false;
}
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',
'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>:
'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-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('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('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('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('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('3des-ctr', '3des-cbc')
@ -1075,12 +1168,15 @@ class Net_SSH2
$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', // 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', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
'none' // OPTIONAL no MAC; NOT RECOMMENDED
//'none' // OPTIONAL no MAC; NOT RECOMMENDED
);
static $compression_algorithms = array(
@ -1605,6 +1701,10 @@ class Net_SSH2
$createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
switch ($mac_algorithms[$i]) {
case 'hmac-sha2-256':
$this->hmac_create = new Crypt_Hash('sha256');
$createKeyLength = 32;
break;
case 'hmac-sha1':
$this->hmac_create = new Crypt_Hash('sha1');
$createKeyLength = 20;
@ -1631,6 +1731,11 @@ class Net_SSH2
$checkKeyLength = 0;
$this->hmac_size = 0;
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':
$this->hmac_check = new Crypt_Hash('sha1');
$checkKeyLength = 20;
@ -1711,6 +1816,12 @@ class Net_SSH2
*/
function _login($username)
{
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}
$args = array_slice(func_get_args(), 1);
if (empty($args)) {
return $this->_login_helper($username);
@ -1736,7 +1847,7 @@ class Net_SSH2
*/
function _login_helper($username, $password = null)
{
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
if (!($this->bitmap & NET_SSH2_MASK_CONNECTED)) {
return false;
}
@ -1968,7 +2079,6 @@ class Net_SSH2
if (!count($responses) && $num_prompts) {
$this->last_interactive_response = $orig;
$this->bitmap |= NET_SSH_MASK_LOGIN_INTERACTIVE;
return false;
}
@ -2151,11 +2261,11 @@ class Net_SSH2
/**
* Execute Command
*
* If $block is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually.
* If $callback is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually.
* In all likelihood, this is not a feature you want to be taking advantage of.
*
* @param String $command
* @param optional Boolean $block
* @param optional Callback $callback
* @return String
* @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,
// 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
$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
// uses 0x4000, that's what will be used here, as well.
$packet_size = 0x4000;
@ -2196,7 +2306,7 @@ class Net_SSH2
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack('CNNa*CNa*N5a*',
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_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)) {
return false;
@ -2258,7 +2368,10 @@ class Net_SSH2
return false;
default:
if (is_callable($callback)) {
$callback($temp);
if (call_user_func($callback, $temp) === true) {
$this->_close_channel(NET_SSH2_CHANNEL_EXEC);
return true;
}
} else {
$output.= $temp;
}
@ -2280,7 +2393,7 @@ class Net_SSH2
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 = pack('CNa*N3',
@ -2300,7 +2413,7 @@ class Net_SSH2
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack('CNNa*CNa*N5a*',
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100',
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)) {
return false;
@ -2557,11 +2670,12 @@ class Net_SSH2
/**
* Is the connection still active?
*
* @return boolean
* @access public
*/
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 = '';
while ($remaining_length > 0) {
$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;
$remaining_length-= strlen($temp);
}
@ -2624,7 +2743,11 @@ class Net_SSH2
if ($this->hmac_check !== false) {
$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');
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
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);
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$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
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])) {
case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
$this->_string_shift($payload, 1);
@ -2763,6 +2886,20 @@ class Net_SSH2
$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()
*
@ -2783,6 +2920,20 @@ class Net_SSH2
$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
*
@ -2834,7 +2985,7 @@ class Net_SSH2
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
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
extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
$data = $this->_string_shift($response, $length);
$this->stdErrorLog .= $data;
$this->stdErrorLog.= $data;
if ($skip_extended || $this->quiet_mode) {
break;
}
@ -3124,54 +3275,37 @@ class Net_SSH2
*/
function _send_channel_packet($client_channel, $data)
{
/* The maximum amount of data allowed is determined by the maximum
packet size for the channel, and the current window size, whichever
is smaller.
-- http://tools.ietf.org/html/rfc4254#section-5.2 */
$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
) - 4;
while (strlen($data) > $max_size) {
while (strlen($data)) {
if (!$this->window_size_client_to_server[$client_channel]) {
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
// using an invalid channel will let the buffers be built up for the valid channels
$output = $this->_get_channel_packet(-1);
$this->_get_channel_packet(-1);
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
) - 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*',
NET_SSH2_MSG_CHANNEL_DATA,
$this->server_channels[$client_channel],
$max_size,
$this->_string_shift($data, $max_size)
strlen($temp),
$temp
);
$this->window_size_client_to_server[$client_channel]-= $max_size + 4;
$this->window_size_client_to_server[$client_channel]-= strlen($temp);
if (!$this->_send_binary_packet($packet)) {
return false;
}
}
if (strlen($data) >= $this->window_size_client_to_server[$client_channel] - 4) {
$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));
return true;
}
/**
@ -3220,7 +3354,7 @@ class Net_SSH2
*/
function _disconnect($reason)
{
if ($this->bitmap) {
if ($this->bitmap & NET_SSH2_MASK_CONNECTED) {
$data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
$this->_send_binary_packet($data);
$this->bitmap = 0;
@ -3374,6 +3508,8 @@ class Net_SSH2
*/
function getServerIdentification()
{
$this->_connect();
return $this->server_identifier;
}
@ -3385,6 +3521,8 @@ class Net_SSH2
*/
function getKexAlgorithms()
{
$this->_connect();
return $this->kex_algorithms;
}
@ -3396,6 +3534,8 @@ class Net_SSH2
*/
function getServerHostKeyAlgorithms()
{
$this->_connect();
return $this->server_host_key_algorithms;
}
@ -3407,6 +3547,8 @@ class Net_SSH2
*/
function getEncryptionAlgorithmsClient2Server()
{
$this->_connect();
return $this->encryption_algorithms_client_to_server;
}
@ -3418,6 +3560,8 @@ class Net_SSH2
*/
function getEncryptionAlgorithmsServer2Client()
{
$this->_connect();
return $this->encryption_algorithms_server_to_client;
}
@ -3429,6 +3573,8 @@ class Net_SSH2
*/
function getMACAlgorithmsClient2Server()
{
$this->_connect();
return $this->mac_algorithms_client_to_server;
}
@ -3440,6 +3586,8 @@ class Net_SSH2
*/
function getMACAlgorithmsServer2Client()
{
$this->_connect();
return $this->mac_algorithms_server_to_client;
}
@ -3451,6 +3599,8 @@ class Net_SSH2
*/
function getCompressionAlgorithmsClient2Server()
{
$this->_connect();
return $this->compression_algorithms_client_to_server;
}
@ -3462,6 +3612,8 @@ class Net_SSH2
*/
function getCompressionAlgorithmsServer2Client()
{
$this->_connect();
return $this->compression_algorithms_server_to_client;
}
@ -3473,6 +3625,8 @@ class Net_SSH2
*/
function getLanguagesServer2Client()
{
$this->_connect();
return $this->languages_server_to_client;
}
@ -3484,6 +3638,8 @@ class Net_SSH2
*/
function getLanguagesClient2Server()
{
$this->_connect();
return $this->languages_client_to_server;
}
@ -3512,6 +3668,12 @@ class Net_SSH2
*/
function getServerPublicHostKey()
{
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}
$signature = $this->signature;
$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);
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
$nLength = $temp['length'];
$rawN = $this->_string_shift($server_public_host_key, $temp['length']);
$n = new Math_BigInteger($rawN, -256);
$nLength = strlen(ltrim($rawN, "\0"));
/*
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
@ -3627,7 +3790,7 @@ class Net_SSH2
$s = $s->toBytes();
$h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h;
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) {
user_error('Bad server signature');
@ -3657,30 +3820,59 @@ class Net_SSH2
}
/**
* Is a path includable?
* Returns the number of columns for the terminal window size.
*
* @return Boolean
* @access private
* @return Integer
* @access public
*/
function _is_includable($suffix)
function getWindowColumns()
{
// stream_resolve_include_path was introduced in PHP 5.3.2
if (function_exists('stream_resolve_include_path')) {
return stream_resolve_include_path($suffix) !== false;
}
return $this->windowColumns;
}
$paths = PATH_SEPARATOR == ':' ?
preg_split('#(?<!phar):#', get_include_path()) :
explode(PATH_SEPARATOR, get_include_path());
foreach ($paths as $prefix) {
$ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR;
$file = $prefix . $ds . $suffix;
/**
* Returns the number of rows for the terminal window size.
*
* @return Integer
* @access public
*/
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
/**
* Pure-PHP ssh-agent client.
* Pure-PHP ssh-agent client wrapper
*
* 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>
* Originally System_SSH_Agent was accessed as System/SSH_Agent.php instead of
* System/SSH/Agent.php. The problem with this is that PSR0 compatible autoloaders
* don't support that kind of directory layout hence the package being moved and
* this "alias" being created to maintain backwards compatibility.
*
* 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
@ -43,273 +30,10 @@
* @category System
* @package System_SSH_Agent
* @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
* @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>
* @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;
}
}
require_once 'SSH/Agent.php';