Update PHPseclib
This commit is contained in:
parent
f6857e6c0c
commit
8e7ec31de0
451
Crypt/AES.php
451
Crypt/AES.php
@ -1,16 +1,15 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of AES.
|
||||
*
|
||||
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
||||
* Uses mcrypt, if available/possible, and an internal implementation, otherwise.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
|
||||
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
|
||||
* it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()}
|
||||
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()}
|
||||
* is called, again, at which point, it'll be recalculated.
|
||||
*
|
||||
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
|
||||
@ -20,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();
|
||||
*
|
||||
@ -42,10 +41,10 @@
|
||||
* 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
|
||||
@ -54,19 +53,19 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_AES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVIII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Crypt
|
||||
* @package Crypt_AES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVIII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* Include Crypt_Rijndael
|
||||
*/
|
||||
if (!class_exists('Crypt_Rijndael')) {
|
||||
require_once 'Rijndael.php';
|
||||
include_once 'Rijndael.php';
|
||||
}
|
||||
|
||||
/**#@+
|
||||
@ -81,172 +80,71 @@ if (!class_exists('Crypt_Rijndael')) {
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CTR', -1);
|
||||
define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
|
||||
/**
|
||||
* Encrypt / decrypt using the Electronic Code Book mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_ECB', 1);
|
||||
define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Code Book Chaining mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CBC', 2);
|
||||
define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CFB', 3);
|
||||
define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_OFB', 4);
|
||||
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_AES::Crypt_AES()
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_AES_MODE_INTERNAL', 1);
|
||||
define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_AES_MODE_MCRYPT', 2);
|
||||
define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of AES.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.1.0
|
||||
* @access public
|
||||
* @package Crypt_AES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_AES extends Crypt_Rijndael {
|
||||
class Crypt_AES extends Crypt_Rijndael
|
||||
{
|
||||
/**
|
||||
* mcrypt resource for encryption
|
||||
* The namespace used by the cipher for its constants.
|
||||
*
|
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
||||
*
|
||||
* @see Crypt_AES::encrypt()
|
||||
* @see Crypt_Base::const_namespace
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $enmcrypt;
|
||||
|
||||
/**
|
||||
* mcrypt resource for decryption
|
||||
*
|
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
||||
*
|
||||
* @see Crypt_AES::decrypt()
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $demcrypt;
|
||||
|
||||
/**
|
||||
* mcrypt resource for CFB mode
|
||||
*
|
||||
* @see Crypt_AES::encrypt()
|
||||
* @see Crypt_AES::decrypt()
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $ecb;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
||||
* CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
|
||||
*
|
||||
* @param optional Integer $mode
|
||||
* @return Crypt_AES
|
||||
* @access public
|
||||
*/
|
||||
function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
|
||||
{
|
||||
if ( !defined('CRYPT_AES_MODE') ) {
|
||||
switch (true) {
|
||||
case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()):
|
||||
define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
|
||||
}
|
||||
}
|
||||
|
||||
switch ( CRYPT_AES_MODE ) {
|
||||
case CRYPT_AES_MODE_MCRYPT:
|
||||
switch ($mode) {
|
||||
case CRYPT_AES_MODE_ECB:
|
||||
$this->paddable = true;
|
||||
$this->mode = MCRYPT_MODE_ECB;
|
||||
break;
|
||||
case CRYPT_AES_MODE_CTR:
|
||||
// ctr doesn't have a constant associated with it even though it appears to be fairly widely
|
||||
// supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
|
||||
// include a compatibility layer. the layer has been implemented but, for now, is commented out.
|
||||
$this->mode = 'ctr';
|
||||
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
|
||||
break;
|
||||
case CRYPT_AES_MODE_CFB:
|
||||
$this->mode = 'ncfb';
|
||||
break;
|
||||
case CRYPT_AES_MODE_OFB:
|
||||
$this->mode = MCRYPT_MODE_NOFB;
|
||||
break;
|
||||
case CRYPT_AES_MODE_CBC:
|
||||
default:
|
||||
$this->paddable = true;
|
||||
$this->mode = MCRYPT_MODE_CBC;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
switch ($mode) {
|
||||
case CRYPT_AES_MODE_ECB:
|
||||
$this->paddable = true;
|
||||
$this->mode = CRYPT_RIJNDAEL_MODE_ECB;
|
||||
break;
|
||||
case CRYPT_AES_MODE_CTR:
|
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CTR;
|
||||
break;
|
||||
case CRYPT_AES_MODE_CFB:
|
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CFB;
|
||||
break;
|
||||
case CRYPT_AES_MODE_OFB:
|
||||
$this->mode = CRYPT_RIJNDAEL_MODE_OFB;
|
||||
break;
|
||||
case CRYPT_AES_MODE_CBC:
|
||||
default:
|
||||
$this->paddable = true;
|
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
|
||||
}
|
||||
}
|
||||
|
||||
if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
|
||||
parent::Crypt_Rijndael($this->mode);
|
||||
}
|
||||
|
||||
}
|
||||
var $const_namespace = 'AES';
|
||||
|
||||
/**
|
||||
* Dummy function
|
||||
*
|
||||
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
|
||||
*
|
||||
* @see Crypt_Rijndael::setBlockLength()
|
||||
* @access public
|
||||
* @param Integer $length
|
||||
*/
|
||||
@ -256,285 +154,54 @@ class Crypt_AES extends Crypt_Rijndael {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initialization vector. (optional)
|
||||
* Sets the key length
|
||||
*
|
||||
* SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
|
||||
* to be all zero's.
|
||||
* 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 String $iv
|
||||
* @param Integer $length
|
||||
*/
|
||||
function setIV($iv)
|
||||
function setKeyLength($length)
|
||||
{
|
||||
parent::setIV($iv);
|
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
||||
$this->changed = true;
|
||||
switch ($length) {
|
||||
case 160:
|
||||
$length = 192;
|
||||
break;
|
||||
case 224:
|
||||
$length = 256;
|
||||
}
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a message.
|
||||
* Sets the key.
|
||||
*
|
||||
* $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
|
||||
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
|
||||
* URL:
|
||||
* Rijndael supports five different key lengths, AES only supports three.
|
||||
*
|
||||
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
||||
*
|
||||
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
||||
* strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
|
||||
* length.
|
||||
*
|
||||
* @see Crypt_AES::decrypt()
|
||||
* @see Crypt_Rijndael:setKey()
|
||||
* @see setKeyLength()
|
||||
* @access public
|
||||
* @param String $plaintext
|
||||
* @param String $key
|
||||
*/
|
||||
function encrypt($plaintext)
|
||||
function setKey($key)
|
||||
{
|
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
||||
$this->_mcryptSetup();
|
||||
|
||||
// re: http://phpseclib.sourceforge.net/cfb-demo.phps
|
||||
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
|
||||
// rewritten CFB implementation the above outputs the same thing twice.
|
||||
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
||||
$iv = &$this->encryptIV;
|
||||
$pos = &$this->enbuffer['pos'];
|
||||
$len = strlen($plaintext);
|
||||
$ciphertext = '';
|
||||
$i = 0;
|
||||
if ($pos) {
|
||||
$orig_pos = $pos;
|
||||
$max = 16 - $pos;
|
||||
if ($len >= $max) {
|
||||
$i = $max;
|
||||
$len-= $max;
|
||||
$pos = 0;
|
||||
} else {
|
||||
$i = $len;
|
||||
$pos+= $len;
|
||||
$len = 0;
|
||||
}
|
||||
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
||||
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
||||
$this->enbuffer['enmcrypt_init'] = true;
|
||||
}
|
||||
if ($len >= 16) {
|
||||
if ($this->enbuffer['enmcrypt_init'] === false || $len > 280) {
|
||||
if ($this->enbuffer['enmcrypt_init'] === true) {
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
||||
$this->enbuffer['enmcrypt_init'] = false;
|
||||
}
|
||||
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16));
|
||||
$iv = substr($ciphertext, -16);
|
||||
$len%= 16;
|
||||
} else {
|
||||
while ($len >= 16) {
|
||||
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16);
|
||||
$ciphertext.= $iv;
|
||||
$len-= 16;
|
||||
$i+= 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($len) {
|
||||
$iv = mcrypt_generic($this->ecb, $iv);
|
||||
$block = $iv ^ substr($plaintext, -$len);
|
||||
$iv = substr_replace($iv, $block, 0, $len);
|
||||
$ciphertext.= $block;
|
||||
$pos = $len;
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
if ($this->paddable) {
|
||||
$plaintext = $this->_pad($plaintext);
|
||||
}
|
||||
|
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
return parent::encrypt($plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a message.
|
||||
*
|
||||
* If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
|
||||
*
|
||||
* @see Crypt_AES::encrypt()
|
||||
* @access public
|
||||
* @param String $ciphertext
|
||||
*/
|
||||
function decrypt($ciphertext)
|
||||
{
|
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
||||
$this->_mcryptSetup();
|
||||
|
||||
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
||||
$iv = &$this->decryptIV;
|
||||
$pos = &$this->debuffer['pos'];
|
||||
$len = strlen($ciphertext);
|
||||
$plaintext = '';
|
||||
$i = 0;
|
||||
if ($pos) {
|
||||
$orig_pos = $pos;
|
||||
$max = 16 - $pos;
|
||||
if ($len >= $max) {
|
||||
$i = $max;
|
||||
$len-= $max;
|
||||
$pos = 0;
|
||||
} else {
|
||||
$i = $len;
|
||||
$pos+= $len;
|
||||
$len = 0;
|
||||
}
|
||||
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
|
||||
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
||||
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
||||
}
|
||||
if ($len >= 16) {
|
||||
$cb = substr($ciphertext, $i, $len - $len % 16);
|
||||
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
||||
$iv = substr($cb, -16);
|
||||
$len%= 16;
|
||||
}
|
||||
if ($len) {
|
||||
$iv = mcrypt_generic($this->ecb, $iv);
|
||||
$plaintext.= $iv ^ substr($ciphertext, -$len);
|
||||
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
|
||||
$pos = $len;
|
||||
}
|
||||
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
if ($this->paddable) {
|
||||
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
||||
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
||||
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
|
||||
}
|
||||
|
||||
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
||||
}
|
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
}
|
||||
|
||||
return parent::decrypt($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup mcrypt
|
||||
*
|
||||
* Validates all the variables.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _mcryptSetup()
|
||||
{
|
||||
if (!$this->changed) {
|
||||
return;
|
||||
}
|
||||
parent::setKey($key);
|
||||
|
||||
if (!$this->explicit_key_length) {
|
||||
// this just copied from Crypt_Rijndael::_setup()
|
||||
$length = strlen($this->key) >> 2;
|
||||
if ($length > 8) {
|
||||
$length = 8;
|
||||
} else if ($length < 4) {
|
||||
$length = 4;
|
||||
$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->Nk = $length;
|
||||
$this->key_size = $length << 2;
|
||||
}
|
||||
|
||||
switch ($this->Nk) {
|
||||
case 4: // 128
|
||||
$this->key_size = 16;
|
||||
break;
|
||||
case 5: // 160
|
||||
case 6: // 192
|
||||
$this->key_size = 24;
|
||||
break;
|
||||
case 7: // 224
|
||||
case 8: // 256
|
||||
$this->key_size = 32;
|
||||
}
|
||||
|
||||
$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
|
||||
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
|
||||
|
||||
if (!isset($this->enmcrypt)) {
|
||||
$mode = $this->mode;
|
||||
//$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
|
||||
|
||||
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
||||
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
||||
|
||||
if ($mode == 'ncfb') {
|
||||
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
|
||||
}
|
||||
|
||||
} // else should mcrypt_generic_deinit be called?
|
||||
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
||||
|
||||
if ($this->mode == 'ncfb') {
|
||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
||||
}
|
||||
|
||||
$this->changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat consecutive "packets" as if they are a continuous buffer.
|
||||
*
|
||||
* The default behavior.
|
||||
*
|
||||
* @see Crypt_Rijndael::disableContinuousBuffer()
|
||||
* @access public
|
||||
*/
|
||||
function enableContinuousBuffer()
|
||||
{
|
||||
parent::enableContinuousBuffer();
|
||||
|
||||
if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
|
||||
$this->enbuffer['enmcrypt_init'] = true;
|
||||
$this->debuffer['demcrypt_init'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat consecutive packets as if they are a discontinuous buffer.
|
||||
*
|
||||
* The default behavior.
|
||||
*
|
||||
* @see Crypt_Rijndael::enableContinuousBuffer()
|
||||
* @access public
|
||||
*/
|
||||
function disableContinuousBuffer()
|
||||
{
|
||||
parent::disableContinuousBuffer();
|
||||
|
||||
if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
||||
$this->_setupEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: ts=4:sw=4:et:
|
||||
// vim6: fdl=1:
|
||||
|
2011
Crypt/Base.php
Executable file
2011
Crypt/Base.php
Executable file
File diff suppressed because it is too large
Load Diff
1210
Crypt/Blowfish.php
1210
Crypt/Blowfish.php
File diff suppressed because it is too large
Load Diff
1800
Crypt/DES.php
1800
Crypt/DES.php
File diff suppressed because it is too large
Load Diff
@ -1,25 +1,24 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* {@internal The variable names are the same as those in
|
||||
* {@internal The variable names are the same as those in
|
||||
* {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
|
||||
*
|
||||
* 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');
|
||||
*
|
||||
@ -35,10 +34,10 @@
|
||||
* 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
|
||||
@ -47,12 +46,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_Hash
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Crypt
|
||||
* @package Crypt_Hash
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
@ -76,12 +75,21 @@ define('CRYPT_HASH_MODE_HASH', 3);
|
||||
/**
|
||||
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.1.0
|
||||
* @access public
|
||||
* @package Crypt_Hash
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_Hash {
|
||||
class Crypt_Hash
|
||||
{
|
||||
/**
|
||||
* Hash Parameter
|
||||
*
|
||||
* @see Crypt_Hash::setHash()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $hashParam;
|
||||
|
||||
/**
|
||||
* Byte-length of compression blocks / key (Internal HMAC)
|
||||
*
|
||||
@ -174,6 +182,19 @@ class Crypt_Hash {
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hash function.
|
||||
*
|
||||
* As set by the constructor or by the setHash() method.
|
||||
*
|
||||
* @access public
|
||||
* @return String
|
||||
*/
|
||||
function getHash()
|
||||
{
|
||||
return $this->hashParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hash function.
|
||||
*
|
||||
@ -182,10 +203,13 @@ class Crypt_Hash {
|
||||
*/
|
||||
function setHash($hash)
|
||||
{
|
||||
$hash = strtolower($hash);
|
||||
$this->hashParam = $hash = strtolower($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':
|
||||
@ -222,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;
|
||||
}
|
||||
@ -237,7 +259,6 @@ class Crypt_Hash {
|
||||
case CRYPT_HASH_MODE_HASH:
|
||||
switch ($hash) {
|
||||
case 'md5':
|
||||
case 'md5-96':
|
||||
$this->hash = 'md5';
|
||||
return;
|
||||
case 'md2':
|
||||
@ -247,7 +268,6 @@ class Crypt_Hash {
|
||||
$this->hash = $hash;
|
||||
return;
|
||||
case 'sha1':
|
||||
case 'sha1-96':
|
||||
default:
|
||||
$this->hash = 'sha1';
|
||||
}
|
||||
@ -260,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;
|
||||
@ -274,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');
|
||||
@ -559,7 +577,7 @@ class Crypt_Hash {
|
||||
function _sha512($m)
|
||||
{
|
||||
if (!class_exists('Math_BigInteger')) {
|
||||
require_once('Math/BigInteger.php');
|
||||
include_once 'Math/BigInteger.php';
|
||||
}
|
||||
|
||||
static $init384, $init512, $k;
|
||||
@ -567,11 +585,11 @@ class Crypt_Hash {
|
||||
if (!isset($k)) {
|
||||
// Initialize variables
|
||||
$init384 = array( // initial values for SHA384
|
||||
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
|
||||
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
|
||||
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
|
||||
);
|
||||
$init512 = array( // initial values for SHA512
|
||||
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
|
||||
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
|
||||
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
|
||||
);
|
||||
|
||||
|
652
Crypt/RC2.php
Executable file
652
Crypt/RC2.php
Executable file
@ -0,0 +1,652 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of RC2.
|
||||
*
|
||||
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* Useful resources are as follows:
|
||||
*
|
||||
* - {@link http://tools.ietf.org/html/rfc2268}
|
||||
*
|
||||
* Here's a short example of how to use this library:
|
||||
* <code>
|
||||
* <?php
|
||||
* include 'Crypt/RC2.php';
|
||||
*
|
||||
* $rc2 = new Crypt_RC2();
|
||||
*
|
||||
* $rc2->setKey('abcdefgh');
|
||||
*
|
||||
* $plaintext = str_repeat('a', 1024);
|
||||
*
|
||||
* echo $rc2->decrypt($rc2->encrypt($plaintext));
|
||||
* ?>
|
||||
* </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 Crypt
|
||||
* @package Crypt_RC2
|
||||
* @author Patrick Monnerat <pm@datasphere.ch>
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* Include Crypt_Base
|
||||
*
|
||||
* Base cipher class
|
||||
*/
|
||||
if (!class_exists('Crypt_Base')) {
|
||||
include_once 'Base.php';
|
||||
}
|
||||
|
||||
/**#@+
|
||||
* @access public
|
||||
* @see Crypt_RC2::encrypt()
|
||||
* @see Crypt_RC2::decrypt()
|
||||
*/
|
||||
/**
|
||||
* Encrypt / decrypt using the Counter mode.
|
||||
*
|
||||
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR);
|
||||
/**
|
||||
* Encrypt / decrypt using the Electronic Code Book mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Code Book Chaining mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_RC2::Crypt_RC2()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of RC2.
|
||||
*
|
||||
* @package Crypt_RC2
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_RC2 extends Crypt_Base
|
||||
{
|
||||
/**
|
||||
* Block Length of the cipher
|
||||
*
|
||||
* @see Crypt_Base::block_size
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $block_size = 8;
|
||||
|
||||
/**
|
||||
* The Key
|
||||
*
|
||||
* @see Crypt_Base::key
|
||||
* @see setKey()
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $key = "\0";
|
||||
|
||||
/**
|
||||
* The default password key_size used by setPassword()
|
||||
*
|
||||
* @see Crypt_Base::password_key_size
|
||||
* @see Crypt_Base::setPassword()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $password_key_size = 16; // = 128 bits
|
||||
|
||||
/**
|
||||
* The namespace used by the cipher for its constants.
|
||||
*
|
||||
* @see Crypt_Base::const_namespace
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $const_namespace = 'RC2';
|
||||
|
||||
/**
|
||||
* The mcrypt specific name of the cipher
|
||||
*
|
||||
* @see Crypt_Base::cipher_name_mcrypt
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $cipher_name_mcrypt = 'rc2';
|
||||
|
||||
/**
|
||||
* Optimizing value while CFB-encrypting
|
||||
*
|
||||
* @see Crypt_Base::cfb_init_len
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $cfb_init_len = 500;
|
||||
|
||||
/**
|
||||
* The key length in bits.
|
||||
*
|
||||
* @see Crypt_RC2::setKeyLength()
|
||||
* @see Crypt_RC2::setKey()
|
||||
* @var Integer
|
||||
* @access private
|
||||
* @internal Should be in range [1..1024].
|
||||
* @internal Changing this value after setting the key has no effect.
|
||||
*/
|
||||
var $default_key_length = 1024;
|
||||
|
||||
/**
|
||||
* The Key Schedule
|
||||
*
|
||||
* @see Crypt_RC2::_setupKey()
|
||||
* @var Array
|
||||
* @access private
|
||||
*/
|
||||
var $keys;
|
||||
|
||||
/**
|
||||
* Key expansion randomization table.
|
||||
* Twice the same 256-value sequence to save a modulus in key expansion.
|
||||
*
|
||||
* @see Crypt_RC2::setKey()
|
||||
* @var Array
|
||||
* @access private
|
||||
*/
|
||||
var $pitable = array(
|
||||
0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
|
||||
0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
|
||||
0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
|
||||
0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
|
||||
0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
|
||||
0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
|
||||
0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
|
||||
0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
|
||||
0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
|
||||
0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
|
||||
0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
|
||||
0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
|
||||
0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
|
||||
0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
|
||||
0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
|
||||
0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
|
||||
0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
|
||||
0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
|
||||
0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
|
||||
0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
|
||||
0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
|
||||
0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
|
||||
0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
|
||||
0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
|
||||
0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
|
||||
0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
|
||||
0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
|
||||
0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
|
||||
0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
|
||||
0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
|
||||
0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
|
||||
0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
|
||||
0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
|
||||
0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
|
||||
0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
|
||||
0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
|
||||
0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
|
||||
0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
|
||||
0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
|
||||
0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
|
||||
0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
|
||||
0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
|
||||
0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
|
||||
0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
|
||||
0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
|
||||
0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
|
||||
0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
|
||||
0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
|
||||
0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
|
||||
0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
|
||||
0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
|
||||
0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
|
||||
0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
|
||||
0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
|
||||
0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
|
||||
0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
|
||||
0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
|
||||
0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
|
||||
0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
|
||||
0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
|
||||
0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
|
||||
0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
|
||||
0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
|
||||
0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
|
||||
);
|
||||
|
||||
/**
|
||||
* Inverse key expansion randomization table.
|
||||
*
|
||||
* @see Crypt_RC2::setKey()
|
||||
* @var Array
|
||||
* @access private
|
||||
*/
|
||||
var $invpitable = array(
|
||||
0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
|
||||
0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
|
||||
0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
|
||||
0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
|
||||
0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
|
||||
0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
|
||||
0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
|
||||
0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
|
||||
0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
|
||||
0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
|
||||
0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
|
||||
0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
|
||||
0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
|
||||
0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
|
||||
0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
|
||||
0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
|
||||
0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
|
||||
0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
|
||||
0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
|
||||
0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
|
||||
0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
|
||||
0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
|
||||
0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
|
||||
0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
|
||||
0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
|
||||
0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
|
||||
0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
|
||||
0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
|
||||
0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
|
||||
0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
|
||||
0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
|
||||
0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
|
||||
);
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* Determines whether or not the mcrypt extension should be used.
|
||||
*
|
||||
* $mode could be:
|
||||
*
|
||||
* - CRYPT_RC2_MODE_ECB
|
||||
*
|
||||
* - CRYPT_RC2_MODE_CBC
|
||||
*
|
||||
* - CRYPT_RC2_MODE_CTR
|
||||
*
|
||||
* - CRYPT_RC2_MODE_CFB
|
||||
*
|
||||
* - CRYPT_RC2_MODE_OFB
|
||||
*
|
||||
* If not explicitly set, CRYPT_RC2_MODE_CBC will be used.
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param optional Integer $mode
|
||||
* @access public
|
||||
*/
|
||||
function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC)
|
||||
{
|
||||
parent::Crypt_Base($mode);
|
||||
$this->setKey('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length
|
||||
*
|
||||
* Valid key lengths are 1 to 1024.
|
||||
* Calling this function after setting the key has no effect until the next
|
||||
* Crypt_RC2::setKey() call.
|
||||
*
|
||||
* @access public
|
||||
* @param Integer $length in bits
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
if ($length >= 1 && $length <= 1024) {
|
||||
$this->default_key_length = $length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Keys can be of any length. RC2, itself, uses 1 to 1024 bit keys (eg.
|
||||
* strlen($key) <= 128), however, we only use the first 128 bytes if $key
|
||||
* has more then 128 bytes in it, and set $key to a single null byte if
|
||||
* it is empty.
|
||||
*
|
||||
* If the key is not explicitly set, it'll be assumed to be a single
|
||||
* null byte.
|
||||
*
|
||||
* @see Crypt_Base::setKey()
|
||||
* @access public
|
||||
* @param String $key
|
||||
* @param Integer $t1 optional Effective key length in bits.
|
||||
*/
|
||||
function setKey($key, $t1 = 0)
|
||||
{
|
||||
if ($t1 <= 0) {
|
||||
$t1 = $this->default_key_length;
|
||||
} else if ($t1 > 1024) {
|
||||
$t1 = 1024;
|
||||
}
|
||||
// Key byte count should be 1..128.
|
||||
$key = strlen($key) ? substr($key, 0, 128) : "\x00";
|
||||
$t = strlen($key);
|
||||
|
||||
// The mcrypt RC2 implementation only supports effective key length
|
||||
// of 1024 bits. It is however possible to handle effective key
|
||||
// lengths in range 1..1024 by expanding the key and applying
|
||||
// inverse pitable mapping to the first byte before submitting it
|
||||
// to mcrypt.
|
||||
|
||||
// Key expansion.
|
||||
$l = array_values(unpack('C*', $key));
|
||||
$t8 = ($t1 + 7) >> 3;
|
||||
$tm = 0xFF >> (8 * $t8 - $t1);
|
||||
|
||||
// Expand key.
|
||||
$pitable = $this->pitable;
|
||||
for ($i = $t; $i < 128; $i++) {
|
||||
$l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
|
||||
}
|
||||
$i = 128 - $t8;
|
||||
$l[$i] = $pitable[$l[$i] & $tm];
|
||||
while ($i--) {
|
||||
$l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
|
||||
}
|
||||
|
||||
// Prepare the key for mcrypt.
|
||||
$l[0] = $this->invpitable[$l[0]];
|
||||
array_unshift($l, 'C*');
|
||||
parent::setKey(call_user_func_array('pack', $l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a block
|
||||
*
|
||||
* @see Crypt_Base::_encryptBlock()
|
||||
* @see Crypt_Base::encrypt()
|
||||
* @access private
|
||||
* @param String $in
|
||||
* @return String
|
||||
*/
|
||||
function _encryptBlock($in)
|
||||
{
|
||||
list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
|
||||
$keys = $this->keys;
|
||||
$limit = 20;
|
||||
$actions = array($limit => 44, 44 => 64);
|
||||
$j = 0;
|
||||
|
||||
for (;;) {
|
||||
// Mixing round.
|
||||
$r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
|
||||
$r0 |= $r0 >> 16;
|
||||
$r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
|
||||
$r1 |= $r1 >> 16;
|
||||
$r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
|
||||
$r2 |= $r2 >> 16;
|
||||
$r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
|
||||
$r3 |= $r3 >> 16;
|
||||
|
||||
if ($j === $limit) {
|
||||
if ($limit === 64) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Mashing round.
|
||||
$r0 += $keys[$r3 & 0x3F];
|
||||
$r1 += $keys[$r0 & 0x3F];
|
||||
$r2 += $keys[$r1 & 0x3F];
|
||||
$r3 += $keys[$r2 & 0x3F];
|
||||
$limit = $actions[$limit];
|
||||
}
|
||||
}
|
||||
|
||||
return pack('vvvv', $r0, $r1, $r2, $r3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a block
|
||||
*
|
||||
* @see Crypt_Base::_decryptBlock()
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @access private
|
||||
* @param String $in
|
||||
* @return String
|
||||
*/
|
||||
function _decryptBlock($in)
|
||||
{
|
||||
list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
|
||||
$keys = $this->keys;
|
||||
$limit = 44;
|
||||
$actions = array($limit => 20, 20 => 0);
|
||||
$j = 64;
|
||||
|
||||
for (;;) {
|
||||
// R-mixing round.
|
||||
$r3 = ($r3 | ($r3 << 16)) >> 5;
|
||||
$r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
|
||||
$r2 = ($r2 | ($r2 << 16)) >> 3;
|
||||
$r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
|
||||
$r1 = ($r1 | ($r1 << 16)) >> 2;
|
||||
$r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
|
||||
$r0 = ($r0 | ($r0 << 16)) >> 1;
|
||||
$r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
|
||||
|
||||
if ($j === $limit) {
|
||||
if ($limit === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// R-mashing round.
|
||||
$r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
|
||||
$r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
|
||||
$r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
|
||||
$r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
|
||||
$limit = $actions[$limit];
|
||||
}
|
||||
}
|
||||
|
||||
return pack('vvvv', $r0, $r1, $r2, $r3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the key schedule
|
||||
*
|
||||
* @see Crypt_Base::_setupKey()
|
||||
* @access private
|
||||
*/
|
||||
function _setupKey()
|
||||
{
|
||||
// Key has already been expanded in Crypt_RC2::setKey():
|
||||
// Only the first value must be altered.
|
||||
$l = unpack('Ca/Cb/v*', $this->key);
|
||||
array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
|
||||
unset($l['a']);
|
||||
unset($l['b']);
|
||||
$this->keys = $l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the performance-optimized function for de/encrypt()
|
||||
*
|
||||
* @see Crypt_Base::_setupInlineCrypt()
|
||||
* @access private
|
||||
*/
|
||||
function _setupInlineCrypt()
|
||||
{
|
||||
$lambda_functions = &Crypt_RC2::_getLambdaFunctions();
|
||||
|
||||
// The first 10 generated $lambda_functions will use the $keys hardcoded as integers
|
||||
// for the mixing rounds, for better inline crypt performance [~20% faster].
|
||||
// But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
|
||||
$keys = $this->keys;
|
||||
if (count($lambda_functions) >= 10) {
|
||||
foreach ($this->keys as $k => $v) {
|
||||
$keys[$k] = '$keys[' . $k . ']';
|
||||
}
|
||||
}
|
||||
|
||||
$code_hash = md5(str_pad("Crypt_RC2, {$this->mode}, ", 32, "\0") . implode(',', $keys));
|
||||
|
||||
// Is there a re-usable $lambda_functions in there?
|
||||
// If not, we have to create it.
|
||||
if (!isset($lambda_functions[$code_hash])) {
|
||||
// Init code for both, encrypt and decrypt.
|
||||
$init_crypt = '$keys = $self->keys;';
|
||||
|
||||
// $in is the current 8 bytes block which has to be en/decrypt
|
||||
$encrypt_block = $decrypt_block = '
|
||||
$in = unpack("v4", $in);
|
||||
$r0 = $in[1];
|
||||
$r1 = $in[2];
|
||||
$r2 = $in[3];
|
||||
$r3 = $in[4];
|
||||
';
|
||||
|
||||
// Create code for encryption.
|
||||
$limit = 20;
|
||||
$actions = array($limit => 44, 44 => 64);
|
||||
$j = 0;
|
||||
|
||||
for (;;) {
|
||||
// Mixing round.
|
||||
$encrypt_block .= '
|
||||
$r0 = (($r0 + ' . $keys[$j++] . ' +
|
||||
((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
|
||||
$r0 |= $r0 >> 16;
|
||||
$r1 = (($r1 + ' . $keys[$j++] . ' +
|
||||
((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
|
||||
$r1 |= $r1 >> 16;
|
||||
$r2 = (($r2 + ' . $keys[$j++] . ' +
|
||||
((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
|
||||
$r2 |= $r2 >> 16;
|
||||
$r3 = (($r3 + ' . $keys[$j++] . ' +
|
||||
((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
|
||||
$r3 |= $r3 >> 16;';
|
||||
|
||||
if ($j === $limit) {
|
||||
if ($limit === 64) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Mashing round.
|
||||
$encrypt_block .= '
|
||||
$r0 += $keys[$r3 & 0x3F];
|
||||
$r1 += $keys[$r0 & 0x3F];
|
||||
$r2 += $keys[$r1 & 0x3F];
|
||||
$r3 += $keys[$r2 & 0x3F];';
|
||||
$limit = $actions[$limit];
|
||||
}
|
||||
}
|
||||
|
||||
$encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
|
||||
|
||||
// Create code for decryption.
|
||||
$limit = 44;
|
||||
$actions = array($limit => 20, 20 => 0);
|
||||
$j = 64;
|
||||
|
||||
for (;;) {
|
||||
// R-mixing round.
|
||||
$decrypt_block .= '
|
||||
$r3 = ($r3 | ($r3 << 16)) >> 5;
|
||||
$r3 = ($r3 - ' . $keys[--$j] . ' -
|
||||
((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
|
||||
$r2 = ($r2 | ($r2 << 16)) >> 3;
|
||||
$r2 = ($r2 - ' . $keys[--$j] . ' -
|
||||
((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
|
||||
$r1 = ($r1 | ($r1 << 16)) >> 2;
|
||||
$r1 = ($r1 - ' . $keys[--$j] . ' -
|
||||
((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
|
||||
$r0 = ($r0 | ($r0 << 16)) >> 1;
|
||||
$r0 = ($r0 - ' . $keys[--$j] . ' -
|
||||
((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
|
||||
|
||||
if ($j === $limit) {
|
||||
if ($limit === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// R-mashing round.
|
||||
$decrypt_block .= '
|
||||
$r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
|
||||
$r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
|
||||
$r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
|
||||
$r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
|
||||
$limit = $actions[$limit];
|
||||
}
|
||||
}
|
||||
|
||||
$decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
|
||||
|
||||
// Creates the inline-crypt function
|
||||
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
|
||||
array(
|
||||
'init_crypt' => $init_crypt,
|
||||
'encrypt_block' => $encrypt_block,
|
||||
'decrypt_block' => $decrypt_block
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Set the inline-crypt function as callback in: $this->inline_crypt
|
||||
$this->inline_crypt = $lambda_functions[$code_hash];
|
||||
}
|
||||
}
|
469
Crypt/RC4.php
469
Crypt/RC4.php
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of RC4.
|
||||
@ -19,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();
|
||||
*
|
||||
@ -41,10 +40,10 @@
|
||||
* 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
|
||||
@ -53,14 +52,23 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_RC4
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Crypt
|
||||
* @package Crypt_RC4
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* Include Crypt_Base
|
||||
*
|
||||
* Base cipher class
|
||||
*/
|
||||
if (!class_exists('Crypt_Base')) {
|
||||
include_once 'Base.php';
|
||||
}
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_RC4::Crypt_RC4()
|
||||
@ -68,11 +76,11 @@
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_RC4_MODE_INTERNAL', 1);
|
||||
define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_RC4_MODE_MCRYPT', 2);
|
||||
define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
@ -86,12 +94,61 @@ define('CRYPT_RC4_DECRYPT', 1);
|
||||
/**
|
||||
* Pure-PHP implementation of RC4.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.1.0
|
||||
* @access public
|
||||
* @package Crypt_RC4
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_RC4 {
|
||||
class Crypt_RC4 extends Crypt_Base
|
||||
{
|
||||
/**
|
||||
* Block Length of the cipher
|
||||
*
|
||||
* RC4 is a stream cipher
|
||||
* so we the block_size to 0
|
||||
*
|
||||
* @see Crypt_Base::block_size
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $block_size = 0;
|
||||
|
||||
/**
|
||||
* The default password key_size used by setPassword()
|
||||
*
|
||||
* @see Crypt_Base::password_key_size
|
||||
* @see Crypt_Base::setPassword()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $password_key_size = 128; // = 1024 bits
|
||||
|
||||
/**
|
||||
* The namespace used by the cipher for its constants.
|
||||
*
|
||||
* @see Crypt_Base::const_namespace
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $const_namespace = 'RC4';
|
||||
|
||||
/**
|
||||
* The mcrypt specific name of the cipher
|
||||
*
|
||||
* @see Crypt_Base::cipher_name_mcrypt
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $cipher_name_mcrypt = 'arcfour';
|
||||
|
||||
/**
|
||||
* Holds whether performance-optimized $inline_crypt() can/should be used.
|
||||
*
|
||||
* @see Crypt_Base::inline_crypt
|
||||
* @var mixed
|
||||
* @access private
|
||||
*/
|
||||
var $use_inline_crypt = false; // currently not available
|
||||
|
||||
/**
|
||||
* The Key
|
||||
*
|
||||
@ -102,190 +159,26 @@ class Crypt_RC4 {
|
||||
var $key = "\0";
|
||||
|
||||
/**
|
||||
* The Key Stream for encryption
|
||||
*
|
||||
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
|
||||
* The Key Stream for decryption and encryption
|
||||
*
|
||||
* @see Crypt_RC4::setKey()
|
||||
* @var Array
|
||||
* @access private
|
||||
*/
|
||||
var $encryptStream = false;
|
||||
|
||||
/**
|
||||
* The Key Stream for decryption
|
||||
*
|
||||
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
|
||||
*
|
||||
* @see Crypt_RC4::setKey()
|
||||
* @var Array
|
||||
* @access private
|
||||
*/
|
||||
var $decryptStream = false;
|
||||
|
||||
/**
|
||||
* The $i and $j indexes for encryption
|
||||
*
|
||||
* @see Crypt_RC4::_crypt()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $encryptIndex = 0;
|
||||
|
||||
/**
|
||||
* The $i and $j indexes for decryption
|
||||
*
|
||||
* @see Crypt_RC4::_crypt()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $decryptIndex = 0;
|
||||
|
||||
/**
|
||||
* The Encryption Algorithm
|
||||
*
|
||||
* Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
|
||||
*
|
||||
* @see Crypt_RC4::Crypt_RC4()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $mode;
|
||||
|
||||
/**
|
||||
* Continuous Buffer status
|
||||
*
|
||||
* @see Crypt_RC4::enableContinuousBuffer()
|
||||
* @var Boolean
|
||||
* @access private
|
||||
*/
|
||||
var $continuousBuffer = false;
|
||||
var $stream;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* Determines whether or not the mcrypt extension should be used.
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @return Crypt_RC4
|
||||
* @access public
|
||||
*/
|
||||
function Crypt_RC4()
|
||||
{
|
||||
if ( !defined('CRYPT_RC4_MODE') ) {
|
||||
switch (true) {
|
||||
case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
|
||||
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
|
||||
}
|
||||
}
|
||||
|
||||
switch ( CRYPT_RC4_MODE ) {
|
||||
case CRYPT_RC4_MODE_MCRYPT:
|
||||
switch (true) {
|
||||
case defined('MCRYPT_ARCFOUR'):
|
||||
$this->mode = MCRYPT_ARCFOUR;
|
||||
break;
|
||||
case defined('MCRYPT_RC4');
|
||||
$this->mode = MCRYPT_RC4;
|
||||
}
|
||||
$this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
|
||||
$this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
|
||||
* be used. If no key is explicitly set, it'll be assumed to be a single null byte.
|
||||
*
|
||||
* @access public
|
||||
* @param String $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
$this->key = $key;
|
||||
|
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
||||
mcrypt_generic_init($this->encryptStream, $this->key, '');
|
||||
mcrypt_generic_init($this->decryptStream, $this->key, '');
|
||||
return;
|
||||
}
|
||||
|
||||
$keyLength = strlen($key);
|
||||
$keyStream = array();
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$keyStream[$i] = $i;
|
||||
}
|
||||
$j = 0;
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
|
||||
$temp = $keyStream[$i];
|
||||
$keyStream[$i] = $keyStream[$j];
|
||||
$keyStream[$j] = $temp;
|
||||
}
|
||||
|
||||
$this->encryptIndex = $this->decryptIndex = array(0, 0);
|
||||
$this->encryptStream = $this->decryptStream = $keyStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}:
|
||||
* $hash, $salt, $count, $dkLen
|
||||
*
|
||||
* @param String $password
|
||||
* @param optional String $method
|
||||
* @access public
|
||||
*/
|
||||
function setPassword($password, $method = 'pbkdf2')
|
||||
{
|
||||
$key = '';
|
||||
|
||||
switch ($method) {
|
||||
default: // 'pbkdf2'
|
||||
list(, , $hash, $salt, $count) = func_get_args();
|
||||
if (!isset($hash)) {
|
||||
$hash = 'sha1';
|
||||
}
|
||||
// WPA and WPA2 use the SSID as the salt
|
||||
if (!isset($salt)) {
|
||||
$salt = 'phpseclib/salt';
|
||||
}
|
||||
// RFC2898#section-4.2 uses 1,000 iterations by default
|
||||
// WPA and WPA2 use 4,096.
|
||||
if (!isset($count)) {
|
||||
$count = 1000;
|
||||
}
|
||||
if (!isset($dkLen)) {
|
||||
$dkLen = 128;
|
||||
}
|
||||
|
||||
if (!class_exists('Crypt_Hash')) {
|
||||
require_once('Crypt/Hash.php');
|
||||
}
|
||||
|
||||
$i = 1;
|
||||
while (strlen($key) < $dkLen) {
|
||||
//$dk.= $this->_pbkdf($password, $salt, $count, $i++);
|
||||
$hmac = new Crypt_Hash();
|
||||
$hmac->setHash($hash);
|
||||
$hmac->setKey($password);
|
||||
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
||||
for ($j = 2; $j <= $count; $j++) {
|
||||
$u = $hmac->hash($u);
|
||||
$f^= $u;
|
||||
}
|
||||
$key.= $f;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setKey(substr($key, 0, $dkLen));
|
||||
parent::Crypt_Base(CRYPT_MODE_STREAM);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,15 +204,35 @@ class Crypt_RC4 {
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
|
||||
* be used. If no key is explicitly set, it'll be assumed to be a single null byte.
|
||||
*
|
||||
* @access public
|
||||
* @see Crypt_Base::setKey()
|
||||
* @param String $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
parent::setKey(substr($key, 0, 256));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a message.
|
||||
*
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @see Crypt_RC4::_crypt()
|
||||
* @access public
|
||||
* @param String $plaintext
|
||||
* @return String $ciphertext
|
||||
*/
|
||||
function encrypt($plaintext)
|
||||
{
|
||||
if ($this->engine == CRYPT_MODE_MCRYPT) {
|
||||
return parent::encrypt($plaintext);
|
||||
}
|
||||
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
|
||||
}
|
||||
|
||||
@ -327,17 +240,50 @@ class Crypt_RC4 {
|
||||
* 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()
|
||||
* @access public
|
||||
* @param String $ciphertext
|
||||
* @return String $plaintext
|
||||
*/
|
||||
function decrypt($ciphertext)
|
||||
{
|
||||
if ($this->engine == CRYPT_MODE_MCRYPT) {
|
||||
return parent::decrypt($ciphertext);
|
||||
}
|
||||
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup the key (expansion)
|
||||
*
|
||||
* @see Crypt_Base::_setupKey()
|
||||
* @access private
|
||||
*/
|
||||
function _setupKey()
|
||||
{
|
||||
$key = $this->key;
|
||||
$keyLength = strlen($key);
|
||||
$keyStream = range(0, 255);
|
||||
$j = 0;
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
|
||||
$temp = $keyStream[$i];
|
||||
$keyStream[$i] = $keyStream[$j];
|
||||
$keyStream[$j] = $temp;
|
||||
}
|
||||
|
||||
$this->stream = array();
|
||||
$this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
|
||||
0, // index $i
|
||||
0, // index $j
|
||||
$keyStream
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts or decrypts a message.
|
||||
*
|
||||
@ -346,147 +292,38 @@ class Crypt_RC4 {
|
||||
* @access private
|
||||
* @param String $text
|
||||
* @param Integer $mode
|
||||
* @return String $text
|
||||
*/
|
||||
function _crypt($text, $mode)
|
||||
{
|
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
||||
$keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
mcrypt_generic_init($this->$keyStream, $this->key, '');
|
||||
}
|
||||
|
||||
return mcrypt_generic($this->$keyStream, $text);
|
||||
}
|
||||
|
||||
if ($this->encryptStream === false) {
|
||||
$this->setKey($this->key);
|
||||
}
|
||||
|
||||
switch ($mode) {
|
||||
case CRYPT_RC4_ENCRYPT:
|
||||
$keyStream = $this->encryptStream;
|
||||
list($i, $j) = $this->encryptIndex;
|
||||
break;
|
||||
case CRYPT_RC4_DECRYPT:
|
||||
$keyStream = $this->decryptStream;
|
||||
list($i, $j) = $this->decryptIndex;
|
||||
}
|
||||
|
||||
$newText = '';
|
||||
for ($k = 0; $k < strlen($text); $k++) {
|
||||
$i = ($i + 1) & 255;
|
||||
$j = ($j + $keyStream[$i]) & 255;
|
||||
$temp = $keyStream[$i];
|
||||
$keyStream[$i] = $keyStream[$j];
|
||||
$keyStream[$j] = $temp;
|
||||
$temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
|
||||
$newText.= chr(ord($text[$k]) ^ $temp);
|
||||
if ($this->changed) {
|
||||
$this->_setup();
|
||||
$this->changed = false;
|
||||
}
|
||||
|
||||
$stream = &$this->stream[$mode];
|
||||
if ($this->continuousBuffer) {
|
||||
switch ($mode) {
|
||||
case CRYPT_RC4_ENCRYPT:
|
||||
$this->encryptStream = $keyStream;
|
||||
$this->encryptIndex = array($i, $j);
|
||||
break;
|
||||
case CRYPT_RC4_DECRYPT:
|
||||
$this->decryptStream = $keyStream;
|
||||
$this->decryptIndex = array($i, $j);
|
||||
}
|
||||
$i = &$stream[0];
|
||||
$j = &$stream[1];
|
||||
$keyStream = &$stream[2];
|
||||
} else {
|
||||
$i = $stream[0];
|
||||
$j = $stream[1];
|
||||
$keyStream = $stream[2];
|
||||
}
|
||||
|
||||
return $newText;
|
||||
}
|
||||
$len = strlen($text);
|
||||
for ($k = 0; $k < $len; ++$k) {
|
||||
$i = ($i + 1) & 255;
|
||||
$ksi = $keyStream[$i];
|
||||
$j = ($j + $ksi) & 255;
|
||||
$ksj = $keyStream[$j];
|
||||
|
||||
/**
|
||||
* Treat consecutive "packets" as if they are a continuous buffer.
|
||||
*
|
||||
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
||||
* will yield different outputs:
|
||||
*
|
||||
* <code>
|
||||
* echo $rc4->encrypt(substr($plaintext, 0, 8));
|
||||
* echo $rc4->encrypt(substr($plaintext, 8, 8));
|
||||
* </code>
|
||||
* <code>
|
||||
* echo $rc4->encrypt($plaintext);
|
||||
* </code>
|
||||
*
|
||||
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
||||
* another, as demonstrated with the following:
|
||||
*
|
||||
* <code>
|
||||
* $rc4->encrypt(substr($plaintext, 0, 8));
|
||||
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
||||
* </code>
|
||||
* <code>
|
||||
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
||||
* </code>
|
||||
*
|
||||
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
||||
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
||||
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
||||
*
|
||||
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
|
||||
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
||||
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
||||
* however, they are also less intuitive and more likely to cause you problems.
|
||||
*
|
||||
* @see Crypt_RC4::disableContinuousBuffer()
|
||||
* @access public
|
||||
*/
|
||||
function enableContinuousBuffer()
|
||||
{
|
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
||||
mcrypt_generic_init($this->encryptStream, $this->key, '');
|
||||
mcrypt_generic_init($this->decryptStream, $this->key, '');
|
||||
$keyStream[$i] = $ksj;
|
||||
$keyStream[$j] = $ksi;
|
||||
$text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
|
||||
}
|
||||
|
||||
$this->continuousBuffer = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat consecutive packets as if they are a discontinuous buffer.
|
||||
*
|
||||
* The default behavior.
|
||||
*
|
||||
* @see Crypt_RC4::enableContinuousBuffer()
|
||||
* @access public
|
||||
*/
|
||||
function disableContinuousBuffer()
|
||||
{
|
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
|
||||
$this->encryptIndex = $this->decryptIndex = array(0, 0);
|
||||
$this->encryptStream = $this->decryptStream = false;
|
||||
}
|
||||
|
||||
$this->continuousBuffer = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function.
|
||||
*
|
||||
* Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
|
||||
* included is so that you can switch between a block cipher and a stream cipher transparently.
|
||||
*
|
||||
* @see Crypt_RC4::disablePadding()
|
||||
* @access public
|
||||
*/
|
||||
function enablePadding()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function.
|
||||
*
|
||||
* @see Crypt_RC4::enablePadding()
|
||||
* @access public
|
||||
*/
|
||||
function disablePadding()
|
||||
{
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
// vim: ts=4:sw=4:et:
|
||||
// vim6: fdl=1:
|
||||
|
461
Crypt/RSA.php
461
Crypt/RSA.php
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
|
||||
@ -9,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());
|
||||
@ -27,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());
|
||||
@ -48,10 +47,10 @@
|
||||
* 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
|
||||
@ -60,12 +59,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMIX Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Crypt
|
||||
* @package Crypt_RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMIX Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -73,17 +72,17 @@
|
||||
*/
|
||||
// the class_exists() will only be called if the crypt_random_string function hasn't been defined and
|
||||
// will trigger a call to __autoload() if you're wanting to auto-load classes
|
||||
// call function_exists() a second time to stop the require_once from being called outside
|
||||
// call function_exists() a second time to stop the include_once from being called outside
|
||||
// of the auto loader
|
||||
if (!function_exists('crypt_random_string')) {
|
||||
require_once('Random.php');
|
||||
include_once 'Random.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Include Crypt_Hash
|
||||
*/
|
||||
if (!class_exists('Crypt_Hash')) {
|
||||
require_once('Hash.php');
|
||||
include_once 'Hash.php';
|
||||
}
|
||||
|
||||
/**#@+
|
||||
@ -105,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);
|
||||
/**#@-*/
|
||||
@ -129,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);
|
||||
/**#@-*/
|
||||
@ -141,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);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
@ -173,7 +180,6 @@ define('CRYPT_RSA_MODE_OPENSSL', 2);
|
||||
*/
|
||||
define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
|
||||
|
||||
|
||||
/**#@+
|
||||
* @access public
|
||||
* @see Crypt_RSA::createKey()
|
||||
@ -193,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);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
@ -218,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
|
||||
@ -234,19 +251,27 @@ 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);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP PKCS#1 compliant implementation of RSA.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.1.0
|
||||
* @access public
|
||||
* @package Crypt_RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_RSA {
|
||||
class Crypt_RSA
|
||||
{
|
||||
/**
|
||||
* Precomputed Zero
|
||||
*
|
||||
@ -277,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)
|
||||
@ -434,7 +459,7 @@ class Crypt_RSA {
|
||||
/**
|
||||
* OpenSSL configuration file name.
|
||||
*
|
||||
* Set to NULL to use system configuration file.
|
||||
* Set to null to use system configuration file.
|
||||
* @see Crypt_RSA::createKey()
|
||||
* @var Mixed
|
||||
* @Access public
|
||||
@ -462,15 +487,50 @@ class Crypt_RSA {
|
||||
function Crypt_RSA()
|
||||
{
|
||||
if (!class_exists('Math_BigInteger')) {
|
||||
require_once('Math/BigInteger.php');
|
||||
include_once 'Math/BigInteger.php';
|
||||
}
|
||||
|
||||
$this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
|
||||
|
||||
if ( !defined('CRYPT_RSA_MODE') ) {
|
||||
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):
|
||||
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
|
||||
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
|
||||
ob_start();
|
||||
@phpinfo();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
|
||||
|
||||
$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])));
|
||||
}
|
||||
}
|
||||
|
||||
// it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
|
||||
switch (true) {
|
||||
case !isset($versions['Header']):
|
||||
case !isset($versions['Library']):
|
||||
case $versions['Header'] == $versions['Library']:
|
||||
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
|
||||
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
|
||||
@ -524,7 +584,7 @@ class Crypt_RSA {
|
||||
$config['config'] = $this->configFile;
|
||||
}
|
||||
$rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
|
||||
openssl_pkey_export($rsa, $privatekey, NULL, $config);
|
||||
openssl_pkey_export($rsa, $privatekey, null, $config);
|
||||
$publickey = openssl_pkey_get_details($rsa);
|
||||
$publickey = $publickey['key'];
|
||||
|
||||
@ -642,12 +702,12 @@ class Crypt_RSA {
|
||||
$exponents[$i] = $e->modInverse($temp);
|
||||
}
|
||||
|
||||
list($lcm) = $lcm['top']->divide($lcm['bottom']);
|
||||
$gcd = $lcm->gcd($e);
|
||||
list($temp) = $lcm['top']->divide($lcm['bottom']);
|
||||
$gcd = $temp->gcd($e);
|
||||
$i0 = 1;
|
||||
} while (!$gcd->equals($this->one));
|
||||
|
||||
$d = $e->modInverse($lcm);
|
||||
$d = $e->modInverse($temp);
|
||||
|
||||
$coefficients[2] = $primes[2]->modInverse($primes[1]);
|
||||
|
||||
@ -682,17 +742,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,
|
||||
@ -725,11 +786,11 @@ 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) + 32) >> 6) . "\r\n";
|
||||
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
|
||||
$key.= chunk_split($public, 64);
|
||||
$private = pack('Na*Na*Na*Na*',
|
||||
strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
|
||||
@ -742,7 +803,7 @@ class Crypt_RSA {
|
||||
$private.= crypt_random_string(16 - (strlen($private) & 15));
|
||||
$source.= pack('Na*', strlen($private), $private);
|
||||
if (!class_exists('Crypt_AES')) {
|
||||
require_once('Crypt/AES.php');
|
||||
include_once 'Crypt/AES.php';
|
||||
}
|
||||
$sequence = 0;
|
||||
$symkey = '';
|
||||
@ -760,10 +821,10 @@ class Crypt_RSA {
|
||||
}
|
||||
|
||||
$private = base64_encode($private);
|
||||
$key.= 'Private-Lines: ' . ((strlen($private) + 32) >> 6) . "\r\n";
|
||||
$key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
|
||||
$key.= chunk_split($private, 64);
|
||||
if (!class_exists('Crypt_Hash')) {
|
||||
require_once('Crypt/Hash.php');
|
||||
include_once 'Crypt/Hash.php';
|
||||
}
|
||||
$hash = new Crypt_Hash('sha1');
|
||||
$hash->setKey(pack('H*', sha1($hashkey)));
|
||||
@ -798,12 +859,58 @@ 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
|
||||
$symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
|
||||
if (!class_exists('Crypt_TripleDES')) {
|
||||
require_once('Crypt/TripleDES.php');
|
||||
include_once 'Crypt/TripleDES.php';
|
||||
}
|
||||
$des = new Crypt_TripleDES();
|
||||
$des->setKey($symkey);
|
||||
@ -835,8 +942,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:
|
||||
@ -872,7 +981,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;
|
||||
@ -881,11 +994,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;
|
||||
}
|
||||
@ -941,6 +1054,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
|
||||
@ -953,7 +1067,7 @@ class Crypt_RSA {
|
||||
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
|
||||
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
|
||||
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
|
||||
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
||||
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
||||
implementation are part of the standard, as well.
|
||||
|
||||
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
|
||||
@ -961,41 +1075,42 @@ class Crypt_RSA {
|
||||
$iv = pack('H*', trim($matches[2]));
|
||||
$symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
|
||||
$symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
|
||||
$ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
|
||||
$ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
|
||||
// remove the Proc-Type / DEK-Info sections as they're no longer needed
|
||||
$key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
|
||||
$ciphertext = $this->_extractBER($key);
|
||||
if ($ciphertext === false) {
|
||||
$ciphertext = $key;
|
||||
}
|
||||
switch ($matches[1]) {
|
||||
case 'AES-256-CBC':
|
||||
if (!class_exists('Crypt_AES')) {
|
||||
require_once('Crypt/AES.php');
|
||||
include_once 'Crypt/AES.php';
|
||||
}
|
||||
$crypto = new Crypt_AES();
|
||||
break;
|
||||
case 'AES-128-CBC':
|
||||
if (!class_exists('Crypt_AES')) {
|
||||
require_once('Crypt/AES.php');
|
||||
include_once 'Crypt/AES.php';
|
||||
}
|
||||
$symkey = substr($symkey, 0, 16);
|
||||
$crypto = new Crypt_AES();
|
||||
break;
|
||||
case 'DES-EDE3-CFB':
|
||||
if (!class_exists('Crypt_TripleDES')) {
|
||||
require_once('Crypt/TripleDES.php');
|
||||
include_once 'Crypt/TripleDES.php';
|
||||
}
|
||||
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
|
||||
break;
|
||||
case 'DES-EDE3-CBC':
|
||||
if (!class_exists('Crypt_TripleDES')) {
|
||||
require_once('Crypt/TripleDES.php');
|
||||
include_once 'Crypt/TripleDES.php';
|
||||
}
|
||||
$symkey = substr($symkey, 0, 24);
|
||||
$crypto = new Crypt_TripleDES();
|
||||
break;
|
||||
case 'DES-CBC':
|
||||
if (!class_exists('Crypt_DES')) {
|
||||
require_once('Crypt/DES.php');
|
||||
include_once 'Crypt/DES.php';
|
||||
}
|
||||
$crypto = new Crypt_DES();
|
||||
break;
|
||||
@ -1006,8 +1121,7 @@ class Crypt_RSA {
|
||||
$crypto->setIV($iv);
|
||||
$decoded = $crypto->decrypt($ciphertext);
|
||||
} else {
|
||||
$decoded = preg_replace('#-.+-|[\r\n]| #', '', $key);
|
||||
$decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
|
||||
$decoded = $this->_extractBER($key);
|
||||
}
|
||||
|
||||
if ($decoded !== false) {
|
||||
@ -1031,7 +1145,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);
|
||||
@ -1039,6 +1155,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
|
||||
@ -1046,7 +1208,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
|
||||
@ -1209,7 +1370,7 @@ class Crypt_RSA {
|
||||
switch ($encryption) {
|
||||
case 'aes256-cbc':
|
||||
if (!class_exists('Crypt_AES')) {
|
||||
require_once('Crypt/AES.php');
|
||||
include_once 'Crypt/AES.php';
|
||||
}
|
||||
$symkey = '';
|
||||
$sequence = 0;
|
||||
@ -1311,9 +1472,6 @@ class Crypt_RSA {
|
||||
break;
|
||||
case 'D':
|
||||
$this->current = &$this->components['privateExponent'];
|
||||
break;
|
||||
default:
|
||||
unset($this->current);
|
||||
}
|
||||
$this->current = '';
|
||||
}
|
||||
@ -1329,11 +1487,10 @@ class Crypt_RSA {
|
||||
*/
|
||||
function _stop_element_handler($parser, $name)
|
||||
{
|
||||
//$name = strtoupper($name);
|
||||
if ($name == 'RSAKEYVALUE') {
|
||||
return;
|
||||
if (isset($this->current)) {
|
||||
$this->current = new Math_BigInteger(base64_decode($this->current), 256);
|
||||
unset($this->current);
|
||||
}
|
||||
$this->current = new Math_BigInteger(base64_decode($this->current), 256);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1364,6 +1521,53 @@ class Crypt_RSA {
|
||||
*/
|
||||
function loadKey($key, $type = false)
|
||||
{
|
||||
if (is_object($key) && strtolower(get_class($key)) == 'crypt_rsa') {
|
||||
$this->privateKeyFormat = $key->privateKeyFormat;
|
||||
$this->publicKeyFormat = $key->publicKeyFormat;
|
||||
$this->k = $key->k;
|
||||
$this->hLen = $key->hLen;
|
||||
$this->sLen = $key->sLen;
|
||||
$this->mgfHLen = $key->mgfHLen;
|
||||
$this->encryptionMode = $key->encryptionMode;
|
||||
$this->signatureMode = $key->signatureMode;
|
||||
$this->password = $key->password;
|
||||
$this->configFile = $key->configFile;
|
||||
$this->comment = $key->comment;
|
||||
|
||||
if (is_object($key->hash)) {
|
||||
$this->hash = new Crypt_Hash($key->hash->getHash());
|
||||
}
|
||||
if (is_object($key->mgfHash)) {
|
||||
$this->mgfHash = new Crypt_Hash($key->mgfHash->getHash());
|
||||
}
|
||||
|
||||
if (is_object($key->modulus)) {
|
||||
$this->modulus = $key->modulus->copy();
|
||||
}
|
||||
if (is_object($key->exponent)) {
|
||||
$this->exponent = $key->exponent->copy();
|
||||
}
|
||||
if (is_object($key->publicExponent)) {
|
||||
$this->publicExponent = $key->publicExponent->copy();
|
||||
}
|
||||
|
||||
$this->primes = array();
|
||||
$this->exponents = array();
|
||||
$this->coefficients = array();
|
||||
|
||||
foreach ($this->primes as $prime) {
|
||||
$this->primes[] = $prime->copy();
|
||||
}
|
||||
foreach ($this->exponents as $exponent) {
|
||||
$this->exponents[] = $exponent->copy();
|
||||
}
|
||||
foreach ($this->coefficients as $coefficient) {
|
||||
$this->coefficients[] = $coefficient->copy();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($type === false) {
|
||||
$types = array(
|
||||
CRYPT_RSA_PUBLIC_FORMAT_RAW,
|
||||
@ -1378,7 +1582,7 @@ class Crypt_RSA {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
$components = $this->_parseKey($key, $type);
|
||||
}
|
||||
@ -1405,6 +1609,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;
|
||||
}
|
||||
|
||||
@ -1431,7 +1648,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.
|
||||
*
|
||||
@ -1445,6 +1664,11 @@ class Crypt_RSA {
|
||||
*/
|
||||
function setPublicKey($key = false, $type = false)
|
||||
{
|
||||
// if a public key has already been loaded return false
|
||||
if (!empty($this->publicExponent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($key === false && !empty($this->modulus)) {
|
||||
$this->publicExponent = $this->exponent;
|
||||
return true;
|
||||
@ -1482,6 +1706,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
|
||||
*
|
||||
@ -1494,7 +1752,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;
|
||||
@ -1541,7 +1799,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;
|
||||
@ -1569,6 +1827,18 @@ class Crypt_RSA {
|
||||
return $key !== false ? $key : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* __clone() magic method
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function __clone()
|
||||
{
|
||||
$key = new Crypt_RSA();
|
||||
$key->loadKey($this);
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the smallest and largest numbers requiring $bits bits
|
||||
*
|
||||
@ -2061,7 +2331,7 @@ class Crypt_RSA {
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
|
||||
* messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
|
||||
*
|
||||
*
|
||||
* Note. Care must be taken to ensure that an opponent cannot
|
||||
* distinguish the different error conditions in Step 3.g, whether by
|
||||
* error message or timing, or, more generally, learn partial
|
||||
@ -2184,11 +2454,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
|
||||
@ -2690,4 +2960,31 @@ class Crypt_RSA {
|
||||
return $this->_rsassa_pss_verify($message, $signature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract raw BER from Base64 encoding
|
||||
*
|
||||
* @access private
|
||||
* @param String $str
|
||||
* @return String
|
||||
*/
|
||||
function _extractBER($str)
|
||||
{
|
||||
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
|
||||
* above and beyond the ceritificate.
|
||||
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
|
||||
*
|
||||
* Bag Attributes
|
||||
* localKeyID: 01 00 00 00
|
||||
* subject=/O=organization/OU=org unit/CN=common name
|
||||
* issuer=/O=organization/CN=common name
|
||||
*/
|
||||
$temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1);
|
||||
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
||||
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
|
||||
// remove new lines
|
||||
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
||||
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
|
||||
return $temp != false ? $temp : $str;
|
||||
}
|
||||
}
|
||||
|
435
Crypt/Random.php
435
Crypt/Random.php
@ -1,15 +1,17 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* 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));
|
||||
* ?>
|
||||
@ -21,10 +23,10 @@
|
||||
* 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
|
||||
@ -33,186 +35,213 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_Random
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Crypt
|
||||
* @package Crypt_Random
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII 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();
|
||||
if (isset($_SESSION)) {
|
||||
$_OLD_SESSION = $_SESSION;
|
||||
}
|
||||
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 (isset($_OLD_SESSION)) {
|
||||
$_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
|
||||
@ -221,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;
|
||||
}
|
||||
}
|
||||
|
1974
Crypt/Rijndael.php
1974
Crypt/Rijndael.php
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Triple DES.
|
||||
@ -11,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();
|
||||
*
|
||||
@ -33,10 +32,10 @@
|
||||
* 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
|
||||
@ -45,19 +44,19 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_TripleDES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Crypt
|
||||
* @package Crypt_TripleDES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* Include Crypt_DES
|
||||
*/
|
||||
if (!class_exists('Crypt_DES')) {
|
||||
require_once('DES.php');
|
||||
include_once 'DES.php';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,15 +76,85 @@ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
|
||||
/**
|
||||
* Pure-PHP implementation of Triple DES.
|
||||
*
|
||||
* @package Crypt_TripleDES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.1.0
|
||||
* @access public
|
||||
* @package Crypt_TerraDES
|
||||
*/
|
||||
class Crypt_TripleDES extends Crypt_DES {
|
||||
class Crypt_TripleDES extends Crypt_DES
|
||||
{
|
||||
/**
|
||||
* The default password key_size used by setPassword()
|
||||
*
|
||||
* @see Crypt_DES::password_key_size
|
||||
* @see Crypt_Base::password_key_size
|
||||
* @see Crypt_Base::setPassword()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $password_key_size = 24;
|
||||
|
||||
/**
|
||||
* The default salt used by setPassword()
|
||||
*
|
||||
* @see Crypt_Base::password_default_salt
|
||||
* @see Crypt_Base::setPassword()
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $password_default_salt = 'phpseclib';
|
||||
|
||||
/**
|
||||
* The namespace used by the cipher for its constants.
|
||||
*
|
||||
* @see Crypt_DES::const_namespace
|
||||
* @see Crypt_Base::const_namespace
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $const_namespace = 'DES';
|
||||
|
||||
/**
|
||||
* The mcrypt specific name of the cipher
|
||||
*
|
||||
* @see Crypt_DES::cipher_name_mcrypt
|
||||
* @see Crypt_Base::cipher_name_mcrypt
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $cipher_name_mcrypt = 'tripledes';
|
||||
|
||||
/**
|
||||
* Optimizing value while CFB-encrypting
|
||||
*
|
||||
* @see Crypt_Base::cfb_init_len
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $cfb_init_len = 750;
|
||||
|
||||
/**
|
||||
* max possible size of $key
|
||||
*
|
||||
* @see Crypt_TripleDES::setKey()
|
||||
* @see Crypt_DES::setKey()
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $key_size_max = 24;
|
||||
|
||||
/**
|
||||
* Internal flag whether using CRYPT_DES_MODE_3CBC or not
|
||||
*
|
||||
* @var Boolean
|
||||
* @access private
|
||||
*/
|
||||
var $mode_3cbc;
|
||||
|
||||
/**
|
||||
* The Crypt_DES objects
|
||||
*
|
||||
* Used only if $mode_3cbc === true
|
||||
*
|
||||
* @var Array
|
||||
* @access private
|
||||
*/
|
||||
@ -94,99 +163,73 @@ class Crypt_TripleDES extends Crypt_DES {
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
||||
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
|
||||
* 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
|
||||
*
|
||||
* - CRYPT_DES_MODE_3CBC
|
||||
*
|
||||
* If not explicitly set, CRYPT_DES_MODE_CBC will be used.
|
||||
*
|
||||
* @see Crypt_DES::Crypt_DES()
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param optional Integer $mode
|
||||
* @return Crypt_TripleDES
|
||||
* @access public
|
||||
*/
|
||||
function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
|
||||
{
|
||||
if ( !defined('CRYPT_DES_MODE') ) {
|
||||
switch (true) {
|
||||
case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()):
|
||||
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
|
||||
}
|
||||
}
|
||||
switch ($mode) {
|
||||
// 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_Base(CRYPT_DES_MODE_CBC);
|
||||
$this->mode_3cbc = true;
|
||||
|
||||
if ( $mode == CRYPT_DES_MODE_3CBC ) {
|
||||
$this->mode = CRYPT_DES_MODE_3CBC;
|
||||
$this->des = array(
|
||||
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
||||
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
||||
new Crypt_DES(CRYPT_DES_MODE_CBC)
|
||||
);
|
||||
$this->paddable = true;
|
||||
|
||||
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
|
||||
$this->des[0]->disablePadding();
|
||||
$this->des[1]->disablePadding();
|
||||
$this->des[2]->disablePadding();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( CRYPT_DES_MODE ) {
|
||||
case CRYPT_DES_MODE_MCRYPT:
|
||||
switch ($mode) {
|
||||
case CRYPT_DES_MODE_ECB:
|
||||
$this->paddable = true;
|
||||
$this->mode = MCRYPT_MODE_ECB;
|
||||
break;
|
||||
case CRYPT_DES_MODE_CTR:
|
||||
$this->mode = 'ctr';
|
||||
break;
|
||||
case CRYPT_DES_MODE_CFB:
|
||||
$this->mode = 'ncfb';
|
||||
$this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
|
||||
break;
|
||||
case CRYPT_DES_MODE_OFB:
|
||||
$this->mode = MCRYPT_MODE_NOFB;
|
||||
break;
|
||||
case CRYPT_DES_MODE_CBC:
|
||||
default:
|
||||
$this->paddable = true;
|
||||
$this->mode = MCRYPT_MODE_CBC;
|
||||
}
|
||||
$this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
|
||||
$this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
|
||||
|
||||
break;
|
||||
default:
|
||||
// This three $des'es will do the 3CBC work (if $key > 64bits)
|
||||
$this->des = array(
|
||||
new Crypt_DES(CRYPT_DES_MODE_ECB),
|
||||
new Crypt_DES(CRYPT_DES_MODE_ECB),
|
||||
new Crypt_DES(CRYPT_DES_MODE_ECB)
|
||||
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
||||
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
||||
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
||||
);
|
||||
|
||||
|
||||
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
|
||||
$this->des[0]->disablePadding();
|
||||
$this->des[1]->disablePadding();
|
||||
$this->des[2]->disablePadding();
|
||||
break;
|
||||
// If not 3CBC, we init as usual
|
||||
default:
|
||||
parent::Crypt_Base($mode);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($mode) {
|
||||
case CRYPT_DES_MODE_ECB:
|
||||
case CRYPT_DES_MODE_CBC:
|
||||
$this->paddable = true;
|
||||
$this->mode = $mode;
|
||||
break;
|
||||
case CRYPT_DES_MODE_CTR:
|
||||
case CRYPT_DES_MODE_CFB:
|
||||
case CRYPT_DES_MODE_OFB:
|
||||
$this->mode = $mode;
|
||||
break;
|
||||
default:
|
||||
$this->paddable = true;
|
||||
$this->mode = CRYPT_DES_MODE_CBC;
|
||||
}
|
||||
if (function_exists('create_function') && is_callable('create_function')) {
|
||||
$this->inline_crypt_setup(3);
|
||||
$this->use_inline_crypt = true;
|
||||
}
|
||||
/**
|
||||
* Sets the initialization vector. (optional)
|
||||
*
|
||||
* 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()
|
||||
* @access public
|
||||
* @param String $iv
|
||||
*/
|
||||
function setIV($iv)
|
||||
{
|
||||
parent::setIV($iv);
|
||||
if ($this->mode_3cbc) {
|
||||
$this->des[0]->setIV($iv);
|
||||
$this->des[1]->setIV($iv);
|
||||
$this->des[2]->setIV($iv);
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,571 +241,87 @@ class Crypt_TripleDES extends Crypt_DES {
|
||||
*
|
||||
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
|
||||
*
|
||||
* If the key is not explicitly set, it'll be assumed to be all zero's.
|
||||
* If the key is not explicitly set, it'll be assumed to be all null bytes.
|
||||
*
|
||||
* @access public
|
||||
* @see Crypt_DES::setKey()
|
||||
* @see Crypt_Base::setKey()
|
||||
* @param String $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
$length = strlen($key);
|
||||
if ($length > 8) {
|
||||
$key = str_pad($key, 24, chr(0));
|
||||
$key = str_pad(substr($key, 0, 24), 24, chr(0));
|
||||
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
|
||||
// http://php.net/function.mcrypt-encrypt#47973
|
||||
//$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
|
||||
} else {
|
||||
$key = str_pad($key, 8, chr(0));
|
||||
}
|
||||
$this->key = $key;
|
||||
switch (true) {
|
||||
case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL:
|
||||
case $this->mode == CRYPT_DES_MODE_3CBC:
|
||||
$this->des[0]->setKey(substr($key, 0, 8));
|
||||
$this->des[1]->setKey(substr($key, 8, 8));
|
||||
$this->des[2]->setKey(substr($key, 16, 8));
|
||||
parent::setKey($key);
|
||||
|
||||
// Merge the three DES-1-dim-key-arrays for 3DES-inline-en/decrypting
|
||||
if ($this->use_inline_crypt && $this->mode != CRYPT_DES_MODE_3CBC) {
|
||||
$this->keys = array(
|
||||
CRYPT_DES_ENCRYPT_1DIM => array_merge(
|
||||
$this->des[0]->keys[CRYPT_DES_ENCRYPT_1DIM],
|
||||
$this->des[1]->keys[CRYPT_DES_DECRYPT_1DIM],
|
||||
$this->des[2]->keys[CRYPT_DES_ENCRYPT_1DIM]
|
||||
),
|
||||
CRYPT_DES_DECRYPT_1DIM => array_merge(
|
||||
$this->des[2]->keys[CRYPT_DES_DECRYPT_1DIM],
|
||||
$this->des[1]->keys[CRYPT_DES_ENCRYPT_1DIM],
|
||||
$this->des[0]->keys[CRYPT_DES_DECRYPT_1DIM]
|
||||
),
|
||||
);
|
||||
}
|
||||
// And in case of CRYPT_DES_MODE_3CBC:
|
||||
// if key <= 64bits we not need the 3 $des to work,
|
||||
// because we will then act as regular DES-CBC with just a <= 64bit key.
|
||||
// So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
|
||||
if ($this->mode_3cbc && $length > 8) {
|
||||
$this->des[0]->setKey(substr($key, 0, 8));
|
||||
$this->des[1]->setKey(substr($key, 8, 8));
|
||||
$this->des[2]->setKey(substr($key, 16, 8));
|
||||
}
|
||||
$this->enchanged = $this->dechanged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}:
|
||||
* $hash, $salt, $method
|
||||
*
|
||||
* @param String $password
|
||||
* @param optional String $method
|
||||
* @access public
|
||||
*/
|
||||
function setPassword($password, $method = 'pbkdf2')
|
||||
{
|
||||
$key = '';
|
||||
|
||||
switch ($method) {
|
||||
default: // 'pbkdf2'
|
||||
list(, , $hash, $salt, $count) = func_get_args();
|
||||
if (!isset($hash)) {
|
||||
$hash = 'sha1';
|
||||
}
|
||||
// WPA and WPA2 use the SSID as the salt
|
||||
if (!isset($salt)) {
|
||||
$salt = 'phpseclib';
|
||||
}
|
||||
// RFC2898#section-4.2 uses 1,000 iterations by default
|
||||
// WPA and WPA2 use 4,096.
|
||||
if (!isset($count)) {
|
||||
$count = 1000;
|
||||
}
|
||||
|
||||
if (!class_exists('Crypt_Hash')) {
|
||||
require_once('Crypt/Hash.php');
|
||||
}
|
||||
|
||||
$i = 1;
|
||||
while (strlen($key) < 24) { // $dkLen == 24
|
||||
$hmac = new Crypt_Hash();
|
||||
$hmac->setHash($hash);
|
||||
$hmac->setKey($password);
|
||||
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
||||
for ($j = 2; $j <= $count; $j++) {
|
||||
$u = $hmac->hash($u);
|
||||
$f^= $u;
|
||||
}
|
||||
$key.= $f;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* to be all zero's.
|
||||
*
|
||||
* @access public
|
||||
* @param String $iv
|
||||
*/
|
||||
function setIV($iv)
|
||||
{
|
||||
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
|
||||
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
||||
$this->des[0]->setIV($iv);
|
||||
$this->des[1]->setIV($iv);
|
||||
$this->des[2]->setIV($iv);
|
||||
}
|
||||
$this->enchanged = $this->dechanged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a message.
|
||||
*
|
||||
* @see Crypt_Base::encrypt()
|
||||
* @access public
|
||||
* @param String $plaintext
|
||||
* @return String $cipertext
|
||||
*/
|
||||
function encrypt($plaintext)
|
||||
{
|
||||
if ($this->paddable) {
|
||||
$plaintext = $this->_pad($plaintext);
|
||||
}
|
||||
// parent::en/decrypt() is able to do all the work for all modes and keylengths,
|
||||
// except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits
|
||||
|
||||
// if the key is smaller then 8, do what we'd normally do
|
||||
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
|
||||
$ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext)));
|
||||
|
||||
return $ciphertext;
|
||||
if ($this->mode_3cbc && strlen($this->key) > 8) {
|
||||
return $this->des[2]->encrypt(
|
||||
$this->des[1]->decrypt(
|
||||
$this->des[0]->encrypt(
|
||||
$this->_pad($plaintext)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
||||
if ($this->enchanged) {
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
||||
if ($this->mode == 'ncfb') {
|
||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
||||
}
|
||||
$this->enchanged = false;
|
||||
}
|
||||
|
||||
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
||||
} else {
|
||||
$iv = &$this->encryptIV;
|
||||
$pos = &$this->enbuffer['pos'];
|
||||
$len = strlen($plaintext);
|
||||
$ciphertext = '';
|
||||
$i = 0;
|
||||
if ($pos) {
|
||||
$orig_pos = $pos;
|
||||
$max = 8 - $pos;
|
||||
if ($len >= $max) {
|
||||
$i = $max;
|
||||
$len-= $max;
|
||||
$pos = 0;
|
||||
} else {
|
||||
$i = $len;
|
||||
$pos+= $len;
|
||||
$len = 0;
|
||||
}
|
||||
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
||||
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
||||
$this->enbuffer['enmcrypt_init'] = true;
|
||||
}
|
||||
if ($len >= 8) {
|
||||
if ($this->enbuffer['enmcrypt_init'] === false || $len > 950) {
|
||||
if ($this->enbuffer['enmcrypt_init'] === true) {
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
||||
$this->enbuffer['enmcrypt_init'] = false;
|
||||
}
|
||||
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
|
||||
$iv = substr($ciphertext, -8);
|
||||
$i = strlen($ciphertext);
|
||||
$len%= 8;
|
||||
} else {
|
||||
while ($len >= 8) {
|
||||
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
|
||||
$ciphertext.= $iv;
|
||||
$len-= 8;
|
||||
$i+= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($len) {
|
||||
$iv = mcrypt_generic($this->ecb, $iv);
|
||||
$block = $iv ^ substr($plaintext, $i);
|
||||
$iv = substr_replace($iv, $block, 0, $len);
|
||||
$ciphertext.= $block;
|
||||
$pos = $len;
|
||||
}
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
if (strlen($this->key) <= 8) {
|
||||
$this->des[0]->mode = $this->mode;
|
||||
|
||||
return $this->des[0]->encrypt($plaintext);
|
||||
}
|
||||
|
||||
if ($this->use_inline_crypt) {
|
||||
$inline = $this->inline_crypt;
|
||||
return $inline('encrypt', $this, $plaintext);
|
||||
}
|
||||
|
||||
$des = $this->des;
|
||||
|
||||
$buffer = &$this->enbuffer;
|
||||
$continuousBuffer = $this->continuousBuffer;
|
||||
$ciphertext = '';
|
||||
switch ($this->mode) {
|
||||
case CRYPT_DES_MODE_ECB:
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
||||
$block = substr($plaintext, $i, 8);
|
||||
// all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something.
|
||||
// only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that
|
||||
// function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make
|
||||
// encryption and decryption take more time, per this:
|
||||
//
|
||||
// http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html
|
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
|
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
||||
$ciphertext.= $block;
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_CBC:
|
||||
$xor = $this->encryptIV;
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
||||
$block = substr($plaintext, $i, 8) ^ $xor;
|
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
|
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
||||
$xor = $block;
|
||||
$ciphertext.= $block;
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$this->encryptIV = $xor;
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_CTR:
|
||||
$xor = $this->encryptIV;
|
||||
if (strlen($buffer['encrypted'])) {
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
||||
$block = substr($plaintext, $i, 8);
|
||||
if (strlen($block) > strlen($buffer['encrypted'])) {
|
||||
$key = $this->_generate_xor($xor);
|
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$buffer['encrypted'].= $key;
|
||||
}
|
||||
$key = $this->_string_shift($buffer['encrypted']);
|
||||
$ciphertext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
||||
$block = substr($plaintext, $i, 8);
|
||||
$key = $this->_generate_xor($xor);
|
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$ciphertext.= $block ^ $key;
|
||||
}
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$this->encryptIV = $xor;
|
||||
if ($start = strlen($plaintext) & 7) {
|
||||
$buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_CFB:
|
||||
if (strlen($buffer['xor'])) {
|
||||
$ciphertext = $plaintext ^ $buffer['xor'];
|
||||
$iv = $buffer['encrypted'] . $ciphertext;
|
||||
$start = strlen($ciphertext);
|
||||
$buffer['encrypted'].= $ciphertext;
|
||||
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
|
||||
} else {
|
||||
$ciphertext = '';
|
||||
$iv = $this->encryptIV;
|
||||
$start = 0;
|
||||
}
|
||||
|
||||
for ($i = $start; $i < strlen($plaintext); $i+=8) {
|
||||
$block = substr($plaintext, $i, 8);
|
||||
$iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
||||
$iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
|
||||
$xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
||||
|
||||
$iv = $block ^ $xor;
|
||||
if ($continuousBuffer && strlen($iv) != 8) {
|
||||
$buffer = array(
|
||||
'encrypted' => $iv,
|
||||
'xor' => substr($xor, strlen($iv))
|
||||
);
|
||||
}
|
||||
$ciphertext.= $iv;
|
||||
}
|
||||
|
||||
if ($this->continuousBuffer) {
|
||||
$this->encryptIV = $iv;
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_OFB:
|
||||
$xor = $this->encryptIV;
|
||||
if (strlen($buffer['xor'])) {
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
||||
$block = substr($plaintext, $i, 8);
|
||||
if (strlen($block) > strlen($buffer['xor'])) {
|
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$buffer['xor'].= $xor;
|
||||
}
|
||||
$key = $this->_string_shift($buffer['xor']);
|
||||
$ciphertext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$ciphertext.= substr($plaintext, $i, 8) ^ $xor;
|
||||
}
|
||||
$key = $xor;
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$this->encryptIV = $xor;
|
||||
if ($start = strlen($plaintext) & 7) {
|
||||
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
return parent::encrypt($plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a message.
|
||||
*
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @access public
|
||||
* @param String $ciphertext
|
||||
* @return String $plaintext
|
||||
*/
|
||||
function decrypt($ciphertext)
|
||||
{
|
||||
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
|
||||
$plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext)));
|
||||
|
||||
return $this->_unpad($plaintext);
|
||||
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")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->paddable) {
|
||||
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
||||
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
||||
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
|
||||
}
|
||||
|
||||
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
||||
if ($this->dechanged) {
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
||||
if ($this->mode == 'ncfb') {
|
||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
||||
}
|
||||
$this->dechanged = false;
|
||||
}
|
||||
|
||||
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
||||
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
||||
} else {
|
||||
$iv = &$this->decryptIV;
|
||||
$pos = &$this->debuffer['pos'];
|
||||
$len = strlen($ciphertext);
|
||||
$plaintext = '';
|
||||
$i = 0;
|
||||
if ($pos) {
|
||||
$orig_pos = $pos;
|
||||
$max = 8 - $pos;
|
||||
if ($len >= $max) {
|
||||
$i = $max;
|
||||
$len-= $max;
|
||||
$pos = 0;
|
||||
} else {
|
||||
$i = $len;
|
||||
$pos+= $len;
|
||||
$len = 0;
|
||||
}
|
||||
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
||||
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
||||
}
|
||||
if ($len >= 8) {
|
||||
$cb = substr($ciphertext, $i, $len - $len % 8);
|
||||
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
||||
$iv = substr($cb, -8);
|
||||
$len%= 8;
|
||||
}
|
||||
if ($len) {
|
||||
$iv = mcrypt_generic($this->ecb, $iv);
|
||||
$cb = substr($ciphertext, -$len);
|
||||
$plaintext.= $iv ^ $cb;
|
||||
$iv = substr_replace($iv, $cb, 0, $len);
|
||||
$pos = $len;
|
||||
}
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
||||
}
|
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
}
|
||||
|
||||
if (strlen($this->key) <= 8) {
|
||||
$this->des[0]->mode = $this->mode;
|
||||
$plaintext = $this->des[0]->decrypt($ciphertext);
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
}
|
||||
|
||||
if ($this->use_inline_crypt) {
|
||||
$inline = $this->inline_crypt;
|
||||
return $inline('decrypt', $this, $ciphertext);
|
||||
}
|
||||
|
||||
$des = $this->des;
|
||||
|
||||
$buffer = &$this->debuffer;
|
||||
$continuousBuffer = $this->continuousBuffer;
|
||||
$plaintext = '';
|
||||
switch ($this->mode) {
|
||||
case CRYPT_DES_MODE_ECB:
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
||||
$block = substr($ciphertext, $i, 8);
|
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
|
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
|
||||
$plaintext.= $block;
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_CBC:
|
||||
$xor = $this->decryptIV;
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
||||
$orig = $block = substr($ciphertext, $i, 8);
|
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
|
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
|
||||
$plaintext.= $block ^ $xor;
|
||||
$xor = $orig;
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$this->decryptIV = $xor;
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_CTR:
|
||||
$xor = $this->decryptIV;
|
||||
if (strlen($buffer['ciphertext'])) {
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
||||
$block = substr($ciphertext, $i, 8);
|
||||
if (strlen($block) > strlen($buffer['ciphertext'])) {
|
||||
$key = $this->_generate_xor($xor);
|
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$buffer['ciphertext'].= $key;
|
||||
}
|
||||
$key = $this->_string_shift($buffer['ciphertext']);
|
||||
$plaintext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
||||
$block = substr($ciphertext, $i, 8);
|
||||
$key = $this->_generate_xor($xor);
|
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
||||
$plaintext.= $block ^ $key;
|
||||
}
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$this->decryptIV = $xor;
|
||||
if ($start = strlen($plaintext) & 7) {
|
||||
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_CFB:
|
||||
if (strlen($buffer['ciphertext'])) {
|
||||
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
|
||||
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
|
||||
if (strlen($buffer['ciphertext']) != 8) {
|
||||
$block = $this->decryptIV;
|
||||
} else {
|
||||
$block = $buffer['ciphertext'];
|
||||
$xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
|
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$buffer['ciphertext'] = '';
|
||||
}
|
||||
$start = strlen($plaintext);
|
||||
} else {
|
||||
$plaintext = '';
|
||||
$xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
|
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$start = 0;
|
||||
}
|
||||
|
||||
for ($i = $start; $i < strlen($ciphertext); $i+=8) {
|
||||
$block = substr($ciphertext, $i, 8);
|
||||
$plaintext.= $block ^ $xor;
|
||||
if ($continuousBuffer && strlen($block) != 8) {
|
||||
$buffer['ciphertext'].= $block;
|
||||
$block = $xor;
|
||||
} else if (strlen($block) == 8) {
|
||||
$xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
}
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$this->decryptIV = $block;
|
||||
}
|
||||
break;
|
||||
case CRYPT_DES_MODE_OFB:
|
||||
$xor = $this->decryptIV;
|
||||
if (strlen($buffer['xor'])) {
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
||||
$block = substr($ciphertext, $i, 8);
|
||||
if (strlen($block) > strlen($buffer['xor'])) {
|
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$buffer['xor'].= $xor;
|
||||
}
|
||||
$key = $this->_string_shift($buffer['xor']);
|
||||
$plaintext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
||||
$plaintext.= substr($ciphertext, $i, 8) ^ $xor;
|
||||
}
|
||||
$key = $xor;
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$this->decryptIV = $xor;
|
||||
if ($start = strlen($ciphertext) & 7) {
|
||||
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
return parent::decrypt($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -799,13 +358,14 @@ class Crypt_TripleDES extends Crypt_DES {
|
||||
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
||||
* however, they are also less intuitive and more likely to cause you problems.
|
||||
*
|
||||
* @see Crypt_Base::enableContinuousBuffer()
|
||||
* @see Crypt_TripleDES::disableContinuousBuffer()
|
||||
* @access public
|
||||
*/
|
||||
function enableContinuousBuffer()
|
||||
{
|
||||
$this->continuousBuffer = true;
|
||||
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
||||
parent::enableContinuousBuffer();
|
||||
if ($this->mode_3cbc) {
|
||||
$this->des[0]->enableContinuousBuffer();
|
||||
$this->des[1]->enableContinuousBuffer();
|
||||
$this->des[2]->enableContinuousBuffer();
|
||||
@ -817,26 +377,52 @@ class Crypt_TripleDES extends Crypt_DES {
|
||||
*
|
||||
* The default behavior.
|
||||
*
|
||||
* @see Crypt_Base::disableContinuousBuffer()
|
||||
* @see Crypt_TripleDES::enableContinuousBuffer()
|
||||
* @access public
|
||||
*/
|
||||
function disableContinuousBuffer()
|
||||
{
|
||||
$this->continuousBuffer = false;
|
||||
$this->encryptIV = $this->iv;
|
||||
$this->decryptIV = $this->iv;
|
||||
$this->enchanged = true;
|
||||
$this->dechanged = true;
|
||||
$this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
||||
$this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
||||
|
||||
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
||||
parent::disableContinuousBuffer();
|
||||
if ($this->mode_3cbc) {
|
||||
$this->des[0]->disableContinuousBuffer();
|
||||
$this->des[1]->disableContinuousBuffer();
|
||||
$this->des[2]->disableContinuousBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: ts=4:sw=4:et:
|
||||
// vim6: fdl=1:
|
||||
/**
|
||||
* Creates the key schedule
|
||||
*
|
||||
* @see Crypt_DES::_setupKey()
|
||||
* @see Crypt_Base::_setupKey()
|
||||
* @access private
|
||||
*/
|
||||
function _setupKey()
|
||||
{
|
||||
switch (true) {
|
||||
// if $key <= 64bits we configure our internal pure-php cipher engine
|
||||
// to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
|
||||
case strlen($this->key) <= 8:
|
||||
$this->des_rounds = 1;
|
||||
break;
|
||||
|
||||
// otherwise, if $key > 64bits, we configure our engine to work as 3DES.
|
||||
default:
|
||||
$this->des_rounds = 3;
|
||||
|
||||
// (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
|
||||
if ($this->mode_3cbc) {
|
||||
$this->des[0]->_setupKey();
|
||||
$this->des[1]->_setupKey();
|
||||
$this->des[2]->_setupKey();
|
||||
|
||||
// because $des[0-2] will, now, do all the work we can return here
|
||||
// not need unnecessary stress parent::_setupKey() with our, now unused, $key.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// setup our key
|
||||
parent::_setupKey();
|
||||
}
|
||||
}
|
||||
|
1327
Crypt/Twofish.php
1327
Crypt/Twofish.php
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP ANSI Decoder
|
||||
@ -17,10 +16,10 @@
|
||||
* 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
|
||||
@ -29,23 +28,23 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category File
|
||||
* @package File_ANSI
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMXII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category File
|
||||
* @package File_ANSI
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMXII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pure-PHP ANSI Decoder
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.3.0
|
||||
* @access public
|
||||
* @package File_ANSI
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class File_ANSI {
|
||||
class File_ANSI
|
||||
{
|
||||
/**
|
||||
* Max Width
|
||||
*
|
||||
@ -351,7 +350,7 @@ class File_ANSI {
|
||||
$this->attrs[$this->y][$this->x] = '';
|
||||
|
||||
if ($this->bold) $this->attrs[$this->y][$this->x].= '</b>';
|
||||
if ($this->underline) $this->attrs[$this->y][$this->x].= '</underline>';
|
||||
if ($this->underline) $this->attrs[$this->y][$this->x].= '</u>';
|
||||
if ($this->blink) $this->attrs[$this->y][$this->x].= '</blink>';
|
||||
if ($this->color) $this->attrs[$this->y][$this->x].= '</span>';
|
||||
|
||||
@ -557,4 +556,4 @@ class File_ANSI {
|
||||
|
||||
return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $scrollback . '</pre>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
629
File/ASN1.php
629
File/ASN1.php
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP ASN.1 Parser
|
||||
@ -20,10 +19,10 @@
|
||||
* 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
|
||||
@ -32,12 +31,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category File
|
||||
* @package File_ASN1
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMXII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category File
|
||||
* @package File_ASN1
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMXII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
@ -58,21 +57,21 @@ define('FILE_ASN1_CLASS_PRIVATE', 3);
|
||||
* @access private
|
||||
* @link http://www.obj-sys.com/asn1tutorial/node124.html
|
||||
*/
|
||||
define('FILE_ASN1_TYPE_BOOLEAN', 1);
|
||||
define('FILE_ASN1_TYPE_INTEGER', 2);
|
||||
define('FILE_ASN1_TYPE_BIT_STRING', 3);
|
||||
define('FILE_ASN1_TYPE_OCTET_STRING', 4);
|
||||
define('FILE_ASN1_TYPE_NULL', 5);
|
||||
define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER',6);
|
||||
//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR',7);
|
||||
//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
|
||||
define('FILE_ASN1_TYPE_REAL', 9);
|
||||
define('FILE_ASN1_TYPE_ENUMERATED', 10);
|
||||
//define('FILE_ASN1_TYPE_EMBEDDED', 11);
|
||||
define('FILE_ASN1_TYPE_UTF8_STRING', 12);
|
||||
//define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
|
||||
define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
|
||||
define('FILE_ASN1_TYPE_SET', 17); // SET OF
|
||||
define('FILE_ASN1_TYPE_BOOLEAN', 1);
|
||||
define('FILE_ASN1_TYPE_INTEGER', 2);
|
||||
define('FILE_ASN1_TYPE_BIT_STRING', 3);
|
||||
define('FILE_ASN1_TYPE_OCTET_STRING', 4);
|
||||
define('FILE_ASN1_TYPE_NULL', 5);
|
||||
define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6);
|
||||
//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7);
|
||||
//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
|
||||
define('FILE_ASN1_TYPE_REAL', 9);
|
||||
define('FILE_ASN1_TYPE_ENUMERATED', 10);
|
||||
//define('FILE_ASN1_TYPE_EMBEDDED', 11);
|
||||
define('FILE_ASN1_TYPE_UTF8_STRING', 12);
|
||||
//define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
|
||||
define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
|
||||
define('FILE_ASN1_TYPE_SET', 17); // SET OF
|
||||
/**#@-*/
|
||||
/**#@+
|
||||
* More Tag Classes
|
||||
@ -80,19 +79,19 @@ define('FILE_ASN1_TYPE_SET', 17); // SET OF
|
||||
* @access private
|
||||
* @link http://www.obj-sys.com/asn1tutorial/node10.html
|
||||
*/
|
||||
define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
|
||||
define('FILE_ASN1_TYPE_PRINTABLE_STRING',19);
|
||||
define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
|
||||
define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
|
||||
define('FILE_ASN1_TYPE_IA5_STRING', 22);
|
||||
define('FILE_ASN1_TYPE_UTC_TIME', 23);
|
||||
define('FILE_ASN1_TYPE_GENERALIZED_TIME',24);
|
||||
define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
|
||||
define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
|
||||
define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
|
||||
define('FILE_ASN1_TYPE_UNIVERSAL_STRING',28);
|
||||
//define('FILE_ASN1_TYPE_CHARACTER_STRING',29);
|
||||
define('FILE_ASN1_TYPE_BMP_STRING', 30);
|
||||
define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
|
||||
define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19);
|
||||
define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
|
||||
define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
|
||||
define('FILE_ASN1_TYPE_IA5_STRING', 22);
|
||||
define('FILE_ASN1_TYPE_UTC_TIME', 23);
|
||||
define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24);
|
||||
define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
|
||||
define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
|
||||
define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
|
||||
define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28);
|
||||
//define('FILE_ASN1_TYPE_CHARACTER_STRING', 29);
|
||||
define('FILE_ASN1_TYPE_BMP_STRING', 30);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
@ -111,12 +110,12 @@ define('FILE_ASN1_TYPE_ANY', -2);
|
||||
*
|
||||
* Bypass normal encoding rules in File_ASN1::encodeDER()
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.3.0
|
||||
* @access public
|
||||
* @package File_ASN1
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class File_ASN1_Element {
|
||||
class File_ASN1_Element
|
||||
{
|
||||
/**
|
||||
* Raw element value
|
||||
*
|
||||
@ -141,12 +140,12 @@ class File_ASN1_Element {
|
||||
/**
|
||||
* Pure-PHP ASN.1 Parser
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.3.0
|
||||
* @access public
|
||||
* @package File_ASN1
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class File_ASN1 {
|
||||
class File_ASN1
|
||||
{
|
||||
/**
|
||||
* ASN.1 object identifier
|
||||
*
|
||||
@ -163,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
|
||||
@ -252,7 +251,7 @@ class File_ASN1 {
|
||||
if (!$static_init) {
|
||||
$static_init = true;
|
||||
if (!class_exists('Math_BigInteger')) {
|
||||
require_once('Math/BigInteger.php');
|
||||
include_once 'Math/BigInteger.php';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -273,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));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -288,226 +288,247 @@ 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:
|
||||
$newcontent = $this->_decode_ber($content, $start);
|
||||
$length = $newcontent['length'];
|
||||
if (substr($content, $length, 2) == "\0\0") {
|
||||
$length+= 2;
|
||||
}
|
||||
|
||||
$start+= $length;
|
||||
|
||||
return array(
|
||||
'type' => $class,
|
||||
'constant' => $tag,
|
||||
// the array encapsulation is for BC with the old format
|
||||
'content' => array($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.
|
||||
*
|
||||
* "Special" mappings may be applied on a per tag-name basis via $special.
|
||||
*
|
||||
* @param Array $decoded
|
||||
* @param Array $mapping
|
||||
* @param Array $special
|
||||
* @return Array
|
||||
* @access public
|
||||
*/
|
||||
function asn1map($decoded, $mapping)
|
||||
function asn1map($decoded, $mapping, $special = array())
|
||||
{
|
||||
if (isset($mapping['explicit'])) {
|
||||
if (isset($mapping['explicit']) && is_array($decoded['content'])) {
|
||||
$decoded = $decoded['content'][0];
|
||||
}
|
||||
|
||||
@ -519,7 +540,7 @@ class File_ASN1 {
|
||||
}
|
||||
$inmap = $this->ANYmap[$intype];
|
||||
if (is_string($inmap)) {
|
||||
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping));
|
||||
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
|
||||
}
|
||||
break;
|
||||
case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
|
||||
@ -527,25 +548,36 @@ class File_ASN1 {
|
||||
switch (true) {
|
||||
case isset($option['constant']) && $option['constant'] == $decoded['constant']:
|
||||
case !isset($option['constant']) && $option['type'] == $decoded['type']:
|
||||
$value = $this->asn1map($decoded, $option);
|
||||
$value = $this->asn1map($decoded, $option, $special);
|
||||
break;
|
||||
case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
|
||||
$v = $this->asn1map($decoded, $option);
|
||||
$v = $this->asn1map($decoded, $option, $special);
|
||||
if (isset($v)) {
|
||||
$value = $v;
|
||||
}
|
||||
}
|
||||
if (isset($value)) {
|
||||
if (isset($special[$key])) {
|
||||
$value = call_user_func($special[$key], $value);
|
||||
}
|
||||
return array($key => $value);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return null;
|
||||
case isset($mapping['implicit']):
|
||||
case isset($mapping['explicit']):
|
||||
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'])) {
|
||||
@ -560,8 +592,8 @@ class File_ASN1 {
|
||||
if (isset($mapping['min']) && isset($mapping['max'])) {
|
||||
$child = $mapping['children'];
|
||||
foreach ($decoded['content'] as $content) {
|
||||
if (($map[] = $this->asn1map($content, $child)) === NULL) {
|
||||
return NULL;
|
||||
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,15 +611,14 @@ class File_ASN1 {
|
||||
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
|
||||
// Get the mapping and input class & constant.
|
||||
$childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
|
||||
$constant = NULL;
|
||||
$constant = null;
|
||||
if (isset($temp['constant'])) {
|
||||
$tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
|
||||
}
|
||||
if (isset($child['class'])) {
|
||||
$childClass = $child['class'];
|
||||
$constant = $child['cast'];
|
||||
}
|
||||
elseif (isset($child['constant'])) {
|
||||
} elseif (isset($child['constant'])) {
|
||||
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
|
||||
$constant = $child['constant'];
|
||||
}
|
||||
@ -604,23 +635,26 @@ class File_ASN1 {
|
||||
|
||||
if ($maymatch) {
|
||||
// Attempt submapping.
|
||||
$candidate = $this->asn1map($temp, $child);
|
||||
$maymatch = $candidate !== NULL;
|
||||
$candidate = $this->asn1map($temp, $child, $special);
|
||||
$maymatch = $candidate !== null;
|
||||
}
|
||||
|
||||
if ($maymatch) {
|
||||
// Got the match: use it.
|
||||
if (isset($special[$key])) {
|
||||
$candidate = call_user_func($special[$key], $candidate);
|
||||
}
|
||||
$map[$key] = $candidate;
|
||||
$i++;
|
||||
} elseif (isset($child['default'])) {
|
||||
$map[$key] = $child['default']; // Use default.
|
||||
} elseif (!isset($child['optional'])) {
|
||||
return NULL; // Syntax error.
|
||||
return null; // Syntax error.
|
||||
}
|
||||
}
|
||||
|
||||
// Fail mapping if all input items have not been consumed.
|
||||
return $i < $n? NULL: $map;
|
||||
return $i < $n? null: $map;
|
||||
|
||||
// the main diff between sets and sequences is the encapsulation of the foreach in another for loop
|
||||
case FILE_ASN1_TYPE_SET:
|
||||
@ -630,8 +664,8 @@ class File_ASN1 {
|
||||
if (isset($mapping['min']) && isset($mapping['max'])) {
|
||||
$child = $mapping['children'];
|
||||
foreach ($decoded['content'] as $content) {
|
||||
if (($map[] = $this->asn1map($content, $child)) === NULL) {
|
||||
return NULL;
|
||||
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -652,12 +686,11 @@ class File_ASN1 {
|
||||
$maymatch = true;
|
||||
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
|
||||
$childClass = FILE_ASN1_CLASS_UNIVERSAL;
|
||||
$constant = NULL;
|
||||
$constant = null;
|
||||
if (isset($child['class'])) {
|
||||
$childClass = $child['class'];
|
||||
$constant = $child['cast'];
|
||||
}
|
||||
elseif (isset($child['constant'])) {
|
||||
} elseif (isset($child['constant'])) {
|
||||
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
|
||||
$constant = $child['constant'];
|
||||
}
|
||||
@ -673,8 +706,8 @@ class File_ASN1 {
|
||||
|
||||
if ($maymatch) {
|
||||
// Attempt submapping.
|
||||
$candidate = $this->asn1map($temp, $child);
|
||||
$maymatch = $candidate !== NULL;
|
||||
$candidate = $this->asn1map($temp, $child, $special);
|
||||
$maymatch = $candidate !== null;
|
||||
}
|
||||
|
||||
if (!$maymatch) {
|
||||
@ -682,6 +715,9 @@ class File_ASN1 {
|
||||
}
|
||||
|
||||
// Got the match: use it.
|
||||
if (isset($special[$key])) {
|
||||
$candidate = call_user_func($special[$key], $candidate);
|
||||
}
|
||||
$map[$key] = $candidate;
|
||||
break;
|
||||
}
|
||||
@ -692,7 +728,7 @@ class File_ASN1 {
|
||||
if (isset($child['default'])) {
|
||||
$map[$key] = $child['default'];
|
||||
} elseif (!isset($child['optional'])) {
|
||||
return NULL;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -774,16 +810,18 @@ class File_ASN1 {
|
||||
* DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
|
||||
* an ASN.1 compiler.
|
||||
*
|
||||
* "Special" mappings can be applied via $special.
|
||||
*
|
||||
* @param String $source
|
||||
* @param String $mapping
|
||||
* @param Integer $idx
|
||||
* @return String
|
||||
* @access public
|
||||
*/
|
||||
function encodeDER($source, $mapping)
|
||||
function encodeDER($source, $mapping, $special = array())
|
||||
{
|
||||
$this->location = array();
|
||||
return $this->_encode_der($source, $mapping);
|
||||
return $this->_encode_der($source, $mapping, null, $special);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -795,7 +833,7 @@ class File_ASN1 {
|
||||
* @return String
|
||||
* @access private
|
||||
*/
|
||||
function _encode_der($source, $mapping, $idx = NULL)
|
||||
function _encode_der($source, $mapping, $idx = null, $special = array())
|
||||
{
|
||||
if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
|
||||
return $source->element;
|
||||
@ -807,6 +845,9 @@ class File_ASN1 {
|
||||
}
|
||||
|
||||
if (isset($idx)) {
|
||||
if (isset($special[$idx])) {
|
||||
$source = call_user_func($special[$idx], $source);
|
||||
}
|
||||
$this->location[] = $idx;
|
||||
}
|
||||
|
||||
@ -823,7 +864,7 @@ class File_ASN1 {
|
||||
$child = $mapping['children'];
|
||||
|
||||
foreach ($source as $content) {
|
||||
$temp = $this->_encode_der($content, $child);
|
||||
$temp = $this->_encode_der($content, $child, null, $special);
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
@ -840,7 +881,7 @@ class File_ASN1 {
|
||||
continue;
|
||||
}
|
||||
|
||||
$temp = $this->_encode_der($source[$key], $child, $key);
|
||||
$temp = $this->_encode_der($source[$key], $child, $key, $special);
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
@ -881,7 +922,7 @@ class File_ASN1 {
|
||||
continue;
|
||||
}
|
||||
|
||||
$temp = $this->_encode_der($source[$key], $child, $key);
|
||||
$temp = $this->_encode_der($source[$key], $child, $key, $special);
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
@ -918,6 +959,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']);
|
||||
@ -926,9 +970,9 @@ class File_ASN1 {
|
||||
}
|
||||
$value = new Math_BigInteger($value);
|
||||
$value = $value->toBytes(true);
|
||||
if (!strlen($value)) {
|
||||
$value = chr(0);
|
||||
}
|
||||
}
|
||||
if (!strlen($value)) {
|
||||
$value = chr(0);
|
||||
}
|
||||
break;
|
||||
case FILE_ASN1_TYPE_UTC_TIME:
|
||||
@ -948,6 +992,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;
|
||||
|
||||
@ -1003,19 +1051,19 @@ class File_ASN1 {
|
||||
|
||||
switch (true) {
|
||||
case !isset($source):
|
||||
return $this->_encode_der(NULL, array('type' => FILE_ASN1_TYPE_NULL) + $mapping);
|
||||
return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special);
|
||||
case is_int($source):
|
||||
case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping);
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special);
|
||||
case is_float($source):
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping);
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special);
|
||||
case is_bool($source):
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping);
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special);
|
||||
case is_array($source) && count($source) == 1:
|
||||
$typename = implode('', array_keys($source));
|
||||
$outtype = array_search($typename, $this->ANYmap, true);
|
||||
if ($outtype !== false) {
|
||||
return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping);
|
||||
return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1031,7 +1079,7 @@ class File_ASN1 {
|
||||
user_error('No filters defined for ' . implode('/', $loc));
|
||||
return false;
|
||||
}
|
||||
return $this->_encode_der($source, $filters + $mapping);
|
||||
return $this->_encode_der($source, $filters + $mapping, null, $special);
|
||||
case FILE_ASN1_TYPE_NULL:
|
||||
$value = '';
|
||||
break;
|
||||
@ -1061,7 +1109,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;
|
||||
|
544
File/X509.php
544
File/X509.php
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP arbitrary precision integer arithmetic library.
|
||||
@ -9,7 +8,7 @@
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
|
||||
* {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
|
||||
* {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
|
||||
*
|
||||
* Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
|
||||
@ -20,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)
|
||||
*
|
||||
@ -36,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);
|
||||
@ -53,10 +48,10 @@
|
||||
* 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
|
||||
@ -65,12 +60,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Math
|
||||
* @package Math_BigInteger
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVI Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
* @category Math
|
||||
* @package Math_BigInteger
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVI Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
@ -174,12 +169,12 @@ define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
|
||||
* Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
|
||||
* numbers.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 1.0.0RC4
|
||||
* @access public
|
||||
* @package Math_BigInteger
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Math_BigInteger {
|
||||
class Math_BigInteger
|
||||
{
|
||||
/**
|
||||
* Holds the BigInteger's value.
|
||||
*
|
||||
@ -223,7 +218,7 @@ class Math_BigInteger {
|
||||
/**
|
||||
* Mode independent value used for serialization.
|
||||
*
|
||||
* If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
|
||||
* If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
|
||||
* a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
|
||||
* however, $this->hex is only calculated when $this->__sleep() is called.
|
||||
*
|
||||
@ -242,13 +237,13 @@ class Math_BigInteger {
|
||||
*
|
||||
* Here's an example:
|
||||
* <code>
|
||||
* <?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
|
||||
* ?>
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* @param optional $x base-10 number or base-$base number if $base set.
|
||||
@ -272,7 +267,31 @@ class Math_BigInteger {
|
||||
}
|
||||
|
||||
if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
|
||||
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
|
||||
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
|
||||
ob_start();
|
||||
@phpinfo();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
|
||||
|
||||
$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])));
|
||||
}
|
||||
}
|
||||
|
||||
// it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
|
||||
switch (true) {
|
||||
case !isset($versions['Header']):
|
||||
case !isset($versions['Library']):
|
||||
case $versions['Header'] == $versions['Library']:
|
||||
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
|
||||
break;
|
||||
default:
|
||||
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined('PHP_INT_SIZE')) {
|
||||
@ -438,7 +457,6 @@ class Math_BigInteger {
|
||||
}
|
||||
|
||||
$x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
|
||||
|
||||
while (strlen($x)) {
|
||||
$temp = $temp->multiply($multiplier);
|
||||
$temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
|
||||
@ -488,7 +506,7 @@ class Math_BigInteger {
|
||||
* Here's an example:
|
||||
* <code>
|
||||
* <?php
|
||||
* include('Math/BigInteger.php');
|
||||
* include 'Math/BigInteger.php';
|
||||
*
|
||||
* $a = new Math_BigInteger('65');
|
||||
*
|
||||
@ -585,7 +603,7 @@ class Math_BigInteger {
|
||||
* Here's an example:
|
||||
* <code>
|
||||
* <?php
|
||||
* include('Math/BigInteger.php');
|
||||
* include 'Math/BigInteger.php';
|
||||
*
|
||||
* $a = new Math_BigInteger('65');
|
||||
*
|
||||
@ -612,7 +630,7 @@ class Math_BigInteger {
|
||||
* Here's an example:
|
||||
* <code>
|
||||
* <?php
|
||||
* include('Math/BigInteger.php');
|
||||
* include 'Math/BigInteger.php';
|
||||
*
|
||||
* $a = new Math_BigInteger('65');
|
||||
*
|
||||
@ -650,7 +668,7 @@ class Math_BigInteger {
|
||||
* Here's an example:
|
||||
* <code>
|
||||
* <?php
|
||||
* include('Math/BigInteger.php');
|
||||
* include 'Math/BigInteger.php';
|
||||
*
|
||||
* $a = new Math_BigInteger('50');
|
||||
*
|
||||
@ -774,7 +792,7 @@ class Math_BigInteger {
|
||||
$vars[] = 'precision';
|
||||
}
|
||||
return $vars;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -803,7 +821,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');
|
||||
@ -902,7 +920,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;
|
||||
@ -934,7 +952,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');
|
||||
@ -1038,7 +1056,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;
|
||||
@ -1070,7 +1088,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');
|
||||
@ -1186,7 +1204,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);
|
||||
}
|
||||
|
||||
@ -1199,7 +1217,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);
|
||||
}
|
||||
|
||||
@ -1287,13 +1305,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);
|
||||
}
|
||||
|
||||
@ -1354,7 +1372,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');
|
||||
@ -1491,9 +1509,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]
|
||||
);
|
||||
}
|
||||
@ -1561,7 +1578,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]);
|
||||
}
|
||||
|
||||
@ -1574,7 +1591,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');
|
||||
@ -1699,6 +1716,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));
|
||||
@ -2173,7 +2195,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);
|
||||
}
|
||||
|
||||
@ -2189,7 +2211,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);
|
||||
}
|
||||
|
||||
@ -2238,7 +2260,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);
|
||||
@ -2256,7 +2278,7 @@ class Math_BigInteger {
|
||||
/**
|
||||
* Montgomery Multiply
|
||||
*
|
||||
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
|
||||
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
|
||||
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
|
||||
*
|
||||
* @see _prepMontgomery()
|
||||
@ -2272,6 +2294,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()
|
||||
@ -2290,9 +2317,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);
|
||||
@ -2336,7 +2363,7 @@ class Math_BigInteger {
|
||||
* {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
|
||||
*
|
||||
* As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
|
||||
* instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
|
||||
* instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
|
||||
* int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
|
||||
* auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
|
||||
* the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
|
||||
@ -2369,7 +2396,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);
|
||||
@ -2437,7 +2464,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);
|
||||
@ -2572,7 +2599,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);
|
||||
@ -2877,7 +2904,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));
|
||||
}
|
||||
@ -3029,40 +3056,17 @@ class Math_BigInteger {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number
|
||||
* Generates a random BigInteger
|
||||
*
|
||||
* @param optional Integer $min
|
||||
* @param optional Integer $max
|
||||
* Byte length is equal to $length. Uses crypt_random if it's loaded and mt_rand if it's not.
|
||||
*
|
||||
* @param Integer $length
|
||||
* @return Math_BigInteger
|
||||
* @access public
|
||||
* @access private
|
||||
*/
|
||||
function random($min = false, $max = false)
|
||||
function _random_number_helper($size)
|
||||
{
|
||||
if ($min === false) {
|
||||
$min = new Math_BigInteger(0);
|
||||
}
|
||||
|
||||
if ($max === false) {
|
||||
$max = new Math_BigInteger(0x7FFFFFFF);
|
||||
}
|
||||
|
||||
$compare = $max->compare($min);
|
||||
|
||||
if (!$compare) {
|
||||
return $this->_normalize($min);
|
||||
} else if ($compare < 0) {
|
||||
// if $min is bigger then $max, swap $min and $max
|
||||
$temp = $max;
|
||||
$max = $min;
|
||||
$min = $temp;
|
||||
}
|
||||
|
||||
$max = $max->subtract($min);
|
||||
$max = ltrim($max->toBytes(), chr(0));
|
||||
$size = strlen($max) - 1;
|
||||
|
||||
$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 = '';
|
||||
@ -3078,25 +3082,89 @@ class Math_BigInteger {
|
||||
}
|
||||
}
|
||||
|
||||
$fragment = new Math_BigInteger($random, 256);
|
||||
$leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ?
|
||||
ord($max[0]) - 1 : ord($max[0]);
|
||||
return new Math_BigInteger($random, 256);
|
||||
}
|
||||
|
||||
if (!$crypt_random) {
|
||||
$msb = chr(mt_rand(0, $leading));
|
||||
} else {
|
||||
$cutoff = floor(0xFF / $leading) * $leading;
|
||||
while (true) {
|
||||
$msb = ord(crypt_random_string(1));
|
||||
if ($msb <= $cutoff) {
|
||||
$msb%= $leading;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$msb = chr($msb);
|
||||
/**
|
||||
* Generate a random number
|
||||
*
|
||||
* 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($arg1, $arg2 = false)
|
||||
{
|
||||
if ($arg1 === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$random = new Math_BigInteger($msb . $random, 256);
|
||||
if ($arg2 === false) {
|
||||
$max = $arg1;
|
||||
$min = $this;
|
||||
} else {
|
||||
$min = $arg1;
|
||||
$max = $arg2;
|
||||
}
|
||||
|
||||
$compare = $max->compare($min);
|
||||
|
||||
if (!$compare) {
|
||||
return $this->_normalize($min);
|
||||
} else if ($compare < 0) {
|
||||
// if $min is bigger then $max, swap $min and $max
|
||||
$temp = $max;
|
||||
$max = $min;
|
||||
$min = $temp;
|
||||
}
|
||||
|
||||
static $one;
|
||||
if (!isset($one)) {
|
||||
$one = new Math_BigInteger(1);
|
||||
}
|
||||
|
||||
$max = $max->subtract($min->subtract($one));
|
||||
$size = strlen(ltrim($max->toBytes(), chr(0)));
|
||||
|
||||
/*
|
||||
doing $random % $max doesn't work because some numbers will be more likely to occur than others.
|
||||
eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
|
||||
would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
|
||||
not all numbers would be equally likely. some would be more likely than others.
|
||||
|
||||
creating a whole new random number until you find one that is within the range doesn't work
|
||||
because, for sufficiently small ranges, the likelihood that you'd get a number within that range
|
||||
would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
|
||||
would be pretty high that $random would be greater than $max.
|
||||
|
||||
phpseclib works around this using the technique described here:
|
||||
|
||||
http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
|
||||
*/
|
||||
$random_max = new Math_BigInteger(chr(1) . str_repeat("\0", $size), 256);
|
||||
$random = $this->_random_number_helper($size);
|
||||
|
||||
list($max_multiple) = $random_max->divide($max);
|
||||
$max_multiple = $max_multiple->multiply($max);
|
||||
|
||||
while ($random->compare($max_multiple) >= 0) {
|
||||
$random = $random->subtract($max_multiple);
|
||||
$random_max = $random_max->subtract($max_multiple);
|
||||
$random = $random->bitwise_leftShift(8);
|
||||
$random = $random->add($this->_random_number_helper(1));
|
||||
$random_max = $random_max->bitwise_leftShift(8);
|
||||
list($max_multiple) = $random_max->divide($max);
|
||||
$max_multiple = $max_multiple->multiply($max);
|
||||
}
|
||||
list(, $random) = $random->divide($max);
|
||||
|
||||
return $this->_normalize($random->add($min));
|
||||
}
|
||||
@ -3107,21 +3175,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);
|
||||
@ -3147,6 +3219,7 @@ class Math_BigInteger {
|
||||
|
||||
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
|
||||
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
|
||||
$p = new Math_BigInteger();
|
||||
$p->value = gmp_nextprime($x->value);
|
||||
|
||||
if ($p->compare($max) <= 0) {
|
||||
@ -3229,14 +3302,14 @@ 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
|
||||
* {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
|
||||
* {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
|
||||
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
|
||||
*/
|
||||
function isPrime($t = false)
|
||||
@ -3245,6 +3318,7 @@ class Math_BigInteger {
|
||||
|
||||
if (!$t) {
|
||||
// see HAC 4.49 "Note (controlling the error probability)"
|
||||
// @codingStandardsIgnoreStart
|
||||
if ($length >= 163) { $t = 2; } // floor(1300 / 8)
|
||||
else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
|
||||
else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
|
||||
@ -3257,6 +3331,7 @@ class Math_BigInteger {
|
||||
else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
|
||||
else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
|
||||
else { $t = 27; }
|
||||
// @codingStandardsIgnoreEnd
|
||||
}
|
||||
|
||||
// ie. gmp_testbit($this, 0)
|
||||
@ -3285,16 +3360,16 @@ class Math_BigInteger {
|
||||
|
||||
if (!isset($primes)) {
|
||||
$primes = array(
|
||||
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
|
||||
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
|
||||
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
|
||||
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
|
||||
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
|
||||
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
|
||||
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
|
||||
619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
|
||||
733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
|
||||
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
|
||||
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
|
||||
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
|
||||
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
|
||||
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
|
||||
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
|
||||
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
|
||||
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
|
||||
619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
|
||||
733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
|
||||
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
|
||||
953, 967, 971, 977, 983, 991, 997
|
||||
);
|
||||
|
||||
@ -3399,7 +3474,7 @@ 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);
|
||||
}
|
||||
|
||||
@ -3647,4 +3722,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;
|
||||
}
|
||||
}
|
||||
|
94
Net/SCP.php
94
Net/SCP.php
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SCP.
|
||||
@ -11,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')) {
|
||||
@ -30,10 +29,10 @@
|
||||
* 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
|
||||
@ -42,12 +41,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Net
|
||||
* @package Net_SCP
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMX Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Net
|
||||
* @package Net_SCP
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMX Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
@ -82,12 +81,12 @@ define('NET_SCP_SSH2', 2);
|
||||
/**
|
||||
* Pure-PHP implementations of SCP.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.1.0
|
||||
* @access public
|
||||
* @package Net_SCP
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Net_SCP {
|
||||
class Net_SCP
|
||||
{
|
||||
/**
|
||||
* SSH Object
|
||||
*
|
||||
@ -151,7 +150,7 @@ class Net_SCP {
|
||||
* So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes
|
||||
* long, containing 'filename.ext' as its contents.
|
||||
*
|
||||
* Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will
|
||||
* Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will
|
||||
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
|
||||
* large $remote_file will be, as well.
|
||||
*
|
||||
@ -161,16 +160,19 @@ class Net_SCP {
|
||||
* @param String $remote_file
|
||||
* @param String $data
|
||||
* @param optional Integer $mode
|
||||
* @param optional Callable $callback
|
||||
* @return Boolean
|
||||
* @access public
|
||||
*/
|
||||
function put($remote_file, $data, $mode = NET_SCP_STRING)
|
||||
function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null)
|
||||
{
|
||||
if (!isset($this->ssh)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->ssh->exec('scp -t ' . $remote_file, false); // -t = to
|
||||
if (!$this->ssh->exec('scp -t "' . $remote_file . '"', false)) { // -t = to
|
||||
return false;
|
||||
}
|
||||
|
||||
$temp = $this->_receive();
|
||||
if ($temp !== chr(0)) {
|
||||
@ -178,35 +180,51 @@ class Net_SCP {
|
||||
}
|
||||
|
||||
if ($this->mode == NET_SCP_SSH2) {
|
||||
$this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC];
|
||||
$this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4;
|
||||
}
|
||||
|
||||
$remote_file = basename($remote_file);
|
||||
$this->_send('C0644 ' . strlen($data) . ' ' . $remote_file . "\n");
|
||||
|
||||
if ($mode == NET_SCP_STRING) {
|
||||
$size = strlen($data);
|
||||
} else {
|
||||
if (!is_file($data)) {
|
||||
user_error("$data is not a valid file", E_USER_NOTICE);
|
||||
return false;
|
||||
}
|
||||
|
||||
$fp = @fopen($data, 'rb');
|
||||
if (!$fp) {
|
||||
fclose($fp);
|
||||
return false;
|
||||
}
|
||||
$size = filesize($data);
|
||||
}
|
||||
|
||||
$this->_send('C0644 ' . $size . ' ' . $remote_file . "\n");
|
||||
|
||||
$temp = $this->_receive();
|
||||
if ($temp !== chr(0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($mode == NET_SCP_STRING) {
|
||||
$this->_send($data);
|
||||
} else {
|
||||
if (!is_file($data)) {
|
||||
user_error("$data is not a valid file", E_USER_NOTICE);
|
||||
return false;
|
||||
$sent = 0;
|
||||
while ($sent < $size) {
|
||||
$temp = $mode & NET_SCP_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size);
|
||||
$this->_send($temp);
|
||||
$sent+= strlen($temp);
|
||||
|
||||
if (is_callable($callback)) {
|
||||
call_user_func($callback, $sent);
|
||||
}
|
||||
$fp = @fopen($data, 'rb');
|
||||
if (!$fp) {
|
||||
return false;
|
||||
}
|
||||
$size = filesize($data);
|
||||
for ($i = 0; $i < $size; $i += $this->packet_size) {
|
||||
$this->_send(fgets($fp, $this->packet_size));
|
||||
}
|
||||
fclose($fp);
|
||||
}
|
||||
$this->_close();
|
||||
|
||||
if ($mode != NET_SCP_STRING) {
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -227,7 +245,9 @@ class Net_SCP {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->ssh->exec('scp -f ' . $remote_file, false); // -f = from
|
||||
if (!$this->ssh->exec('scp -f "' . $remote_file . '"', false)) { // -f = from
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_send("\0");
|
||||
|
||||
@ -332,7 +352,7 @@ class Net_SCP {
|
||||
{
|
||||
switch ($this->mode) {
|
||||
case NET_SCP_SSH2:
|
||||
$this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC);
|
||||
$this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true);
|
||||
break;
|
||||
case NET_SCP_SSH1:
|
||||
$this->ssh->disconnect();
|
||||
|
1052
Net/SFTP.php
1052
Net/SFTP.php
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* SFTP Stream Wrapper
|
||||
@ -14,10 +13,10 @@
|
||||
* 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
|
||||
@ -26,23 +25,23 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Net
|
||||
* @package Net_SFTP_Stream
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMXIII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Net
|
||||
* @package Net_SFTP_Stream
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMXIII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* SFTP Stream Wrapper
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.3.2
|
||||
* @access public
|
||||
* @package Net_SFTP_Stream
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Net_SFTP_Stream {
|
||||
class Net_SFTP_Stream
|
||||
{
|
||||
/**
|
||||
* SFTP instances
|
||||
*
|
||||
@ -127,6 +126,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
|
||||
*
|
||||
@ -134,8 +149,12 @@ class Net_SFTP_Stream {
|
||||
*/
|
||||
function Net_SFTP_Stream()
|
||||
{
|
||||
if (defined('NET_SFTP_STREAM_LOGGING')) {
|
||||
echo "__construct()\r\n";
|
||||
}
|
||||
|
||||
if (!class_exists('Net_SFTP')) {
|
||||
require_once('Net/SFTP.php');
|
||||
include_once 'Net/SFTP.php';
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,44 +172,48 @@ class Net_SFTP_Stream {
|
||||
*/
|
||||
function _parse_path($path)
|
||||
{
|
||||
extract(parse_url($path));
|
||||
extract(parse_url($path) + array('port' => 22));
|
||||
|
||||
if (!isset($host)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$context = stream_context_get_params($this->context);
|
||||
if (isset($context['notification'])) {
|
||||
$this->notification = $context['notification'];
|
||||
if (isset($this->context)) {
|
||||
$context = stream_context_get_params($this->context);
|
||||
if (isset($context['notification'])) {
|
||||
$this->notification = $context['notification'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($host[0] == '$') {
|
||||
$host = substr($host, 1);
|
||||
global $$host;
|
||||
if (!is_object($$host) || get_class($$host) != 'Net_sFTP') {
|
||||
if (!is_object($$host) || get_class($$host) != 'Net_SFTP') {
|
||||
return false;
|
||||
}
|
||||
$this->sftp = $$host;
|
||||
} else {
|
||||
$context = stream_context_get_options($this->context);
|
||||
if (isset($context['sftp']['session'])) {
|
||||
$sftp = $context['sftp']['session'];
|
||||
if (isset($this->context)) {
|
||||
$context = stream_context_get_options($this->context);
|
||||
}
|
||||
if (isset($context['sftp']['sftp'])) {
|
||||
$sftp = $context['sftp']['sftp'];
|
||||
if (isset($context[$scheme]['session'])) {
|
||||
$sftp = $context[$scheme]['session'];
|
||||
}
|
||||
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)) {
|
||||
@ -201,7 +224,8 @@ class Net_SFTP_Stream {
|
||||
if (isset(self::$instances[$host][$port][$user][(string) $pass])) {
|
||||
$this->sftp = self::$instances[$host][$port][$user][(string) $pass];
|
||||
} else {
|
||||
$this->sftp = new Net_SFTP($host, isset($port) ? $port : 22);
|
||||
$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:
|
||||
|
||||
@ -252,6 +276,7 @@ class Net_SFTP_Stream {
|
||||
|
||||
$this->size = $this->sftp->size($path);
|
||||
$this->mode = preg_replace('#[bt]$#', '', $mode);
|
||||
$this->eof = false;
|
||||
|
||||
if ($this->size === false) {
|
||||
if ($this->mode[0] == 'r') {
|
||||
@ -508,7 +533,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
|
||||
@ -761,6 +799,4 @@ class Net_SFTP_Stream {
|
||||
}
|
||||
}
|
||||
|
||||
if (function_exists('stream_wrapper_register')) {
|
||||
stream_wrapper_register('sftp', 'Net_SFTP_Stream');
|
||||
}
|
||||
Net_SFTP_Stream::register();
|
||||
|
302
Net/SSH1.php
302
Net/SSH1.php
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SSHv1.
|
||||
@ -9,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')) {
|
||||
@ -23,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')) {
|
||||
@ -36,7 +35,7 @@
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* More information on the SSHv1 specification can be found by reading
|
||||
* More information on the SSHv1 specification can be found by reading
|
||||
* {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
|
||||
*
|
||||
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -45,10 +44,10 @@
|
||||
* 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
|
||||
@ -57,12 +56,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Net
|
||||
* @package Net_SSH1
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
* @category Net
|
||||
* @package Net_SSH1
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright MMVII Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
@ -183,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);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
@ -202,11 +202,11 @@ define('NET_SSH1_LOG_COMPLEX', 2);
|
||||
/**
|
||||
* Outputs the content real-time
|
||||
*/
|
||||
define('NET_SSH2_LOG_REALTIME', 3);
|
||||
define('NET_SSH1_LOG_REALTIME', 3);
|
||||
/**
|
||||
* Dumps the content real-time to a file
|
||||
*/
|
||||
define('NET_SSH2_LOG_REALTIME_FILE', 4);
|
||||
define('NET_SSH1_LOG_REALTIME_FILE', 4);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
@ -226,12 +226,12 @@ define('NET_SSH1_READ_REGEX', 2);
|
||||
/**
|
||||
* Pure-PHP implementation of SSHv1.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @version 0.1.0
|
||||
* @access public
|
||||
* @package Net_SSH1
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Net_SSH1 {
|
||||
class Net_SSH1
|
||||
{
|
||||
/**
|
||||
* The SSH identifier
|
||||
*
|
||||
@ -429,11 +429,80 @@ class Net_SSH1 {
|
||||
/**
|
||||
* Current Timeout
|
||||
*
|
||||
* @see Net_SSH2::_get_channel_packet()
|
||||
* @see Net_SSH1::_get_channel_packet()
|
||||
* @access private
|
||||
*/
|
||||
var $curTimeout;
|
||||
|
||||
/**
|
||||
* Log Boundary
|
||||
*
|
||||
* @see Net_SSH1::_format_log
|
||||
* @access private
|
||||
*/
|
||||
var $log_boundary = ':';
|
||||
|
||||
/**
|
||||
* Log Long Width
|
||||
*
|
||||
* @see Net_SSH1::_format_log
|
||||
* @access private
|
||||
*/
|
||||
var $log_long_width = 65;
|
||||
|
||||
/**
|
||||
* Log Short Width
|
||||
*
|
||||
* @see Net_SSH1::_format_log
|
||||
* @access private
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@ -449,16 +518,16 @@ class Net_SSH1 {
|
||||
function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
|
||||
{
|
||||
if (!class_exists('Math_BigInteger')) {
|
||||
require_once('Math/BigInteger.php');
|
||||
include_once 'Math/BigInteger.php';
|
||||
}
|
||||
|
||||
// Include Crypt_Random
|
||||
// the class_exists() will only be called if the crypt_random_string function hasn't been defined and
|
||||
// will trigger a call to __autoload() if you're wanting to auto-load classes
|
||||
// call function_exists() a second time to stop the require_once from being called outside
|
||||
// call function_exists() a second time to stop the include_once from being called outside
|
||||
// of the auto loader
|
||||
if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
|
||||
require_once('Crypt/Random.php');
|
||||
include_once 'Crypt/Random.php';
|
||||
}
|
||||
|
||||
$this->protocol_flags = array(
|
||||
@ -482,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);
|
||||
@ -497,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");
|
||||
@ -509,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);
|
||||
@ -589,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) {
|
||||
@ -603,7 +686,7 @@ class Net_SSH1 {
|
||||
// break;
|
||||
case NET_SSH1_CIPHER_DES:
|
||||
if (!class_exists('Crypt_DES')) {
|
||||
require_once('Crypt/DES.php');
|
||||
include_once 'Crypt/DES.php';
|
||||
}
|
||||
$this->crypto = new Crypt_DES();
|
||||
$this->crypto->disablePadding();
|
||||
@ -612,7 +695,7 @@ class Net_SSH1 {
|
||||
break;
|
||||
case NET_SSH1_CIPHER_3DES:
|
||||
if (!class_exists('Crypt_TripleDES')) {
|
||||
require_once('Crypt/TripleDES.php');
|
||||
include_once 'Crypt/TripleDES.php';
|
||||
}
|
||||
$this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
|
||||
$this->crypto->disablePadding();
|
||||
@ -621,7 +704,7 @@ class Net_SSH1 {
|
||||
break;
|
||||
//case NET_SSH1_CIPHER_RC4:
|
||||
// if (!class_exists('Crypt_RC4')) {
|
||||
// require_once('Crypt/RC4.php');
|
||||
// include_once 'Crypt/RC4.php';
|
||||
// }
|
||||
// $this->crypto = new Crypt_RC4();
|
||||
// $this->crypto->enableContinuousBuffer();
|
||||
@ -633,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -650,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;
|
||||
}
|
||||
|
||||
@ -1017,7 +1109,7 @@ class Net_SSH1 {
|
||||
|
||||
if ($this->curTimeout) {
|
||||
$read = array($this->fsock);
|
||||
$write = $except = NULL;
|
||||
$write = $except = null;
|
||||
|
||||
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
||||
$sec = floor($this->curTimeout);
|
||||
@ -1253,7 +1345,7 @@ class Net_SSH1 {
|
||||
{
|
||||
/*
|
||||
if (!class_exists('Crypt_RSA')) {
|
||||
require_once('Crypt/RSA.php');
|
||||
include_once 'Crypt/RSA.php';
|
||||
}
|
||||
|
||||
$rsa = new Crypt_RSA();
|
||||
@ -1318,7 +1410,7 @@ class Net_SSH1 {
|
||||
/**
|
||||
* Returns a log of the packets that have been sent and received.
|
||||
*
|
||||
* Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
|
||||
* Returns a string if NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX, an array if NET_SSH1_LOGGING == NET_SSH1_LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING')
|
||||
*
|
||||
* @access public
|
||||
* @return String or Array
|
||||
@ -1351,8 +1443,6 @@ class Net_SSH1 {
|
||||
*/
|
||||
function _format_log($message_log, $message_number_log)
|
||||
{
|
||||
static $boundary = ':', $long_width = 65, $short_width = 16;
|
||||
|
||||
$output = '';
|
||||
for ($i = 0; $i < count($message_log); $i++) {
|
||||
$output.= $message_number_log[$i] . "\r\n";
|
||||
@ -1362,19 +1452,13 @@ class Net_SSH1 {
|
||||
if (strlen($current_log)) {
|
||||
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
|
||||
}
|
||||
$fragment = $this->_string_shift($current_log, $short_width);
|
||||
$hex = substr(
|
||||
preg_replace(
|
||||
'#(.)#es',
|
||||
'"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)',
|
||||
$fragment),
|
||||
strlen($boundary)
|
||||
);
|
||||
$fragment = $this->_string_shift($current_log, $this->log_short_width);
|
||||
$hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
|
||||
// replace non ASCII printable characters with dots
|
||||
// http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
|
||||
// also replace < with a . since < messes up the output on web browsers
|
||||
$raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
|
||||
$output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n";
|
||||
$output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
|
||||
$j++;
|
||||
} while (strlen($current_log));
|
||||
$output.= "\r\n";
|
||||
@ -1383,6 +1467,20 @@ class Net_SSH1 {
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for _format_log
|
||||
*
|
||||
* For use with preg_replace_callback()
|
||||
*
|
||||
* @param Array $matches
|
||||
* @access private
|
||||
* @return String
|
||||
*/
|
||||
function _format_log_helper($matches)
|
||||
{
|
||||
return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server key public exponent
|
||||
*
|
||||
@ -1496,57 +1594,57 @@ class Net_SSH1 {
|
||||
*/
|
||||
function _append_log($protocol_flags, $message)
|
||||
{
|
||||
switch (NET_SSH1_LOGGING) {
|
||||
// useful for benchmarks
|
||||
case NET_SSH1_LOG_SIMPLE:
|
||||
$this->protocol_flags_log[] = $protocol_flags;
|
||||
switch (NET_SSH1_LOGGING) {
|
||||
// useful for benchmarks
|
||||
case NET_SSH1_LOG_SIMPLE:
|
||||
$this->protocol_flags_log[] = $protocol_flags;
|
||||
break;
|
||||
// the most useful log for SSH1
|
||||
case NET_SSH1_LOG_COMPLEX:
|
||||
$this->protocol_flags_log[] = $protocol_flags;
|
||||
$this->_string_shift($message);
|
||||
$this->log_size+= strlen($message);
|
||||
$this->message_log[] = $message;
|
||||
while ($this->log_size > NET_SSH1_LOG_MAX_SIZE) {
|
||||
$this->log_size-= strlen(array_shift($this->message_log));
|
||||
array_shift($this->protocol_flags_log);
|
||||
}
|
||||
break;
|
||||
// dump the output out realtime; packets may be interspersed with non packets,
|
||||
// passwords won't be filtered out and select other packets may not be correctly
|
||||
// identified
|
||||
case NET_SSH1_LOG_REALTIME:
|
||||
echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
|
||||
@flush();
|
||||
@ob_flush();
|
||||
break;
|
||||
// basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE
|
||||
// needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE.
|
||||
// the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
|
||||
// at the beginning of the file
|
||||
case NET_SSH1_LOG_REALTIME_FILE:
|
||||
if (!isset($this->realtime_log_file)) {
|
||||
// PHP doesn't seem to like using constants in fopen()
|
||||
$filename = NET_SSH1_LOG_REALTIME_FILE;
|
||||
$fp = fopen($filename, 'w');
|
||||
$this->realtime_log_file = $fp;
|
||||
}
|
||||
if (!is_resource($this->realtime_log_file)) {
|
||||
break;
|
||||
// the most useful log for SSH1
|
||||
case NET_SSH1_LOG_COMPLEX:
|
||||
$this->protocol_flags_log[] = $protocol_flags;
|
||||
$this->_string_shift($message);
|
||||
$this->log_size+= strlen($message);
|
||||
$this->message_log[] = $message;
|
||||
while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) {
|
||||
$this->log_size-= strlen(array_shift($this->message_log));
|
||||
array_shift($this->protocol_flags_log);
|
||||
}
|
||||
break;
|
||||
// dump the output out realtime; packets may be interspersed with non packets,
|
||||
// passwords won't be filtered out and select other packets may not be correctly
|
||||
// identified
|
||||
case NET_SSH1_LOG_REALTIME:
|
||||
echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
|
||||
@flush();
|
||||
@ob_flush();
|
||||
break;
|
||||
// basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE
|
||||
// needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE.
|
||||
// the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
|
||||
// at the beginning of the file
|
||||
case NET_SSH1_LOG_REALTIME_FILE:
|
||||
if (!isset($this->realtime_log_file)) {
|
||||
// PHP doesn't seem to like using constants in fopen()
|
||||
$filename = NET_SSH2_LOG_REALTIME_FILE;
|
||||
$fp = fopen($filename, 'w');
|
||||
$this->realtime_log_file = $fp;
|
||||
}
|
||||
if (!is_resource($this->realtime_log_file)) {
|
||||
break;
|
||||
}
|
||||
$entry = $this->_format_log(array($message), array($protocol_flags));
|
||||
if ($this->realtime_log_wrap) {
|
||||
$temp = "<<< START >>>\r\n";
|
||||
$entry.= $temp;
|
||||
fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
|
||||
}
|
||||
$this->realtime_log_size+= strlen($entry);
|
||||
if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) {
|
||||
fseek($this->realtime_log_file, 0);
|
||||
$this->realtime_log_size = strlen($entry);
|
||||
$this->realtime_log_wrap = true;
|
||||
}
|
||||
fputs($this->realtime_log_file, $entry);
|
||||
}
|
||||
}
|
||||
$entry = $this->_format_log(array($message), array($protocol_flags));
|
||||
if ($this->realtime_log_wrap) {
|
||||
$temp = "<<< START >>>\r\n";
|
||||
$entry.= $temp;
|
||||
fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
|
||||
}
|
||||
$this->realtime_log_size+= strlen($entry);
|
||||
if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) {
|
||||
fseek($this->realtime_log_file, 0);
|
||||
$this->realtime_log_size = strlen($entry);
|
||||
$this->realtime_log_wrap = true;
|
||||
}
|
||||
fputs($this->realtime_log_file, $entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1112
Net/SSH2.php
1112
Net/SSH2.php
File diff suppressed because it is too large
Load Diff
313
System/SSH/Agent.php
Executable file
313
System/SSH/Agent.php
Executable 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 MMXIV 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;
|
||||
}
|
||||
}
|
39
System/SSH_Agent.php
Executable file
39
System/SSH_Agent.php
Executable file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* Pure-PHP ssh-agent client wrapper
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* 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
|
||||
* 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 MMXIV 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
|
||||
*/
|
||||
|
||||
require_once 'SSH/Agent.php';
|
@ -3,4 +3,4 @@
|
||||
HOME = .
|
||||
RANDFILE = $ENV::HOME/.rnd
|
||||
|
||||
[ v3_ca ]
|
||||
[ v3_ca ]
|
||||
|
Loading…
Reference in New Issue
Block a user