提交 e8576e7f authored 作者: lefull_wl's avatar lefull_wl

allinpay

上级 7de649e3
<?php
/**
* Pure-PHP implementation of AES.
*
* Uses mcrypt, if available/possible, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
* just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
* to save one include_once().
*
* If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::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
* make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function,
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/AES.php';
*
* $aes = new Crypt_AES();
*
* $aes->setKey('abcdefghijklmnop');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $aes->decrypt($aes->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_AES
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2008 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')) {
include_once 'Rijndael.php';
}
/**#@+
* @access public
* @see self::encrypt()
* @see self::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_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', 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', 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', 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', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of AES.
*
* @package Crypt_AES
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Crypt_AES extends Crypt_Rijndael
{
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
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 int $length
*/
function setBlockLength($length)
{
return;
}
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @see Crypt_Rijndael:setKeyLength()
* @access public
* @param int $length
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see Crypt_Rijndael:setKey()
* @see setKeyLength()
* @access public
* @param string $key
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_length = 16;
break;
case $length <= 24:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}
$this->_setEngine();
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
/**
* Pure-PHP implementation of Blowfish.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/Blowfish.php';
*
* $blowfish = new Crypt_Blowfish();
*
* $blowfish->setKey('12345678901234567890123456789012');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $blowfish->decrypt($blowfish->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_Blowfish
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright 2007 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 public
* @see self::encrypt()
* @see self::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_BLOWFISH_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_BLOWFISH_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_BLOWFISH_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_BLOWFISH_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_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of Blowfish.
*
* @package Crypt_Blowfish
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @access public
*/
class Crypt_Blowfish extends Crypt_Base
{
/**
* Block Length of the cipher
*
* @see Crypt_Base::block_size
* @var int
* @access private
*/
var $block_size = 8;
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'BLOWFISH';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'blowfish';
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 500;
/**
* The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
*
* S-Box 0
*
* @access private
* @var array
*/
var $sbox0 = array(
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
);
/**
* S-Box 1
*
* @access private
* @var array
*/
var $sbox1 = array(
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
);
/**
* S-Box 2
*
* @access private
* @var array
*/
var $sbox2 = array(
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
);
/**
* S-Box 3
*
* @access private
* @var array
*/
var $sbox3 = array(
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
);
/**
* P-Array consists of 18 32-bit subkeys
*
* @var array
* @access private
*/
var $parray = array(
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
);
/**
* The BCTX-working Array
*
* Holds the expanded key [p] and the key-depended s-boxes [sb]
*
* @var array
* @access private
*/
var $bctx;
/**
* Holds the last used key
*
* @var array
* @access private
*/
var $kl;
/**
* The Key Length (in bytes)
*
* @see Crypt_Base::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
* because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
* derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.
*/
var $key_length = 16;
/**
* Sets the key length.
*
* Key lengths can be between 32 and 448 bits.
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
if ($length < 32) {
$this->key_length = 4;
} elseif ($length > 448) {
$this->key_length = 56;
} else {
$this->key_length = $length >> 3;
}
parent::setKeyLength($length);
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::isValidEngine()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
return false;
}
if ($this->key_length < 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'bf-ecb';
$this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
}
return parent::isValidEngine($engine);
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key);
/* key-expanding p[] and S-Box building sb[] */
$this->bctx = array(
'p' => array(),
'sb' => array(
$this->sbox0,
$this->sbox1,
$this->sbox2,
$this->sbox3
)
);
// unpack binary string in unsigned chars
$key = array_values(unpack('C*', $this->key));
$keyl = count($key);
for ($j = 0, $i = 0; $i < 18; ++$i) {
// xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
for ($data = 0, $k = 0; $k < 4; ++$k) {
$data = ($data << 8) | $key[$j];
if (++$j >= $keyl) {
$j = 0;
}
}
$this->bctx['p'][] = $this->parray[$i] ^ $data;
}
// encrypt the zero-string, replace P1 and P2 with the encrypted data,
// encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
$data = "\0\0\0\0\0\0\0\0";
for ($i = 0; $i < 18; $i += 2) {
list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
$this->bctx['p'][$i ] = $l;
$this->bctx['p'][$i + 1] = $r;
}
for ($i = 0; $i < 4; ++$i) {
for ($j = 0; $j < 256; $j += 2) {
list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
$this->bctx['sb'][$i][$j ] = $l;
$this->bctx['sb'][$i][$j + 1] = $r;
}
}
}
/**
* Encrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
$p = $this->bctx["p"];
// extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
$sb_0 = $this->bctx["sb"][0];
$sb_1 = $this->bctx["sb"][1];
$sb_2 = $this->bctx["sb"][2];
$sb_3 = $this->bctx["sb"][3];
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
for ($i = 0; $i < 16; $i+= 2) {
$l^= $p[$i];
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]);
$r^= $p[$i + 1];
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[17], $l ^ $p[16]);
}
/**
* Decrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
$p = $this->bctx["p"];
$sb_0 = $this->bctx["sb"][0];
$sb_1 = $this->bctx["sb"][1];
$sb_2 = $this->bctx["sb"][2];
$sb_3 = $this->bctx["sb"][3];
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
for ($i = 17; $i > 2; $i-= 2) {
$l^= $p[$i];
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]);
$r^= $p[$i - 1];
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[0], $l ^ $p[1]);
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
$lambda_functions =& Crypt_Blowfish::_getLambdaFunctions();
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a unique hash for our generated code
$code_hash = "Crypt_Blowfish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
$safeint = $this->safe_intval_inline();
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
$p = $this->bctx['p'];
$init_crypt = '
static $sb_0, $sb_1, $sb_2, $sb_3;
if (!$sb_0) {
$sb_0 = $self->bctx["sb"][0];
$sb_1 = $self->bctx["sb"][1];
$sb_2 = $self->bctx["sb"][2];
$sb_3 = $self->bctx["sb"][3];
}
';
break;
default:
$p = array();
for ($i = 0; $i < 18; ++$i) {
$p[] = '$p_' . $i;
}
$init_crypt = '
list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
list(' . implode(',', $p) . ') = $self->bctx["p"];
';
}
// Generating encrypt code:
$encrypt_block = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
';
for ($i = 0; $i < 16; $i+= 2) {
$encrypt_block.= '
$l^= ' . $p[$i] . ';
$r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i + 1] . ';
$l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]') . ';
';
}
$encrypt_block.= '
$in = pack("N*",
$r ^ ' . $p[17] . ',
$l ^ ' . $p[16] . '
);
';
// Generating decrypt code:
$decrypt_block = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
';
for ($i = 17; $i > 2; $i-= 2) {
$decrypt_block.= '
$l^= ' . $p[$i] . ';
$r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i - 1] . ';
$l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]') . ';
';
}
$decrypt_block.= '
$in = pack("N*",
$r ^ ' . $p[0] . ',
$l ^ ' . $p[1] . '
);
';
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => '',
'init_decrypt' => '',
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php
/**
* Pure-PHP implementation of DES.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
* - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
* - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/DES.php';
*
* $des = new Crypt_DES();
*
* $des->setKey('abcdefgh');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $des->decrypt($des->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_DES
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 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 self::_setupKey()
* @see self::_processBlock()
*/
/**
* Contains $keys[CRYPT_DES_ENCRYPT]
*/
define('CRYPT_DES_ENCRYPT', 0);
/**
* Contains $keys[CRYPT_DES_DECRYPT]
*/
define('CRYPT_DES_DECRYPT', 1);
/**#@-*/
/**#@+
* @access public
* @see self::encrypt()
* @see self::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_DES_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_DES_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_DES_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_DES_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_DES_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of DES.
*
* @package Crypt_DES
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Crypt_DES extends Crypt_Base
{
/**
* Block Length of the cipher
*
* @see Crypt_Base::block_size
* @var int
* @access private
*/
var $block_size = 8;
/**
* Key Length (in bytes)
*
* @see Crypt_Base::setKeyLength()
* @var int
* @access private
*/
var $key_length = 8;
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'DES';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'des';
/**
* The OpenSSL names of the cipher / modes
*
* @see Crypt_Base::openssl_mode_names
* @var array
* @access private
*/
var $openssl_mode_names = array(
CRYPT_MODE_ECB => 'des-ecb',
CRYPT_MODE_CBC => 'des-cbc',
CRYPT_MODE_CFB => 'des-cfb',
CRYPT_MODE_OFB => 'des-ofb'
// CRYPT_MODE_CTR is undefined for DES
);
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 500;
/**
* Switch for DES/3DES encryption
*
* Used only if $engine == CRYPT_DES_MODE_INTERNAL
*
* @see self::_setupKey()
* @see self::_processBlock()
* @var int
* @access private
*/
var $des_rounds = 1;
/**
* max possible size of $key
*
* @see self::setKey()
* @var string
* @access private
*/
var $key_length_max = 8;
/**
* The Key Schedule
*
* @see self::_setupKey()
* @var array
* @access private
*/
var $keys;
/**
* Shuffle table.
*
* For each byte value index, the entry holds an 8-byte string
* with each byte containing all bits in the same state as the
* corresponding bit in the index value.
*
* @see self::_processBlock()
* @see self::_setupKey()
* @var array
* @access private
*/
var $shuffle = array(
"\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
"\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
"\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
"\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
"\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
"\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
"\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
"\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
"\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
"\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
"\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
"\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
"\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
"\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
"\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
"\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
"\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
"\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
"\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
"\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
"\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
"\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
"\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
"\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
"\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
"\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
"\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
"\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
"\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
"\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
"\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
"\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
"\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
"\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
"\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
"\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
"\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
"\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
"\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
"\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
"\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
"\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
"\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
"\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
"\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
"\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
"\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
"\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
"\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
"\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
"\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
"\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
"\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
"\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
"\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
"\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
"\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
"\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
"\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
"\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
"\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
"\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
"\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
"\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
"\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
);
/**
* IP mapping helper table.
*
* Indexing this table with each source byte performs the initial bit permutation.
*
* @var array
* @access private
*/
var $ipmap = array(
0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
);
/**
* Inverse IP mapping helper table.
* Indexing this table with a byte value reverses the bit order.
*
* @var array
* @access private
*/
var $invipmap = array(
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
);
/**
* Pre-permuted S-box1
*
* Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
* P table: concatenation can then be replaced by exclusive ORs.
*
* @var array
* @access private
*/
var $sbox1 = array(
0x00808200, 0x00000000, 0x00008000, 0x00808202,
0x00808002, 0x00008202, 0x00000002, 0x00008000,
0x00000200, 0x00808200, 0x00808202, 0x00000200,
0x00800202, 0x00808002, 0x00800000, 0x00000002,
0x00000202, 0x00800200, 0x00800200, 0x00008200,
0x00008200, 0x00808000, 0x00808000, 0x00800202,
0x00008002, 0x00800002, 0x00800002, 0x00008002,
0x00000000, 0x00000202, 0x00008202, 0x00800000,
0x00008000, 0x00808202, 0x00000002, 0x00808000,
0x00808200, 0x00800000, 0x00800000, 0x00000200,
0x00808002, 0x00008000, 0x00008200, 0x00800002,
0x00000200, 0x00000002, 0x00800202, 0x00008202,
0x00808202, 0x00008002, 0x00808000, 0x00800202,
0x00800002, 0x00000202, 0x00008202, 0x00808200,
0x00000202, 0x00800200, 0x00800200, 0x00000000,
0x00008002, 0x00008200, 0x00000000, 0x00808002
);
/**
* Pre-permuted S-box2
*
* @var array
* @access private
*/
var $sbox2 = array(
0x40084010, 0x40004000, 0x00004000, 0x00084010,
0x00080000, 0x00000010, 0x40080010, 0x40004010,
0x40000010, 0x40084010, 0x40084000, 0x40000000,
0x40004000, 0x00080000, 0x00000010, 0x40080010,
0x00084000, 0x00080010, 0x40004010, 0x00000000,
0x40000000, 0x00004000, 0x00084010, 0x40080000,
0x00080010, 0x40000010, 0x00000000, 0x00084000,
0x00004010, 0x40084000, 0x40080000, 0x00004010,
0x00000000, 0x00084010, 0x40080010, 0x00080000,
0x40004010, 0x40080000, 0x40084000, 0x00004000,
0x40080000, 0x40004000, 0x00000010, 0x40084010,
0x00084010, 0x00000010, 0x00004000, 0x40000000,
0x00004010, 0x40084000, 0x00080000, 0x40000010,
0x00080010, 0x40004010, 0x40000010, 0x00080010,
0x00084000, 0x00000000, 0x40004000, 0x00004010,
0x40000000, 0x40080010, 0x40084010, 0x00084000
);
/**
* Pre-permuted S-box3
*
* @var array
* @access private
*/
var $sbox3 = array(
0x00000104, 0x04010100, 0x00000000, 0x04010004,
0x04000100, 0x00000000, 0x00010104, 0x04000100,
0x00010004, 0x04000004, 0x04000004, 0x00010000,
0x04010104, 0x00010004, 0x04010000, 0x00000104,
0x04000000, 0x00000004, 0x04010100, 0x00000100,
0x00010100, 0x04010000, 0x04010004, 0x00010104,
0x04000104, 0x00010100, 0x00010000, 0x04000104,
0x00000004, 0x04010104, 0x00000100, 0x04000000,
0x04010100, 0x04000000, 0x00010004, 0x00000104,
0x00010000, 0x04010100, 0x04000100, 0x00000000,
0x00000100, 0x00010004, 0x04010104, 0x04000100,
0x04000004, 0x00000100, 0x00000000, 0x04010004,
0x04000104, 0x00010000, 0x04000000, 0x04010104,
0x00000004, 0x00010104, 0x00010100, 0x04000004,
0x04010000, 0x04000104, 0x00000104, 0x04010000,
0x00010104, 0x00000004, 0x04010004, 0x00010100
);
/**
* Pre-permuted S-box4
*
* @var array
* @access private
*/
var $sbox4 = array(
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x00401040, 0x80400040, 0x80400000, 0x80001000,
0x00000000, 0x00401000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00400040, 0x80400000,
0x80000000, 0x00001000, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x80001000, 0x00001040,
0x80400040, 0x80000000, 0x00001040, 0x00400040,
0x00001000, 0x00401040, 0x80401040, 0x80000040,
0x00400040, 0x80400000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00000000, 0x00401000,
0x00001040, 0x00400040, 0x80400040, 0x80000000,
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x80401040, 0x80000040, 0x80000000, 0x00001000,
0x80400000, 0x80001000, 0x00401040, 0x80400040,
0x80001000, 0x00001040, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x00001000, 0x00401040
);
/**
* Pre-permuted S-box5
*
* @var array
* @access private
*/
var $sbox5 = array(
0x00000080, 0x01040080, 0x01040000, 0x21000080,
0x00040000, 0x00000080, 0x20000000, 0x01040000,
0x20040080, 0x00040000, 0x01000080, 0x20040080,
0x21000080, 0x21040000, 0x00040080, 0x20000000,
0x01000000, 0x20040000, 0x20040000, 0x00000000,
0x20000080, 0x21040080, 0x21040080, 0x01000080,
0x21040000, 0x20000080, 0x00000000, 0x21000000,
0x01040080, 0x01000000, 0x21000000, 0x00040080,
0x00040000, 0x21000080, 0x00000080, 0x01000000,
0x20000000, 0x01040000, 0x21000080, 0x20040080,
0x01000080, 0x20000000, 0x21040000, 0x01040080,
0x20040080, 0x00000080, 0x01000000, 0x21040000,
0x21040080, 0x00040080, 0x21000000, 0x21040080,
0x01040000, 0x00000000, 0x20040000, 0x21000000,
0x00040080, 0x01000080, 0x20000080, 0x00040000,
0x00000000, 0x20040000, 0x01040080, 0x20000080
);
/**
* Pre-permuted S-box6
*
* @var array
* @access private
*/
var $sbox6 = array(
0x10000008, 0x10200000, 0x00002000, 0x10202008,
0x10200000, 0x00000008, 0x10202008, 0x00200000,
0x10002000, 0x00202008, 0x00200000, 0x10000008,
0x00200008, 0x10002000, 0x10000000, 0x00002008,
0x00000000, 0x00200008, 0x10002008, 0x00002000,
0x00202000, 0x10002008, 0x00000008, 0x10200008,
0x10200008, 0x00000000, 0x00202008, 0x10202000,
0x00002008, 0x00202000, 0x10202000, 0x10000000,
0x10002000, 0x00000008, 0x10200008, 0x00202000,
0x10202008, 0x00200000, 0x00002008, 0x10000008,
0x00200000, 0x10002000, 0x10000000, 0x00002008,
0x10000008, 0x10202008, 0x00202000, 0x10200000,
0x00202008, 0x10202000, 0x00000000, 0x10200008,
0x00000008, 0x00002000, 0x10200000, 0x00202008,
0x00002000, 0x00200008, 0x10002008, 0x00000000,
0x10202000, 0x10000000, 0x00200008, 0x10002008
);
/**
* Pre-permuted S-box7
*
* @var array
* @access private
*/
var $sbox7 = array(
0x00100000, 0x02100001, 0x02000401, 0x00000000,
0x00000400, 0x02000401, 0x00100401, 0x02100400,
0x02100401, 0x00100000, 0x00000000, 0x02000001,
0x00000001, 0x02000000, 0x02100001, 0x00000401,
0x02000400, 0x00100401, 0x00100001, 0x02000400,
0x02000001, 0x02100000, 0x02100400, 0x00100001,
0x02100000, 0x00000400, 0x00000401, 0x02100401,
0x00100400, 0x00000001, 0x02000000, 0x00100400,
0x02000000, 0x00100400, 0x00100000, 0x02000401,
0x02000401, 0x02100001, 0x02100001, 0x00000001,
0x00100001, 0x02000000, 0x02000400, 0x00100000,
0x02100400, 0x00000401, 0x00100401, 0x02100400,
0x00000401, 0x02000001, 0x02100401, 0x02100000,
0x00100400, 0x00000000, 0x00000001, 0x02100401,
0x00000000, 0x00100401, 0x02100000, 0x00000400,
0x02000001, 0x02000400, 0x00000400, 0x00100001
);
/**
* Pre-permuted S-box8
*
* @var array
* @access private
*/
var $sbox8 = array(
0x08000820, 0x00000800, 0x00020000, 0x08020820,
0x08000000, 0x08000820, 0x00000020, 0x08000000,
0x00020020, 0x08020000, 0x08020820, 0x00020800,
0x08020800, 0x00020820, 0x00000800, 0x00000020,
0x08020000, 0x08000020, 0x08000800, 0x00000820,
0x00020800, 0x00020020, 0x08020020, 0x08020800,
0x00000820, 0x00000000, 0x00000000, 0x08020020,
0x08000020, 0x08000800, 0x00020820, 0x00020000,
0x00020820, 0x00020000, 0x08020800, 0x00000800,
0x00000020, 0x08020020, 0x00000800, 0x00020820,
0x08000800, 0x00000020, 0x08000020, 0x08020000,
0x08020020, 0x08000000, 0x00020000, 0x08000820,
0x00000000, 0x08020820, 0x00020020, 0x08000020,
0x08020000, 0x08000800, 0x08000820, 0x00000000,
0x08020820, 0x00020800, 0x00020800, 0x00000820,
0x00000820, 0x00020020, 0x08000000, 0x08020800
);
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::isValidEngine()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($this->key_length_max == 8) {
if ($engine == CRYPT_ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ecb';
$this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode();
}
}
return parent::isValidEngine($engine);
}
/**
* Sets the key.
*
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
* only use the first eight, if $key has more then eight characters in it, and pad $key with the
* null byte if it is less then eight characters long.
*
* 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.
*
* @see Crypt_Base::setKey()
* @access public
* @param string $key
*/
function setKey($key)
{
// We check/cut here only up to max length of the key.
// Key padding to the proper length will be done in _setupKey()
if (strlen($key) > $this->key_length_max) {
$key = substr($key, 0, $this->key_length_max);
}
// Sets the key
parent::setKey($key);
}
/**
* Encrypts a block
*
* @see Crypt_Base::_encryptBlock()
* @see Crypt_Base::encrypt()
* @see self::encrypt()
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
return $this->_processBlock($in, CRYPT_DES_ENCRYPT);
}
/**
* Decrypts a block
*
* @see Crypt_Base::_decryptBlock()
* @see Crypt_Base::decrypt()
* @see self::decrypt()
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
return $this->_processBlock($in, CRYPT_DES_DECRYPT);
}
/**
* Encrypts or decrypts a 64-bit block
*
* $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
* {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
* idea of what this function does.
*
* @see self::_encryptBlock()
* @see self::_decryptBlock()
* @access private
* @param string $block
* @param int $mode
* @return string
*/
function _processBlock($block, $mode)
{
static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map("intval", $this->sbox1);
$sbox2 = array_map("intval", $this->sbox2);
$sbox3 = array_map("intval", $this->sbox3);
$sbox4 = array_map("intval", $this->sbox4);
$sbox5 = array_map("intval", $this->sbox5);
$sbox6 = array_map("intval", $this->sbox6);
$sbox7 = array_map("intval", $this->sbox7);
$sbox8 = array_map("intval", $this->sbox8);
/* Merge $shuffle with $[inv]ipmap */
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = $this->shuffle[$this->ipmap[$i]];
$shuffleinvip[] = $this->shuffle[$this->invipmap[$i]];
}
}
$keys = $this->keys[$mode];
$ki = -1;
// Do the initial IP permutation.
$t = unpack('Nl/Nr', $block);
list($l, $r) = array($t['l'], $t['r']);
$block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
// Extract L0 and R0.
$t = unpack('Nl/Nr', $block);
list($l, $r) = array($t['l'], $t['r']);
for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
// Perform the 16 steps.
for ($i = 0; $i < 16; $i++) {
// start of "the Feistel (F) function" - see the following URL:
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
// Merge key schedule.
$b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
$b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki];
// S-box indexing.
$t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l;
// end of "the Feistel (F) function"
$l = $r;
$r = $t;
}
// Last step should not permute L & R.
$t = $l;
$l = $r;
$r = $t;
}
// Perform the inverse IP permutation.
return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
}
/**
* Creates the key schedule
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds);
static $shifts = array( // number of key bits shifted per round
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
);
static $pc1map = array(
0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
);
// Mapping tables for the PC-2 transformation.
static $pc2mapc1 = array(
0x00000000, 0x00000400, 0x00200000, 0x00200400,
0x00000001, 0x00000401, 0x00200001, 0x00200401,
0x02000000, 0x02000400, 0x02200000, 0x02200400,
0x02000001, 0x02000401, 0x02200001, 0x02200401
);
static $pc2mapc2 = array(
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910
);
static $pc2mapc3 = array(
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026
);
static $pc2mapc4 = array(
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208
);
static $pc2mapd1 = array(
0x00000000, 0x00000001, 0x08000000, 0x08000001,
0x00200000, 0x00200001, 0x08200000, 0x08200001,
0x00000002, 0x00000003, 0x08000002, 0x08000003,
0x00200002, 0x00200003, 0x08200002, 0x08200003
);
static $pc2mapd2 = array(
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04
);
static $pc2mapd3 = array(
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030
);
static $pc2mapd4 = array(
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081108, 0x10081508, 0x11081108, 0x11081508,
0x10081108, 0x10081508, 0x11081108, 0x11081508
);
$keys = array();
for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
// pad the key and remove extra characters as appropriate.
$key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");
// Perform the PC/1 transformation and compute C and D.
$t = unpack('Nl/Nr', $key);
list($l, $r) = array($t['l'], $t['r']);
$key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
$key = unpack('Nc/Nd', $key);
$c = ( $key['c'] >> 4) & 0x0FFFFFFF;
$d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
$keys[$des_round] = array(
CRYPT_DES_ENCRYPT => array(),
CRYPT_DES_DECRYPT => array_fill(0, 32, 0)
);
for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) {
$c <<= $shifts[$i];
$c = ($c | ($c >> 28)) & 0x0FFFFFFF;
$d <<= $shifts[$i];
$d = ($d | ($d >> 28)) & 0x0FFFFFFF;
// Perform the PC-2 transformation.
$cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] |
$pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF];
$dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] |
$pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];
// Reorder: odd bytes/even bytes. Push the result in key schedule.
$val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
(($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
$val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
(($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
$keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val1;
$keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = $val1;
$keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val2;
$keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = $val2;
}
}
switch ($this->des_rounds) {
case 3: // 3DES keys
$this->keys = array(
CRYPT_DES_ENCRYPT => array_merge(
$keys[0][CRYPT_DES_ENCRYPT],
$keys[1][CRYPT_DES_DECRYPT],
$keys[2][CRYPT_DES_ENCRYPT]
),
CRYPT_DES_DECRYPT => array_merge(
$keys[2][CRYPT_DES_DECRYPT],
$keys[1][CRYPT_DES_ENCRYPT],
$keys[0][CRYPT_DES_DECRYPT]
)
);
break;
// case 1: // DES keys
default:
$this->keys = array(
CRYPT_DES_ENCRYPT => $keys[0][CRYPT_DES_ENCRYPT],
CRYPT_DES_DECRYPT => $keys[0][CRYPT_DES_DECRYPT]
);
}
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
$lambda_functions =& Crypt_DES::_getLambdaFunctions();
// Engine configuration for:
// - DES ($des_rounds == 1) or
// - 3DES ($des_rounds == 3)
$des_rounds = $this->des_rounds;
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_DES, one generated $lambda_function cost on php5.5@32bit ~135kb unfreeable mem and ~230kb on php5.5@64bit)
// (Currently, for Crypt_TripleDES, one generated $lambda_function cost on php5.5@32bit ~240kb unfreeable mem and ~340kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one
$gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
// Generation of a unique hash for our generated code
$code_hash = "Crypt_DES, $des_rounds, {$this->mode}";
if ($gen_hi_opt_code) {
// For hi-optimized code, we create for each combination of
// $mode, $des_rounds and $this->key its own encrypt/decrypt function.
// After max 10 hi-optimized functions, we create generic
// (still very fast.. but not ultra) functions for each $mode/$des_rounds
// Currently 2 * 5 generic functions will be then max. possible.
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
// Is there a re-usable $lambda_functions in there? If not, we have to create it.
if (!isset($lambda_functions[$code_hash])) {
// Init code for both, encrypt and decrypt.
$init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map("intval", $self->sbox1);
$sbox2 = array_map("intval", $self->sbox2);
$sbox3 = array_map("intval", $self->sbox3);
$sbox4 = array_map("intval", $self->sbox4);
$sbox5 = array_map("intval", $self->sbox5);
$sbox6 = array_map("intval", $self->sbox6);
$sbox7 = array_map("intval", $self->sbox7);
$sbox8 = array_map("intval", $self->sbox8);'
/* Merge $shuffle with $[inv]ipmap */ . '
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = $self->shuffle[$self->ipmap[$i]];
$shuffleinvip[] = $self->shuffle[$self->invipmap[$i]];
}
}
';
switch (true) {
case $gen_hi_opt_code:
// In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers.
// No futher initialisation of the $keys schedule is necessary.
// That is the extra performance boost.
$k = array(
CRYPT_DES_ENCRYPT => $this->keys[CRYPT_DES_ENCRYPT],
CRYPT_DES_DECRYPT => $this->keys[CRYPT_DES_DECRYPT]
);
$init_encrypt = '';
$init_decrypt = '';
break;
default:
// In generic optimized code mode, we have to use, as the best compromise [currently],
// our key schedule as $ke/$kd arrays. (with hardcoded indexes...)
$k = array(
CRYPT_DES_ENCRYPT => array(),
CRYPT_DES_DECRYPT => array()
);
for ($i = 0, $c = count($this->keys[CRYPT_DES_ENCRYPT]); $i < $c; ++$i) {
$k[CRYPT_DES_ENCRYPT][$i] = '$ke[' . $i . ']';
$k[CRYPT_DES_DECRYPT][$i] = '$kd[' . $i . ']';
}
$init_encrypt = '$ke = $self->keys[CRYPT_DES_ENCRYPT];';
$init_decrypt = '$kd = $self->keys[CRYPT_DES_DECRYPT];';
break;
}
// Creating code for en- and decryption.
$crypt_block = array();
foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) {
/* Do the initial IP permutation. */
$crypt_block[$c] = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
$in = unpack("N*",
($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
);
' . /* Extract L0 and R0 */ '
$l = $in[1];
$r = $in[2];
';
$l = '$l';
$r = '$r';
// Perform DES or 3DES.
for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
// Perform the 16 steps.
for ($i = 0; $i < 16; ++$i) {
// start of "the Feistel (F) function" - see the following URL:
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
// Merge key schedule.
$crypt_block[$c].= '
$b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
$b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' .
/* S-box indexing. */
$l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . ';
';
// end of "the Feistel (F) function"
// swap L & R
list($l, $r) = array($r, $l);
}
list($l, $r) = array($r, $l);
}
// Perform the inverse IP permutation.
$crypt_block[$c].= '$in =
($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
';
}
// Creates the inline-crypt function
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => $init_encrypt,
'init_decrypt' => $init_decrypt,
'encrypt_block' => $crypt_block[CRYPT_DES_ENCRYPT],
'decrypt_block' => $crypt_block[CRYPT_DES_DECRYPT]
)
);
}
// Set the inline-crypt function as callback in: $this->inline_crypt
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php
/**
* 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, sha256-96, sha384, and sha512, sha512-96
*
* If {@link self::setKey() setKey()} is called, {@link self::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
* {@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';
*
* $hash = new Crypt_Hash('sha1');
*
* $hash->setKey('abcdefg');
*
* echo base64_encode($hash->hash('abcdefg'));
* ?>
* </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_Hash
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* @access private
* @see self::Crypt_Hash()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_HASH_MODE_INTERNAL', 1);
/**
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
*/
define('CRYPT_HASH_MODE_MHASH', 2);
/**
* Toggles the hash() implementation, which works on PHP 5.1.2+.
*/
define('CRYPT_HASH_MODE_HASH', 3);
/**#@-*/
/**
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
*
* @package Crypt_Hash
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Crypt_Hash
{
/**
* Hash Parameter
*
* @see self::setHash()
* @var int
* @access private
*/
var $hashParam;
/**
* Byte-length of compression blocks / key (Internal HMAC)
*
* @see self::setAlgorithm()
* @var int
* @access private
*/
var $b;
/**
* Byte-length of hash output (Internal HMAC)
*
* @see self::setHash()
* @var int
* @access private
*/
var $l = false;
/**
* Hash Algorithm
*
* @see self::setHash()
* @var string
* @access private
*/
var $hash;
/**
* Key
*
* @see self::setKey()
* @var string
* @access private
*/
var $key = false;
/**
* Computed Key
*
* @see self::_computeKey()
* @var string
* @access private
*/
var $computedKey = false;
/**
* Outer XOR (Internal HMAC)
*
* @see self::setKey()
* @var string
* @access private
*/
var $opad;
/**
* Inner XOR (Internal HMAC)
*
* @see self::setKey()
* @var string
* @access private
*/
var $ipad;
/**
* Default Constructor.
*
* @param string $hash
* @return Crypt_Hash
* @access public
*/
function __construct($hash = 'sha1')
{
if (!defined('CRYPT_HASH_MODE')) {
switch (true) {
case extension_loaded('hash'):
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
break;
case extension_loaded('mhash'):
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
break;
default:
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
}
}
$this->setHash($hash);
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param int $mode
* @access public
*/
function Crypt_Hash($hash = 'sha1')
{
$this->__construct($hash);
}
/**
* Sets the key for HMACs
*
* Keys can be of any length.
*
* @access public
* @param string $key
*/
function setKey($key = false)
{
$this->key = $key;
$this->_computeKey();
}
/**
* Pre-compute the key used by the HMAC
*
* Quoting http://tools.ietf.org/html/rfc2104#section-2, "Applications that use keys longer than B bytes
* will first hash the key using H and then use the resultant L byte string as the actual key to HMAC."
*
* As documented in https://www.reddit.com/r/PHP/comments/9nct2l/symfonypolyfill_hash_pbkdf2_correct_fix_for/
* when doing an HMAC multiple times it's faster to compute the hash once instead of computing it during
* every call
*
* @access private
*/
function _computeKey()
{
if ($this->key === false) {
$this->computedKey = false;
return;
}
if (strlen($this->key) <= $this->b) {
$this->computedKey = $this->key;
return;
}
switch ($mode) {
case CRYPT_HASH_MODE_MHASH:
$this->computedKey = mhash($this->hash, $this->key);
break;
case CRYPT_HASH_MODE_HASH:
$this->computedKey = hash($this->hash, $this->key, true);
break;
case CRYPT_HASH_MODE_INTERNAL:
$this->computedKey = call_user_func($this->hash, $this->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.
*
* @access public
* @param string $hash
*/
function setHash($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':
case 'md5':
$this->l = 16;
break;
case 'sha1':
$this->l = 20;
break;
case 'sha256':
$this->l = 32;
break;
case 'sha384':
$this->l = 48;
break;
case 'sha512':
$this->l = 64;
}
switch ($hash) {
case 'md2-96':
case 'md2':
$this->b = 16;
case 'md5-96':
case 'sha1-96':
case 'sha224-96':
case 'sha256-96':
case 'md2':
case 'md5':
case 'sha1':
case 'sha224':
case 'sha256':
$this->b = 64;
break;
default:
$this->b = 128;
}
switch ($hash) {
case 'md2':
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
break;
case 'sha384':
case 'sha512':
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
break;
default:
$mode = CRYPT_HASH_MODE;
}
switch ($mode) {
case CRYPT_HASH_MODE_MHASH:
switch ($hash) {
case 'md5':
$this->hash = MHASH_MD5;
break;
case 'sha256':
$this->hash = MHASH_SHA256;
break;
case 'sha1':
default:
$this->hash = MHASH_SHA1;
}
$this->_computeKey();
return;
case CRYPT_HASH_MODE_HASH:
switch ($hash) {
case 'md5':
$this->hash = 'md5';
return;
case 'md2':
case 'sha256':
case 'sha384':
case 'sha512':
$this->hash = $hash;
return;
case 'sha1':
default:
$this->hash = 'sha1';
}
$this->_computeKey();
return;
}
switch ($hash) {
case 'md2':
$this->hash = array($this, '_md2');
break;
case 'md5':
$this->hash = array($this, '_md5');
break;
case 'sha256':
$this->hash = array($this, '_sha256');
break;
case 'sha384':
case 'sha512':
$this->hash = array($this, '_sha512');
break;
case 'sha1':
default:
$this->hash = array($this, '_sha1');
}
$this->ipad = str_repeat(chr(0x36), $this->b);
$this->opad = str_repeat(chr(0x5C), $this->b);
$this->_computeKey();
}
/**
* Compute the HMAC.
*
* @access public
* @param string $text
* @return string
*/
function hash($text)
{
$mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
if (!empty($this->key) || is_string($this->key)) {
switch ($mode) {
case CRYPT_HASH_MODE_MHASH:
$output = mhash($this->hash, $text, $this->computedKey);
break;
case CRYPT_HASH_MODE_HASH:
$output = hash_hmac($this->hash, $text, $this->computedKey, true);
break;
case CRYPT_HASH_MODE_INTERNAL:
$key = str_pad($this->computedKey, $this->b, chr(0)); // step 1
$temp = $this->ipad ^ $key; // step 2
$temp .= $text; // step 3
$temp = call_user_func($this->hash, $temp); // step 4
$output = $this->opad ^ $key; // step 5
$output.= $temp; // step 6
$output = call_user_func($this->hash, $output); // step 7
}
} else {
switch ($mode) {
case CRYPT_HASH_MODE_MHASH:
$output = mhash($this->hash, $text);
break;
case CRYPT_HASH_MODE_HASH:
$output = hash($this->hash, $text, true);
break;
case CRYPT_HASH_MODE_INTERNAL:
$output = call_user_func($this->hash, $text);
}
}
return substr($output, 0, $this->l);
}
/**
* Returns the hash length (in bytes)
*
* @access public
* @return int
*/
function getLength()
{
return $this->l;
}
/**
* Wrapper for MD5
*
* @access private
* @param string $m
*/
function _md5($m)
{
return pack('H*', md5($m));
}
/**
* Wrapper for SHA1
*
* @access private
* @param string $m
*/
function _sha1($m)
{
return pack('H*', sha1($m));
}
/**
* Pure-PHP implementation of MD2
*
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
*
* @access private
* @param string $m
*/
function _md2($m)
{
static $s = array(
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
);
// Step 1. Append Padding Bytes
$pad = 16 - (strlen($m) & 0xF);
$m.= str_repeat(chr($pad), $pad);
$length = strlen($m);
// Step 2. Append Checksum
$c = str_repeat(chr(0), 16);
$l = chr(0);
for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {
// RFC1319 incorrectly states that C[j] should be set to S[c xor L]
//$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
// per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
$c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
$l = $c[$j];
}
}
$m.= $c;
$length+= 16;
// Step 3. Initialize MD Buffer
$x = str_repeat(chr(0), 48);
// Step 4. Process Message in 16-Byte Blocks
for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {
$x[$j + 16] = $m[$i + $j];
$x[$j + 32] = $x[$j + 16] ^ $x[$j];
}
$t = chr(0);
for ($j = 0; $j < 18; $j++) {
for ($k = 0; $k < 48; $k++) {
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
//$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
}
$t = chr(ord($t) + $j);
}
}
// Step 5. Output
return substr($x, 0, 16);
}
/**
* Pure-PHP implementation of SHA256
*
* See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
*
* @access private
* @param string $m
*/
function _sha256($m)
{
if (extension_loaded('suhosin')) {
return pack('H*', sha256($m));
}
// Initialize variables
$hash = array(
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
);
// Initialize table of round constants
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
static $k = array(
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
);
// Pre-processing
$length = strlen($m);
// to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
$m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
$m[$length] = chr(0x80);
// we don't support hashing strings 512MB long
$m.= pack('N2', 0, $length << 3);
// Process the message in successive 512-bit chunks
$chunks = str_split($m, 64);
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
$w[] = $temp;
}
// Extend the sixteen 32-bit words into sixty-four 32-bit words
for ($i = 16; $i < 64; $i++) {
// @codingStandardsIgnoreStart
$s0 = $this->_rightRotate($w[$i - 15], 7) ^
$this->_rightRotate($w[$i - 15], 18) ^
$this->_rightShift( $w[$i - 15], 3);
$s1 = $this->_rightRotate($w[$i - 2], 17) ^
$this->_rightRotate($w[$i - 2], 19) ^
$this->_rightShift( $w[$i - 2], 10);
// @codingStandardsIgnoreEnd
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
}
// Initialize hash value for this chunk
list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
// Main loop
for ($i = 0; $i < 64; $i++) {
$s0 = $this->_rightRotate($a, 2) ^
$this->_rightRotate($a, 13) ^
$this->_rightRotate($a, 22);
$maj = ($a & $b) ^
($a & $c) ^
($b & $c);
$t2 = $this->_add($s0, $maj);
$s1 = $this->_rightRotate($e, 6) ^
$this->_rightRotate($e, 11) ^
$this->_rightRotate($e, 25);
$ch = ($e & $f) ^
($this->_not($e) & $g);
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
$h = $g;
$g = $f;
$f = $e;
$e = $this->_add($d, $t1);
$d = $c;
$c = $b;
$b = $a;
$a = $this->_add($t1, $t2);
}
// Add this chunk's hash to result so far
$hash = array(
$this->_add($hash[0], $a),
$this->_add($hash[1], $b),
$this->_add($hash[2], $c),
$this->_add($hash[3], $d),
$this->_add($hash[4], $e),
$this->_add($hash[5], $f),
$this->_add($hash[6], $g),
$this->_add($hash[7], $h)
);
}
// Produce the final hash value (big-endian)
return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
}
/**
* Pure-PHP implementation of SHA384 and SHA512
*
* @access private
* @param string $m
*/
function _sha512($m)
{
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
static $init384, $init512, $k;
if (!isset($k)) {
// Initialize variables
$init384 = array( // initial values for SHA384
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
);
$init512 = array( // initial values for SHA512
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
);
for ($i = 0; $i < 8; $i++) {
$init384[$i] = new Math_BigInteger($init384[$i], 16);
$init384[$i]->setPrecision(64);
$init512[$i] = new Math_BigInteger($init512[$i], 16);
$init512[$i]->setPrecision(64);
}
// Initialize table of round constants
// (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
$k = array(
'428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
'3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
'72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
'2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
'983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
'27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
'650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
'19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
'391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
'748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
'90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
'06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
'28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
'4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
);
for ($i = 0; $i < 80; $i++) {
$k[$i] = new Math_BigInteger($k[$i], 16);
}
}
$hash = $this->l == 48 ? $init384 : $init512;
// Pre-processing
$length = strlen($m);
// to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
$m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
$m[$length] = chr(0x80);
// we don't support hashing strings 512MB long
$m.= pack('N4', 0, 0, 0, $length << 3);
// Process the message in successive 1024-bit chunks
$chunks = str_split($m, 128);
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
$temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
$temp->setPrecision(64);
$w[] = $temp;
}
// Extend the sixteen 32-bit words into eighty 32-bit words
for ($i = 16; $i < 80; $i++) {
$temp = array(
$w[$i - 15]->bitwise_rightRotate(1),
$w[$i - 15]->bitwise_rightRotate(8),
$w[$i - 15]->bitwise_rightShift(7)
);
$s0 = $temp[0]->bitwise_xor($temp[1]);
$s0 = $s0->bitwise_xor($temp[2]);
$temp = array(
$w[$i - 2]->bitwise_rightRotate(19),
$w[$i - 2]->bitwise_rightRotate(61),
$w[$i - 2]->bitwise_rightShift(6)
);
$s1 = $temp[0]->bitwise_xor($temp[1]);
$s1 = $s1->bitwise_xor($temp[2]);
$w[$i] = $w[$i - 16]->copy();
$w[$i] = $w[$i]->add($s0);
$w[$i] = $w[$i]->add($w[$i - 7]);
$w[$i] = $w[$i]->add($s1);
}
// Initialize hash value for this chunk
$a = $hash[0]->copy();
$b = $hash[1]->copy();
$c = $hash[2]->copy();
$d = $hash[3]->copy();
$e = $hash[4]->copy();
$f = $hash[5]->copy();
$g = $hash[6]->copy();
$h = $hash[7]->copy();
// Main loop
for ($i = 0; $i < 80; $i++) {
$temp = array(
$a->bitwise_rightRotate(28),
$a->bitwise_rightRotate(34),
$a->bitwise_rightRotate(39)
);
$s0 = $temp[0]->bitwise_xor($temp[1]);
$s0 = $s0->bitwise_xor($temp[2]);
$temp = array(
$a->bitwise_and($b),
$a->bitwise_and($c),
$b->bitwise_and($c)
);
$maj = $temp[0]->bitwise_xor($temp[1]);
$maj = $maj->bitwise_xor($temp[2]);
$t2 = $s0->add($maj);
$temp = array(
$e->bitwise_rightRotate(14),
$e->bitwise_rightRotate(18),
$e->bitwise_rightRotate(41)
);
$s1 = $temp[0]->bitwise_xor($temp[1]);
$s1 = $s1->bitwise_xor($temp[2]);
$temp = array(
$e->bitwise_and($f),
$g->bitwise_and($e->bitwise_not())
);
$ch = $temp[0]->bitwise_xor($temp[1]);
$t1 = $h->add($s1);
$t1 = $t1->add($ch);
$t1 = $t1->add($k[$i]);
$t1 = $t1->add($w[$i]);
$h = $g->copy();
$g = $f->copy();
$f = $e->copy();
$e = $d->add($t1);
$d = $c->copy();
$c = $b->copy();
$b = $a->copy();
$a = $t1->add($t2);
}
// Add this chunk's hash to result so far
$hash = array(
$hash[0]->add($a),
$hash[1]->add($b),
$hash[2]->add($c),
$hash[3]->add($d),
$hash[4]->add($e),
$hash[5]->add($f),
$hash[6]->add($g),
$hash[7]->add($h)
);
}
// Produce the final hash value (big-endian)
// (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
$temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
$hash[4]->toBytes() . $hash[5]->toBytes();
if ($this->l != 48) {
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
}
return $temp;
}
/**
* Right Rotate
*
* @access private
* @param int $int
* @param int $amt
* @see self::_sha256()
* @return int
*/
function _rightRotate($int, $amt)
{
$invamt = 32 - $amt;
$mask = (1 << $invamt) - 1;
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
}
/**
* Right Shift
*
* @access private
* @param int $int
* @param int $amt
* @see self::_sha256()
* @return int
*/
function _rightShift($int, $amt)
{
$mask = (1 << (32 - $amt)) - 1;
return ($int >> $amt) & $mask;
}
/**
* Not
*
* @access private
* @param int $int
* @see self::_sha256()
* @return int
*/
function _not($int)
{
return ~$int & 0xFFFFFFFF;
}
/**
* Add
*
* _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
* possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
*
* @param int $...
* @return int
* @see self::_sha256()
* @access private
*/
function _add()
{
static $mod;
if (!isset($mod)) {
$mod = pow(2, 32);
}
$result = 0;
$arguments = func_get_args();
foreach ($arguments as $argument) {
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
}
switch (true) {
case is_int($result):
// PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
// PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
return fmod($result, $mod);
}
return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
((fmod(floor($result / 0x80000000), 2) & 1) << 31);
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
<?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 self::encrypt()
* @see self::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);
/**#@-*/
/**
* 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 int
* @access private
*/
var $block_size = 8;
/**
* The Key
*
* @see Crypt_Base::key
* @see self::setKey()
* @var string
* @access private
*/
var $key;
/**
* The Original (unpadded) Key
*
* @see Crypt_Base::key
* @see self::setKey()
* @see self::encrypt()
* @see self::decrypt()
* @var string
* @access private
*/
var $orig_key;
/**
* Don't truncate / null pad key
*
* @see Crypt_Base::_clearBuffers()
* @var bool
* @access private
*/
var $skip_key_adjustment = true;
/**
* Key Length (in bytes)
*
* @see Crypt_RC2::setKeyLength()
* @var int
* @access private
*/
var $key_length = 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 int
* @access private
*/
var $cfb_init_len = 500;
/**
* The key length in bits.
*
* @see self::setKeyLength()
* @see self::setKey()
* @var int
* @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 length in bits.
*
* @see self::isValidEnine()
* @see self::setKey()
* @var int
* @access private
* @internal Should be in range [1..1024].
*/
var $current_key_length;
/**
* The Key Schedule
*
* @see self::_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 self::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 self::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
);
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
switch ($engine) {
case CRYPT_ENGINE_OPENSSL:
if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'rc2-ecb';
$this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
}
return parent::isValidEngine($engine);
}
/**
* Sets the key length.
*
* Valid key lengths are 8 to 1024.
* Calling this function after setting the key has no effect until the next
* Crypt_RC2::setKey() call.
*
* @access public
* @param int $length in bits
*/
function setKeyLength($length)
{
if ($length < 8) {
$this->default_key_length = 1;
} elseif ($length > 1024) {
$this->default_key_length = 128;
} else {
$this->default_key_length = $length;
}
$this->current_key_length = $this->default_key_length;
parent::setKeyLength($length);
}
/**
* Returns the current key length
*
* @access public
* @return int
*/
function getKeyLength()
{
return $this->current_key_length;
}
/**
* Sets the key.
*
* Keys can be of any length. RC2, itself, uses 8 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 int $t1 optional Effective key length in bits.
*/
function setKey($key, $t1 = 0)
{
$this->orig_key = $key;
if ($t1 <= 0) {
$t1 = $this->default_key_length;
} elseif ($t1 > 1024) {
$t1 = 1024;
}
$this->current_key_length = $t1;
// 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 message.
*
* Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code
*
* @see self::decrypt()
* @access public
* @param string $plaintext
* @return string $ciphertext
*/
function encrypt($plaintext)
{
if ($this->engine == CRYPT_ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::encrypt($plaintext);
$this->key = $temp;
return $result;
}
return parent::encrypt($plaintext);
}
/**
* Decrypts a message.
*
* Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code
*
* @see self::encrypt()
* @access public
* @param string $ciphertext
* @return string $plaintext
*/
function decrypt($ciphertext)
{
if ($this->engine == CRYPT_ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::decrypt($ciphertext);
$this->key = $temp;
return $result;
}
return parent::decrypt($ciphertext);
}
/**
* 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);
}
/**
* Setup the CRYPT_ENGINE_MCRYPT $engine
*
* @see Crypt_Base::_setupMcrypt()
* @access private
*/
function _setupMcrypt()
{
if (!isset($this->key)) {
$this->setKey('');
}
parent::_setupMcrypt();
}
/**
* Creates the key schedule
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (!isset($this->key)) {
$this->setKey('');
}
// 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.
// (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a unique hash for our generated code
$code_hash = "Crypt_RC2, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
// Is there a re-usable $lambda_functions in there?
// 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;';
switch (true) {
case $gen_hi_opt_code:
$keys = $this->keys;
default:
$keys = array();
foreach ($this->keys as $k => $v) {
$keys[$k] = '$keys[' . $k . ']';
}
}
// $in is the current 8 bytes block which has to be en/decrypt
$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];
}
}
<?php
/**
* Pure-PHP implementation of RC4.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
* - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
*
* RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
* ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/RC4.php';
*
* $rc4 = new Crypt_RC4();
*
* $rc4->setKey('abcdefgh');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $rc4->decrypt($rc4->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_RC4
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 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 self::_crypt()
*/
define('CRYPT_RC4_ENCRYPT', 0);
define('CRYPT_RC4_DECRYPT', 1);
/**#@-*/
/**
* Pure-PHP implementation of RC4.
*
* @package Crypt_RC4
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
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 int
* @access private
*/
var $block_size = 0;
/**
* Key Length (in bytes)
*
* @see Crypt_RC4::setKeyLength()
* @var int
* @access private
*/
var $key_length = 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
*
* @see self::setKey()
* @var string
* @access private
*/
var $key;
/**
* The Key Stream for decryption and encryption
*
* @see self::setKey()
* @var array
* @access private
*/
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 __construct()
{
parent::__construct(CRYPT_MODE_STREAM);
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function Crypt_RC4()
{
$this->__construct();
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
$this->cipher_name_openssl = 'rc4-40';
} else {
switch (strlen($this->key)) {
case 5:
$this->cipher_name_openssl = 'rc4-40';
break;
case 8:
$this->cipher_name_openssl = 'rc4-64';
break;
case 16:
$this->cipher_name_openssl = 'rc4';
break;
default:
return false;
}
}
}
return parent::isValidEngine($engine);
}
/**
* Dummy function.
*
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
* calling setKey().
*
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
* the IV's are relatively easy to predict, an attack described by
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
* can be used to quickly guess at the rest of the key. The following links elaborate:
*
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
*
* @param string $iv
* @see self::setKey()
* @access public
*/
function setIV($iv)
{
}
/**
* Sets the key length
*
* Keys can be between 1 and 256 bytes long.
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
if ($length < 8) {
$this->key_length = 1;
} elseif ($length > 2048) {
$this->key_length = 256;
} else {
$this->key_length = $length >> 3;
}
parent::setKeyLength($length);
}
/**
* Encrypts a message.
*
* @see Crypt_Base::decrypt()
* @see self::_crypt()
* @access public
* @param string $plaintext
* @return string $ciphertext
*/
function encrypt($plaintext)
{
if ($this->engine != CRYPT_ENGINE_INTERNAL) {
return parent::encrypt($plaintext);
}
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
}
/**
* Decrypts a message.
*
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
* At least if the continuous buffer is disabled.
*
* @see Crypt_Base::encrypt()
* @see self::_crypt()
* @access public
* @param string $ciphertext
* @return string $plaintext
*/
function decrypt($ciphertext)
{
if ($this->engine != CRYPT_ENGINE_INTERNAL) {
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.
*
* @see self::encrypt()
* @see self::decrypt()
* @access private
* @param string $text
* @param int $mode
* @return string $text
*/
function _crypt($text, $mode)
{
if ($this->changed) {
$this->_setup();
$this->changed = false;
}
$stream = &$this->stream[$mode];
if ($this->continuousBuffer) {
$i = &$stream[0];
$j = &$stream[1];
$keyStream = &$stream[2];
} else {
$i = $stream[0];
$j = $stream[1];
$keyStream = $stream[2];
}
$len = strlen($text);
for ($k = 0; $k < $len; ++$k) {
$i = ($i + 1) & 255;
$ksi = $keyStream[$i];
$j = ($j + $ksi) & 255;
$ksj = $keyStream[$j];
$keyStream[$i] = $ksj;
$keyStream[$j] = $ksi;
$text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
}
return $text;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
/**
* 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';
*
* echo bin2hex(crypt_random_string(8));
* ?>
* </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_Random
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
// 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 int $length
* @return string
* @access public
*/
function crypt_random_string($length)
{
if (!$length) {
return '';
}
if (CRYPT_RANDOM_IS_WINDOWS) {
// method 1. prior to PHP 5.3, mcrypt_create_iv() would call rand() on windows
if (extension_loaded('mcrypt') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
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 (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
return openssl_random_pseudo_bytes($length);
}
} else {
// method 1. the fastest
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
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 (extension_loaded('mcrypt')) {
return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
}
// at this point we have no choice but to use a pure-PHP CSPRNG
// cascade entropy across multiple PHP instances by fixing the session and collecting all
// environmental variables, including the previous session data and the current session
// data.
//
// mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
// easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
// PHP isn't low level to be able to use those as sources and on a web server there's not likely
// going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
// however, a ton of people visiting the website. obviously you don't want to base your seeding
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
// by the user and (2) this isn't just looking at the data sent by the current user - it's based
// on the data sent by all users. one user requests the page and a hash of their info is saved.
// another user visits the page and the serialization of their data is utilized along with the
// server envirnment stuff and a hash of the previous http request data (which itself utilizes
// a hash of the session data before that). certainly an attacker should be assumed to have
// full control over his own http requests. he, however, is not going to have control over
// everyone's http requests.
static $crypto = false, $v;
if ($crypto === false) {
// save old session data
$old_session_id = session_id();
$old_use_cookies = ini_get('session.use_cookies');
$old_session_cache_limiter = session_cache_limiter();
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
if ($old_session_id != '') {
session_write_close();
}
session_id(1);
ini_set('session.use_cookies', 0);
session_cache_limiter('');
session_start();
$v = $seed = $_SESSION['seed'] = pack('H*', sha1(
(isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
(isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
(isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
(isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
phpseclib_safe_serialize($GLOBALS) .
phpseclib_safe_serialize($_SESSION) .
phpseclib_safe_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();
}
//return $crypto->encrypt(str_repeat("\0", $length));
// the following is based off of ANSI X9.31:
//
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
//
// OpenSSL uses that same standard for it's random numbers:
//
// 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")
$result = '';
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);
}
}
if (!function_exists('phpseclib_safe_serialize')) {
/**
* Safely serialize variables
*
* If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
* PHP 5.3 will emit a warning.
*
* @param mixed $arr
* @access public
*/
function phpseclib_safe_serialize(&$arr)
{
if (is_object($arr)) {
return '';
}
if (!is_array($arr)) {
return serialize($arr);
}
// prevent circular array recursion
if (isset($arr['__phpseclib_marker'])) {
return '';
}
$safearr = array();
$arr['__phpseclib_marker'] = true;
foreach (array_keys($arr) as $key) {
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
if ($key !== '__phpseclib_marker') {
$safearr[$key] = phpseclib_safe_serialize($arr[$key]);
}
}
unset($arr['__phpseclib_marker']);
return serialize($safearr);
}
}
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 string|false
* @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;
}
}
<?php
/**
* Pure-PHP implementation of Rijndael.
*
* Uses mcrypt, if available/possible, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* If {@link self::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
* {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
* 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until
* {@link self::setKey() setKey()} is called, again, at which point, it'll be recalculated.
*
* Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
* does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
* {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
* algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
* are first defined as valid key / block lengths in
* {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
* Extensions: Other block and Cipher Key lengths.
* Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224).
*
* {@internal The variable names are the same as those in
* {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/Rijndael.php';
*
* $rijndael = new Crypt_Rijndael();
*
* $rijndael->setKey('abcdefghijklmnop');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $rijndael->decrypt($rijndael->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_Rijndael
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2008 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 public
* @see self::encrypt()
* @see self::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_RIJNDAEL_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_RIJNDAEL_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_RIJNDAEL_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_RIJNDAEL_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_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of Rijndael.
*
* @package Crypt_Rijndael
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Crypt_Rijndael extends Crypt_Base
{
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'RIJNDAEL';
/**
* The mcrypt specific name of the cipher
*
* Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
* Crypt_Rijndael determines automatically whether mcrypt is useable
* or not for the current $block_size/$key_length.
* In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
*
* @see Crypt_Base::cipher_name_mcrypt
* @see Crypt_Base::engine
* @see self::isValidEngine()
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'rijndael-128';
/**
* 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 Key Schedule
*
* @see self::_setup()
* @var array
* @access private
*/
var $w;
/**
* The Inverse Key Schedule
*
* @see self::_setup()
* @var array
* @access private
*/
var $dw;
/**
* The Block Length divided by 32
*
* @see self::setBlockLength()
* @var int
* @access private
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
* because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
* derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.
*/
var $Nb = 4;
/**
* The Key Length (in bytes)
*
* @see self::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
* because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
* derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.
*/
var $key_length = 16;
/**
* The Key Length divided by 32
*
* @see self::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
*/
var $Nk = 4;
/**
* The Number of Rounds
*
* @var int
* @access private
* @internal The max value is 14, the min value is 10.
*/
var $Nr;
/**
* Shift offsets
*
* @var array
* @access private
*/
var $c;
/**
* Holds the last used key- and block_size information
*
* @var array
* @access private
*/
var $kl;
/**
* Sets the key.
*
* Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
* whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
* up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
* excess bits.
*
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits.
*
* @see Crypt_Base:setKey()
* @see self::setKeyLength()
* @access public
* @param string $key
*/
function setKey($key)
{
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 20:
$this->key_size = 20;
break;
case $length <= 24:
$this->key_size = 24;
break;
case $length <= 28:
$this->key_size = 28;
break;
default:
$this->key_size = 32;
}
}
parent::setKey($key);
}
/**
* Sets the key length
*
* Valid key lengths are 128, 160, 192, 224, 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.
*
* Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
* and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
* 192/256 bits as, for example, mcrypt will do.
*
* That said, if you want be compatible with other Rijndael and AES implementations,
* you should not setKeyLength(160) or setKeyLength(224).
*
* Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
* the mcrypt php extension, even if available.
* This results then in slower encryption.
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 160:
$this->key_length = 20;
break;
case $length <= 192:
$this->key_length = 24;
break;
case $length <= 224:
$this->key_length = 28;
break;
default:
$this->key_length = 32;
}
parent::setKeyLength($length);
}
/**
* Sets the block length
*
* Valid block lengths are 128, 160, 192, 224, 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.
*
* @access public
* @param int $length
*/
function setBlockLength($length)
{
$length >>= 5;
if ($length > 8) {
$length = 8;
} elseif ($length < 4) {
$length = 4;
}
$this->Nb = $length;
$this->block_size = $length << 2;
$this->changed = true;
$this->_setEngine();
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
switch ($engine) {
case CRYPT_ENGINE_OPENSSL:
if ($this->block_size != 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
$this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
break;
case CRYPT_ENGINE_MCRYPT:
$this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
if ($this->key_length % 8) { // is it a 160/224-bit key?
// mcrypt is not usable for them, only for 128/192/256-bit keys
return false;
}
}
return parent::isValidEngine($engine);
}
/**
* Encrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
static $tables;
if (empty($tables)) {
$tables = &$this->_getTables();
}
$t0 = $tables[0];
$t1 = $tables[1];
$t2 = $tables[2];
$t3 = $tables[3];
$sbox = $tables[4];
$state = array();
$words = unpack('N*', $in);
$c = $this->c;
$w = $this->w;
$Nb = $this->Nb;
$Nr = $this->Nr;
// addRoundKey
$wc = $Nb - 1;
foreach ($words as $word) {
$state[] = $word ^ $w[++$wc];
}
// fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
// subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
// Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
// Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
// Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
// equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
// [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
$temp = array();
for ($round = 1; $round < $Nr; ++$round) {
$i = 0; // $c[0] == 0
$j = $c[1];
$k = $c[2];
$l = $c[3];
while ($i < $Nb) {
$temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
$t1[$state[$j] >> 16 & 0x000000FF] ^
$t2[$state[$k] >> 8 & 0x000000FF] ^
$t3[$state[$l] & 0x000000FF] ^
$w[++$wc];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
}
// subWord
for ($i = 0; $i < $Nb; ++$i) {
$state[$i] = $sbox[$state[$i] & 0x000000FF] |
($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
}
// shiftRows + addRoundKey
$i = 0; // $c[0] == 0
$j = $c[1];
$k = $c[2];
$l = $c[3];
while ($i < $Nb) {
$temp[$i] = ($state[$i] & 0xFF000000) ^
($state[$j] & 0x00FF0000) ^
($state[$k] & 0x0000FF00) ^
($state[$l] & 0x000000FF) ^
$w[$i];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
switch ($Nb) {
case 8:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
case 7:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
case 6:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
case 5:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
default:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
}
}
/**
* Decrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
static $invtables;
if (empty($invtables)) {
$invtables = &$this->_getInvTables();
}
$dt0 = $invtables[0];
$dt1 = $invtables[1];
$dt2 = $invtables[2];
$dt3 = $invtables[3];
$isbox = $invtables[4];
$state = array();
$words = unpack('N*', $in);
$c = $this->c;
$dw = $this->dw;
$Nb = $this->Nb;
$Nr = $this->Nr;
// addRoundKey
$wc = $Nb - 1;
foreach ($words as $word) {
$state[] = $word ^ $dw[++$wc];
}
$temp = array();
for ($round = $Nr - 1; $round > 0; --$round) {
$i = 0; // $c[0] == 0
$j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];
while ($i < $Nb) {
$temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
$dt1[$state[$j] >> 16 & 0x000000FF] ^
$dt2[$state[$k] >> 8 & 0x000000FF] ^
$dt3[$state[$l] & 0x000000FF] ^
$dw[++$wc];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
}
// invShiftRows + invSubWord + addRoundKey
$i = 0; // $c[0] == 0
$j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];
while ($i < $Nb) {
$word = ($state[$i] & 0xFF000000) |
($state[$j] & 0x00FF0000) |
($state[$k] & 0x0000FF00) |
($state[$l] & 0x000000FF);
$temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] |
($isbox[$word >> 8 & 0x000000FF] << 8) |
($isbox[$word >> 16 & 0x000000FF] << 16) |
($isbox[$word >> 24 & 0x000000FF] << 24));
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
switch ($Nb) {
case 8:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
case 7:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
case 6:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
case 5:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
default:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
}
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
// Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
// See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
static $rcon = array(0,
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
);
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);
$this->Nk = $this->key_length >> 2;
// see Rijndael-ammended.pdf#page=44
$this->Nr = max($this->Nk, $this->Nb) + 6;
// shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
// "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
// shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
// "Table 2: Shift offsets for different block lengths"
switch ($this->Nb) {
case 4:
case 5:
case 6:
$this->c = array(0, 1, 2, 3);
break;
case 7:
$this->c = array(0, 1, 2, 4);
break;
case 8:
$this->c = array(0, 1, 3, 4);
}
$w = array_values(unpack('N*words', $this->key));
$length = $this->Nb * ($this->Nr + 1);
for ($i = $this->Nk; $i < $length; $i++) {
$temp = $w[$i - 1];
if ($i % $this->Nk == 0) {
// according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
// on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
// 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
// with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
$temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
$temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
} elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
$temp = $this->_subWord($temp);
}
$w[$i] = $w[$i - $this->Nk] ^ $temp;
}
// convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
// and generate the inverse key schedule. more specifically,
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
// "The key expansion for the Inverse Cipher is defined as follows:
// 1. Apply the Key Expansion.
// 2. Apply InvMixColumn to all Round Keys except the first and the last one."
// also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
$temp = $this->w = $this->dw = array();
for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
if ($col == $this->Nb) {
if ($row == 0) {
$this->dw[0] = $this->w[0];
} else {
// subWord + invMixColumn + invSubWord = invMixColumn
$j = 0;
while ($j < $this->Nb) {
$dw = $this->_subWord($this->w[$row][$j]);
$temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
$dt1[$dw >> 16 & 0x000000FF] ^
$dt2[$dw >> 8 & 0x000000FF] ^
$dt3[$dw & 0x000000FF];
$j++;
}
$this->dw[$row] = $temp;
}
$col = 0;
$row++;
}
$this->w[$row][$col] = $w[$i];
}
$this->dw[$row] = $this->w[$row];
// Converting to 1-dim key arrays (both ascending)
$this->dw = array_reverse($this->dw);
$w = array_pop($this->w);
$dw = array_pop($this->dw);
foreach ($this->w as $r => $wr) {
foreach ($wr as $c => $wc) {
$w[] = $wc;
$dw[] = $this->dw[$r][$c];
}
}
$this->w = $w;
$this->dw = $dw;
}
/**
* Performs S-Box substitutions
*
* @access private
* @param int $word
*/
function _subWord($word)
{
static $sbox;
if (empty($sbox)) {
list(, , , , $sbox) = $this->_getTables();
}
return $sbox[$word & 0x000000FF] |
($sbox[$word >> 8 & 0x000000FF] << 8) |
($sbox[$word >> 16 & 0x000000FF] << 16) |
($sbox[$word >> 24 & 0x000000FF] << 24);
}
/**
* Provides the mixColumns and sboxes tables
*
* @see Crypt_Rijndael:_encryptBlock()
* @see Crypt_Rijndael:_setupInlineCrypt()
* @see Crypt_Rijndael:_subWord()
* @access private
* @return array &$tables
*/
function &_getTables()
{
static $tables;
if (empty($tables)) {
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
// precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
// those are the names we'll use.
$t3 = array_map('intval', array(
// with array_map('intval', ...) we ensure we have only int's and not
// some slower floats converted by php automatically on high values
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
));
foreach ($t3 as $t3i) {
$t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF);
$t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
$t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
}
$tables = array(
// The Precomputed mixColumns tables t0 - t3
$t0,
$t1,
$t2,
$t3,
// The SubByte S-Box
array(
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)
);
}
return $tables;
}
/**
* Provides the inverse mixColumns and inverse sboxes tables
*
* @see Crypt_Rijndael:_decryptBlock()
* @see Crypt_Rijndael:_setupInlineCrypt()
* @see Crypt_Rijndael:_setupKey()
* @access private
* @return array &$tables
*/
function &_getInvTables()
{
static $tables;
if (empty($tables)) {
$dt3 = array_map('intval', array(
0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
));
foreach ($dt3 as $dt3i) {
$dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
$dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
$dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
};
$tables = array(
// The Precomputed inverse mixColumns tables dt0 - dt3
$dt0,
$dt1,
$dt2,
$dt3,
// The inverse SubByte S-Box
array(
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
)
);
}
return $tables;
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
// Note: _setupInlineCrypt() will be called only if $this->changed === true
// So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
// However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
$lambda_functions =& Crypt_Rijndael::_getLambdaFunctions();
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a uniqe hash for our generated code
$code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
// The hi-optimized $lambda_functions will use the key-words hardcoded for better performance.
$w = $this->w;
$dw = $this->dw;
$init_encrypt = '';
$init_decrypt = '';
break;
default:
for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
$w[] = '$w[' . $i . ']';
$dw[] = '$dw[' . $i . ']';
}
$init_encrypt = '$w = $self->w;';
$init_decrypt = '$dw = $self->dw;';
}
$Nr = $this->Nr;
$Nb = $this->Nb;
$c = $this->c;
// Generating encrypt code:
$init_encrypt.= '
static $tables;
if (empty($tables)) {
$tables = &$self->_getTables();
}
$t0 = $tables[0];
$t1 = $tables[1];
$t2 = $tables[2];
$t3 = $tables[3];
$sbox = $tables[4];
';
$s = 'e';
$e = 's';
$wc = $Nb - 1;
// Preround: addRoundKey
$encrypt_block = '$in = unpack("N*", $in);'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
}
// Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
for ($round = 1; $round < $Nr; ++$round) {
list($s, $e) = array($e, $s);
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.=
'$'.$e.$i.' =
$t0[($'.$s.$i .' >> 24) & 0xff] ^
$t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
$t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
$t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
'.$w[++$wc].";\n";
}
}
// Finalround: subWord + shiftRows + addRoundKey
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.=
'$'.$e.$i.' =
$sbox[ $'.$e.$i.' & 0xff] |
($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
}
$encrypt_block .= '$in = pack("N*"'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.= ',
($'.$e.$i .' & '.((int)0xFF000000).') ^
($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^
($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^
($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^
'.$w[$i]."\n";
}
$encrypt_block .= ');';
// Generating decrypt code:
$init_decrypt.= '
static $invtables;
if (empty($invtables)) {
$invtables = &$self->_getInvTables();
}
$dt0 = $invtables[0];
$dt1 = $invtables[1];
$dt2 = $invtables[2];
$dt3 = $invtables[3];
$isbox = $invtables[4];
';
$s = 'e';
$e = 's';
$wc = $Nb - 1;
// Preround: addRoundKey
$decrypt_block = '$in = unpack("N*", $in);'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
}
// Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
for ($round = 1; $round < $Nr; ++$round) {
list($s, $e) = array($e, $s);
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.=
'$'.$e.$i.' =
$dt0[($'.$s.$i .' >> 24) & 0xff] ^
$dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
$dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
$dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
'.$dw[++$wc].";\n";
}
}
// Finalround: subWord + shiftRows + addRoundKey
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.=
'$'.$e.$i.' =
$isbox[ $'.$e.$i.' & 0xff] |
($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
}
$decrypt_block .= '$in = pack("N*"'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.= ',
($'.$e.$i. ' & '.((int)0xFF000000).') ^
($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^
($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^
($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^
'.$dw[$i]."\n";
}
$decrypt_block .= ');';
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => '',
'init_encrypt' => $init_encrypt,
'init_decrypt' => $init_decrypt,
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php
/**
* Pure-PHP implementation of Triple DES.
*
* Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
*
* PHP versions 4 and 5
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/TripleDES.php';
*
* $des = new Crypt_TripleDES();
*
* $des->setKey('abcdefghijklmnopqrstuvwx');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $des->decrypt($des->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_TripleDES
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 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')) {
include_once 'DES.php';
}
/**#@+
* @access public
* @see self::Crypt_TripleDES()
*/
/**
* Encrypt / decrypt using inner chaining
*
* Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
*/
define('CRYPT_MODE_3CBC', -2);
/**
* BC version of the above.
*/
define('CRYPT_DES_MODE_3CBC', -2);
/**
* Encrypt / decrypt using outer chaining
*
* Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
*/
define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC);
/**
* BC version of the above.
*/
define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3);
/**#@-*/
/**
* Pure-PHP implementation of Triple DES.
*
* @package Crypt_TripleDES
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Crypt_TripleDES extends Crypt_DES
{
/**
* Key Length (in bytes)
*
* @see Crypt_TripleDES::setKeyLength()
* @var int
* @access private
*/
var $key_length = 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 int
* @access private
*/
var $cfb_init_len = 750;
/**
* max possible size of $key
*
* @see self::setKey()
* @see Crypt_DES::setKey()
* @var string
* @access private
*/
var $key_length_max = 24;
/**
* Internal flag whether using CRYPT_DES_MODE_3CBC or not
*
* @var bool
* @access private
*/
var $mode_3cbc;
/**
* The Crypt_DES objects
*
* Used only if $mode_3cbc === true
*
* @var array
* @access private
*/
var $des;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_DES_MODE_ECB
*
* - CRYPT_DES_MODE_CBC
*
* - CRYPT_DES_MODE_CTR
*
* - CRYPT_DES_MODE_CFB
*
* - CRYPT_DES_MODE_OFB
*
* - 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 int $mode
* @access public
*/
function __construct($mode = CRYPT_MODE_CBC)
{
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_MODE_CBC);
$this->mode_3cbc = true;
// This three $des'es will do the 3CBC work (if $key > 64bits)
$this->des = array(
new Crypt_DES(CRYPT_MODE_CBC),
new Crypt_DES(CRYPT_MODE_CBC),
new Crypt_DES(CRYPT_MODE_CBC),
);
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
$this->des[0]->disablePadding();
$this->des[1]->disablePadding();
$this->des[2]->disablePadding();
break;
// If not 3CBC, we init as usual
default:
parent::__construct($mode);
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param int $mode
* @access public
*/
function Crypt_TripleDES($mode = CRYPT_MODE_CBC)
{
$this->__construct($mode);
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ede3';
$mode = $this->_openssl_translate_mode();
$this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
}
return parent::isValidEngine($engine);
}
/**
* Sets the initialization vector. (optional)
*
* 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);
}
}
/**
* Sets the key length.
*
* Valid key lengths are 64, 128 and 192
*
* @see Crypt_Base:setKeyLength()
* @access public
* @param int $length
*/
function setKeyLength($length)
{
$length >>= 3;
switch (true) {
case $length <= 8:
$this->key_length = 8;
break;
case $length <= 16:
$this->key_length = 16;
break;
default:
$this->key_length = 24;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
*
* 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 null bytes.
*
* @access public
* @see Crypt_DES::setKey()
* @see Crypt_Base::setKey()
* @param string $key
*/
function setKey($key)
{
$length = $this->explicit_key_length ? $this->key_length : strlen($key);
if ($length > 8) {
$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));
}
parent::setKey($key);
// 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));
}
}
/**
* Encrypts a message.
*
* @see Crypt_Base::encrypt()
* @access public
* @param string $plaintext
* @return string $cipertext
*/
function encrypt($plaintext)
{
// parent::en/decrypt() is able to do all the work for all modes and keylengths,
// except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits
// if the key is smaller then 8, do what we'd normally do
if ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->des[2]->encrypt(
$this->des[1]->decrypt(
$this->des[0]->encrypt(
$this->_pad($plaintext)
)
)
);
}
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_3cbc && strlen($this->key) > 8) {
return $this->_unpad(
$this->des[0]->decrypt(
$this->des[1]->encrypt(
$this->des[2]->decrypt(
str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
)
)
)
);
}
return parent::decrypt($ciphertext);
}
/**
* 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 $des->encrypt(substr($plaintext, 0, 8));
* echo $des->encrypt(substr($plaintext, 8, 8));
* </code>
* <code>
* echo $des->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>
* $des->encrypt(substr($plaintext, 0, 8));
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
* </code>
* <code>
* echo $des->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_Base::enableContinuousBuffer()
* @see self::disableContinuousBuffer()
* @access public
*/
function enableContinuousBuffer()
{
parent::enableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->enableContinuousBuffer();
$this->des[1]->enableContinuousBuffer();
$this->des[2]->enableContinuousBuffer();
}
}
/**
* Treat consecutive packets as if they are a discontinuous buffer.
*
* The default behavior.
*
* @see Crypt_Base::disableContinuousBuffer()
* @see self::enableContinuousBuffer()
* @access public
*/
function disableContinuousBuffer()
{
parent::disableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->disableContinuousBuffer();
$this->des[1]->disableContinuousBuffer();
$this->des[2]->disableContinuousBuffer();
}
}
/**
* 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();
}
/**
* Sets the internal crypt engine
*
* @see Crypt_Base::Crypt_Base()
* @see Crypt_Base::setPreferredEngine()
* @param int $engine
* @access public
* @return int
*/
function setPreferredEngine($engine)
{
if ($this->mode_3cbc) {
$this->des[0]->setPreferredEngine($engine);
$this->des[1]->setPreferredEngine($engine);
$this->des[2]->setPreferredEngine($engine);
}
return parent::setPreferredEngine($engine);
}
}
<?php
/**
* Pure-PHP implementation of Twofish.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/Twofish.php';
*
* $twofish = new Crypt_Twofish();
*
* $twofish->setKey('12345678901234567890123456789012');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $twofish->decrypt($twofish->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_Twofish
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright 2007 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 public
* @see self::encrypt()
* @see self::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_TWOFISH_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_TWOFISH_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_TWOFISH_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_TWOFISH_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_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of Twofish.
*
* @package Crypt_Twofish
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @access public
*/
class Crypt_Twofish extends Crypt_Base
{
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'TWOFISH';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'twofish';
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 800;
/**
* Q-Table
*
* @var array
* @access private
*/
var $q0 = array(
0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
);
/**
* Q-Table
*
* @var array
* @access private
*/
var $q1 = array(
0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m0 = array(
0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m1 = array(
0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m2 = array(
0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m3 = array(
0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
);
/**
* The Key Schedule Array
*
* @var array
* @access private
*/
var $K = array();
/**
* The Key depended S-Table 0
*
* @var array
* @access private
*/
var $S0 = array();
/**
* The Key depended S-Table 1
*
* @var array
* @access private
*/
var $S1 = array();
/**
* The Key depended S-Table 2
*
* @var array
* @access private
*/
var $S2 = array();
/**
* The Key depended S-Table 3
*
* @var array
* @access private
*/
var $S3 = array();
/**
* Holds the last used key
*
* @var array
* @access private
*/
var $kl;
/**
* The Key Length (in bytes)
*
* @see Crypt_Twofish::setKeyLength()
* @var int
* @access private
*/
var $key_length = 16;
/**
* Sets the key length.
*
* Valid key lengths are 128, 192 or 256 bits
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 192:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}
parent::setKeyLength($length);
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key);
/* Key expanding and generating the key-depended s-boxes */
$le_longs = unpack('V*', $this->key);
$key = unpack('C*', $this->key);
$m0 = $this->m0;
$m1 = $this->m1;
$m2 = $this->m2;
$m3 = $this->m3;
$q0 = $this->q0;
$q1 = $this->q1;
$K = $S0 = $S1 = $S2 = $S3 = array();
switch (strlen($this->key)) {
case 16:
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
}
break;
case 24:
list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
}
break;
default: // 32
list($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
}
}
$this->K = $K;
$this->S0 = $S0;
$this->S1 = $S1;
$this->S2 = $S2;
$this->S3 = $S3;
}
/**
* _mdsrem function using by the twofish cipher algorithm
*
* @access private
* @param string $A
* @param string $B
* @return array
*/
function _mdsrem($A, $B)
{
// No gain by unrolling this loop.
for ($i = 0; $i < 8; ++$i) {
// Get most significant coefficient.
$t = 0xff & ($B >> 24);
// Shift the others up.
$B = ($B << 8) | (0xff & ($A >> 24));
$A<<= 8;
$u = $t << 1;
// Subtract the modular polynomial on overflow.
if ($t & 0x80) {
$u^= 0x14d;
}
// Remove t * (a * x^2 + 1).
$B ^= $t ^ ($u << 16);
// Form u = a*t + t/a = t*(a + 1/a).
$u^= 0x7fffffff & ($t >> 1);
// Add the modular polynomial on underflow.
if ($t & 0x01) {
$u^= 0xa6 ;
}
// Remove t * (a + 1/a) * (x^3 + x).
$B^= ($u << 24) | ($u << 8);
}
return array(
0xff & $B >> 24,
0xff & $B >> 16,
0xff & $B >> 8,
0xff & $B);
}
/**
* Encrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
$S0 = $this->S0;
$S1 = $this->S1;
$S2 = $this->S2;
$S3 = $this->S3;
$K = $this->K;
$in = unpack("V4", $in);
$R0 = $K[0] ^ $in[1];
$R1 = $K[1] ^ $in[2];
$R2 = $K[2] ^ $in[3];
$R3 = $K[3] ^ $in[4];
$ki = 7;
while ($ki < 39) {
$t0 = $S0[ $R0 & 0xff] ^
$S1[($R0 >> 8) & 0xff] ^
$S2[($R0 >> 16) & 0xff] ^
$S3[($R0 >> 24) & 0xff];
$t1 = $S0[($R1 >> 24) & 0xff] ^
$S1[ $R1 & 0xff] ^
$S2[($R1 >> 8) & 0xff] ^
$S3[($R1 >> 16) & 0xff];
$R2^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
$t0 = $S0[ $R2 & 0xff] ^
$S1[($R2 >> 8) & 0xff] ^
$S2[($R2 >> 16) & 0xff] ^
$S3[($R2 >> 24) & 0xff];
$t1 = $S0[($R3 >> 24) & 0xff] ^
$S1[ $R3 & 0xff] ^
$S2[($R3 >> 8) & 0xff] ^
$S3[($R3 >> 16) & 0xff];
$R0^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
}
// @codingStandardsIgnoreStart
return pack("V4", $K[4] ^ $R2,
$K[5] ^ $R3,
$K[6] ^ $R0,
$K[7] ^ $R1);
// @codingStandardsIgnoreEnd
}
/**
* Decrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
$S0 = $this->S0;
$S1 = $this->S1;
$S2 = $this->S2;
$S3 = $this->S3;
$K = $this->K;
$in = unpack("V4", $in);
$R0 = $K[4] ^ $in[1];
$R1 = $K[5] ^ $in[2];
$R2 = $K[6] ^ $in[3];
$R3 = $K[7] ^ $in[4];
$ki = 40;
while ($ki > 8) {
$t0 = $S0[$R0 & 0xff] ^
$S1[$R0 >> 8 & 0xff] ^
$S2[$R0 >> 16 & 0xff] ^
$S3[$R0 >> 24 & 0xff];
$t1 = $S0[$R1 >> 24 & 0xff] ^
$S1[$R1 & 0xff] ^
$S2[$R1 >> 8 & 0xff] ^
$S3[$R1 >> 16 & 0xff];
$R3^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
$t0 = $S0[$R2 & 0xff] ^
$S1[$R2 >> 8 & 0xff] ^
$S2[$R2 >> 16 & 0xff] ^
$S3[$R2 >> 24 & 0xff];
$t1 = $S0[$R3 >> 24 & 0xff] ^
$S1[$R3 & 0xff] ^
$S2[$R3 >> 8 & 0xff] ^
$S3[$R3 >> 16 & 0xff];
$R1^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
}
// @codingStandardsIgnoreStart
return pack("V4", $K[0] ^ $R2,
$K[1] ^ $R3,
$K[2] ^ $R0,
$K[3] ^ $R1);
// @codingStandardsIgnoreEnd
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
$lambda_functions =& Crypt_Twofish::_getLambdaFunctions();
// Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
// (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit)
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a unique hash for our generated code
$code_hash = "Crypt_Twofish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
$safeint = $this->safe_intval_inline();
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
$K = $this->K;
$init_crypt = '
static $S0, $S1, $S2, $S3;
if (!$S0) {
for ($i = 0; $i < 256; ++$i) {
$S0[] = (int)$self->S0[$i];
$S1[] = (int)$self->S1[$i];
$S2[] = (int)$self->S2[$i];
$S3[] = (int)$self->S3[$i];
}
}
';
break;
default:
$K = array();
for ($i = 0; $i < 40; ++$i) {
$K[] = '$K_' . $i;
}
$init_crypt = '
$S0 = $self->S0;
$S1 = $self->S1;
$S2 = $self->S2;
$S3 = $self->S3;
list(' . implode(',', $K) . ') = $self->K;
';
}
// Generating encrypt code:
$encrypt_block = '
$in = unpack("V4", $in);
$R0 = '.$K[0].' ^ $in[1];
$R1 = '.$K[1].' ^ $in[2];
$R2 = '.$K[2].' ^ $in[3];
$R3 = '.$K[3].' ^ $in[4];
';
for ($ki = 7, $i = 0; $i < 8; ++$i) {
$encrypt_block.= '
$t0 = $S0[ $R0 & 0xff] ^
$S1[($R0 >> 8) & 0xff] ^
$S2[($R0 >> 16) & 0xff] ^
$S3[($R0 >> 24) & 0xff];
$t1 = $S0[($R1 >> 24) & 0xff] ^
$S1[ $R1 & 0xff] ^
$S2[($R1 >> 8) & 0xff] ^
$S3[($R1 >> 16) & 0xff];
$R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
$t0 = $S0[ $R2 & 0xff] ^
$S1[($R2 >> 8) & 0xff] ^
$S2[($R2 >> 16) & 0xff] ^
$S3[($R2 >> 24) & 0xff];
$t1 = $S0[($R3 >> 24) & 0xff] ^
$S1[ $R3 & 0xff] ^
$S2[($R3 >> 8) & 0xff] ^
$S3[($R3 >> 16) & 0xff];
$R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
';
}
$encrypt_block.= '
$in = pack("V4", ' . $K[4] . ' ^ $R2,
' . $K[5] . ' ^ $R3,
' . $K[6] . ' ^ $R0,
' . $K[7] . ' ^ $R1);
';
// Generating decrypt code:
$decrypt_block = '
$in = unpack("V4", $in);
$R0 = '.$K[4].' ^ $in[1];
$R1 = '.$K[5].' ^ $in[2];
$R2 = '.$K[6].' ^ $in[3];
$R3 = '.$K[7].' ^ $in[4];
';
for ($ki = 40, $i = 0; $i < 8; ++$i) {
$decrypt_block.= '
$t0 = $S0[$R0 & 0xff] ^
$S1[$R0 >> 8 & 0xff] ^
$S2[$R0 >> 16 & 0xff] ^
$S3[$R0 >> 24 & 0xff];
$t1 = $S0[$R1 >> 24 & 0xff] ^
$S1[$R1 & 0xff] ^
$S2[$R1 >> 8 & 0xff] ^
$S3[$R1 >> 16 & 0xff];
$R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
$t0 = $S0[$R2 & 0xff] ^
$S1[$R2 >> 8 & 0xff] ^
$S2[$R2 >> 16 & 0xff] ^
$S3[$R2 >> 24 & 0xff];
$t1 = $S0[$R3 >> 24 & 0xff] ^
$S1[$R3 & 0xff] ^
$S2[$R3 >> 8 & 0xff] ^
$S3[$R3 >> 16 & 0xff];
$R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
';
}
$decrypt_block.= '
$in = pack("V4", ' . $K[0] . ' ^ $R2,
' . $K[1] . ' ^ $R3,
' . $K[2] . ' ^ $R0,
' . $K[3] . ' ^ $R1);
';
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => '',
'init_decrypt' => '',
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
<?php
include_once 'src/File/X509.php';
include_once 'src/Math/BigInteger.php';
include_once 'src/Crypt/RSA.php';
include_once 'src/Crypt/Hash.php';
class Demo
{
var $merchantCode="1902271423530473681";//商户应用号
var $version="2.0";//版本号
var $requestUrl="http://192.168.14.165:8080/service/soa";//请求地址
var $publicKeyPath="E:\\yunst2.0space\\yun-test\\src\\test\\resources\\TLCert-test.cer";//通联公钥地址
var $pfxPath="E:\\yunst2.0space\\yun-test\\src\\test\\resources\\1902271423530473681.pfx";
var $pwd="123456";
/**
*请求封装
* @param $service 服务名称
* @param $method 方法名称
* @param $param 其他的参数
* @return 返回类型
* @throws Exception
* @author trendpower
*/
private function request($service, $method, $param)
{
$ssoid = $this->merchantCode; //商户ID
if (empty($ssoid)) {
return null;
}
$request["service"] = $service;
$request["method"] = $method;
$request["param"] = $param;
$strRequest = json_encode($request);
$strRequest = str_replace("\r\n", "", $strRequest);
$req['req'] = $strRequest;
$req['sysid'] = $ssoid;
$timestamp = date("Y-m-d H:i:s", time());
$sign = $this->sign($ssoid, $strRequest, $timestamp);
$req['timestamp'] = $timestamp;
$req['sign'] = $sign;
$req['v'] = $this->version;
$serverAddress = $this->requestUrl;
$result = $this->requestYSTAPI($serverAddress, $req);
return $this->checkResult($result);
}
/**
*对数据进行加密
* @param $ssoid
* @param $strRequest
* @param $timestamp
* @return 返回类型
* @author trendpower
*/
private function sign($ssoid, $strRequest, $timestamp)
{
$dataStr = $ssoid . $strRequest . $timestamp;
$text = base64_encode(hash('md5', $dataStr, true));
$privateKey = $this->getPrivateKey();
openssl_sign($text, $sign, $privateKey);
openssl_free_key($privateKey);
$sign = base64_encode($sign);
return $sign;
}
/**
*请求云商通URL
* @param 参数1
* @param 参数2
* @return 返回类型
* @author trendpower
*/
private function requestYSTAPI($serverUrl, $args)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $serverUrl);
$sb = '';
$reqbody = array();
foreach ($args as $entry_key => $entry_value) {
$sb .= $entry_key . '=' . urlencode($entry_value) . '&';
}
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $sb);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-length', count($reqbody)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
*检查返回的结果是否合法;
* @param $result 需要检测的返回结果
* @return bool
* @throws Exception
*/
private function checkResult($result)
{
$arr = json_decode($result, true);
$sign = $arr['sign'];
$signedValue = $arr['signedValue'];
$success = false;
if ($sign != null) {
$success = $this->verify($signedValue, $sign);
}
if ($success) {
return $arr;
}
return $success;
}
/**
*验证的返回结果的合法性 2.0版本
* @param $signedValue 返回的数据
* @param $sign 返回的加密数据
* @return bool
*/
private function verify($signedValue, $sign)
{
$publicKey = $this->getTLPublicKey();
$rsa = new Crypt_RSA();
$rsa->loadKey($publicKey); // public key
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$signedValue = base64_encode(hash('md5', $signedValue, true));
$verifyResult = $rsa->verify($signedValue, base64_decode(trim($sign)));
return $verifyResult;
}
/**
*敏感数据加密 2.0版本
*@param $data 待加密数据
*@return $encrypted 加密后数据
*/
function encrypt($data){
$publicKey = $this->getTLPublicKey();
openssl_public_encrypt($data, $encrypted, $publicKey);
$encrypted = strtoupper(bin2hex($encrypted));
return $encrypted;
}
/**
*敏感数据解密 2.0版本
*$data 待解密数据
*@return $decrypted 解密后数据
*/
function decrypt($data){
$privateKey = $this->getPrivateKey();
$data = hex2bin($data);
openssl_private_decrypt($data, $decrypted, $privateKey);
return $decrypted;
}
/**
*获取公匙的绝对路径
* @param 参数1
* @param 参数2
* @return 返回类型
* @author trendpower
*/
public function getPublicKeyPath()
{
return $this->publicKeyPath;
}
/**
*获取通联公钥
*
* @return 返回类型
* @author trendpower
*/
public function getTLPublicKey(){
$certfile = file_get_contents($this->getPublicKeyPath());
if (!$certfile) {
return null;
}
$x509 = new File_X509();
$cert = $x509->loadX509($certfile);
$publicKey = $x509->getPublicKey();
return $publicKey;
}
/**
*获取私匙
* @return 私钥
*/
public function getPrivateKey()
{
return $this->loadPrivateKeyByPfx($this->pfxPath,$this->pwd);
}
/**
* 从证书文件中装入私钥 Pfx 文件格式
* @param path 证书路径
* @param password 证书密码
* @return 私钥
* @throws Exception
*/
private function loadPrivateKeyByPfx($path, $pwd)
{
if (file_exists($path)) {
$priKey = file_get_contents($path);
if (openssl_pkcs12_read($priKey, $certs, $pwd)) {
$privateKey = $certs['pkey'];
return $privateKey;
}
die("私钥文件格式错误");
}
die('私钥文件不存在');
}
}
<?php
/**
* Pure-PHP ANSI Decoder
*
* PHP versions 4 and 5
*
* If you call read() in Net_SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
* They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a
* {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
* color to display them in, etc. File_ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
*
* 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 File
* @package File_ANSI
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Pure-PHP ANSI Decoder
*
* @package File_ANSI
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class File_ANSI
{
/**
* Max Width
*
* @var int
* @access private
*/
var $max_x;
/**
* Max Height
*
* @var int
* @access private
*/
var $max_y;
/**
* Max History
*
* @var int
* @access private
*/
var $max_history;
/**
* History
*
* @var array
* @access private
*/
var $history;
/**
* History Attributes
*
* @var array
* @access private
*/
var $history_attrs;
/**
* Current Column
*
* @var int
* @access private
*/
var $x;
/**
* Current Row
*
* @var int
* @access private
*/
var $y;
/**
* Old Column
*
* @var int
* @access private
*/
var $old_x;
/**
* Old Row
*
* @var int
* @access private
*/
var $old_y;
/**
* An empty attribute cell
*
* @var object
* @access private
*/
var $base_attr_cell;
/**
* The current attribute cell
*
* @var object
* @access private
*/
var $attr_cell;
/**
* An empty attribute row
*
* @var array
* @access private
*/
var $attr_row;
/**
* The current screen text
*
* @var array
* @access private
*/
var $screen;
/**
* The current screen attributes
*
* @var array
* @access private
*/
var $attrs;
/**
* Current ANSI code
*
* @var string
* @access private
*/
var $ansi;
/**
* Tokenization
*
* @var array
* @access private
*/
var $tokenization;
/**
* Default Constructor.
*
* @return File_ANSI
* @access public
*/
function __construct()
{
$attr_cell = new stdClass();
$attr_cell->bold = false;
$attr_cell->underline = false;
$attr_cell->blink = false;
$attr_cell->background = 'black';
$attr_cell->foreground = 'white';
$attr_cell->reverse = false;
$this->base_attr_cell = clone($attr_cell);
$this->attr_cell = clone($attr_cell);
$this->setHistory(200);
$this->setDimensions(80, 24);
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function File_ANSI()
{
$this->__construct($mode);
}
/**
* Set terminal width and height
*
* Resets the screen as well
*
* @param int $x
* @param int $y
* @access public
*/
function setDimensions($x, $y)
{
$this->max_x = $x - 1;
$this->max_y = $y - 1;
$this->x = $this->y = 0;
$this->history = $this->history_attrs = array();
$this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
$this->screen = array_fill(0, $this->max_y + 1, '');
$this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
$this->ansi = '';
}
/**
* Set the number of lines that should be logged past the terminal height
*
* @param int $x
* @param int $y
* @access public
*/
function setHistory($history)
{
$this->max_history = $history;
}
/**
* Load a string
*
* @param string $source
* @access public
*/
function loadString($source)
{
$this->setDimensions($this->max_x + 1, $this->max_y + 1);
$this->appendString($source);
}
/**
* Appdend a string
*
* @param string $source
* @access public
*/
function appendString($source)
{
$this->tokenization = array('');
for ($i = 0; $i < strlen($source); $i++) {
if (strlen($this->ansi)) {
$this->ansi.= $source[$i];
$chr = ord($source[$i]);
// http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
// single character CSI's not currently supported
switch (true) {
case $this->ansi == "\x1B=":
$this->ansi = '';
continue 2;
case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
break;
default:
continue 2;
}
$this->tokenization[] = $this->ansi;
$this->tokenization[] = '';
// http://ascii-table.com/ansi-escape-sequences-vt-100.php
switch ($this->ansi) {
case "\x1B[H": // Move cursor to upper left corner
$this->old_x = $this->x;
$this->old_y = $this->y;
$this->x = $this->y = 0;
break;
case "\x1B[J": // Clear screen from cursor down
$this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
$this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
$this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
$this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
if (count($this->history) == $this->max_history) {
array_shift($this->history);
array_shift($this->history_attrs);
}
case "\x1B[K": // Clear screen from cursor right
$this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
break;
case "\x1B[2K": // Clear entire line
$this->screen[$this->y] = str_repeat(' ', $this->x);
$this->attrs[$this->y] = $this->attr_row;
break;
case "\x1B[?1h": // set cursor key to application
case "\x1B[?25h": // show the cursor
case "\x1B(B": // set united states g0 character set
break;
case "\x1BE": // Move to next line
$this->_newLine();
$this->x = 0;
break;
default:
switch (true) {
case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
$this->old_y = $this->y;
$this->y+= $match[1];
break;
case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
$this->old_x = $this->x;
$this->old_y = $this->y;
$this->x = $match[2] - 1;
$this->y = $match[1] - 1;
break;
case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
$this->old_x = $this->x;
$this->x+= $match[1];
break;
case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
$this->old_x = $this->x;
$this->x-= $match[1];
if ($this->x < 0) {
$this->x = 0;
}
break;
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
break;
case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
$attr_cell = &$this->attr_cell;
$mods = explode(';', $match[1]);
foreach ($mods as $mod) {
switch ($mod) {
case 0: // Turn off character attributes
$attr_cell = clone($this->base_attr_cell);
break;
case 1: // Turn bold mode on
$attr_cell->bold = true;
break;
case 4: // Turn underline mode on
$attr_cell->underline = true;
break;
case 5: // Turn blinking mode on
$attr_cell->blink = true;
break;
case 7: // Turn reverse video on
$attr_cell->reverse = !$attr_cell->reverse;
$temp = $attr_cell->background;
$attr_cell->background = $attr_cell->foreground;
$attr_cell->foreground = $temp;
break;
default: // set colors
//$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
$front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
//$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
$back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
switch ($mod) {
// @codingStandardsIgnoreStart
case 30: $front = 'black'; break;
case 31: $front = 'red'; break;
case 32: $front = 'green'; break;
case 33: $front = 'yellow'; break;
case 34: $front = 'blue'; break;
case 35: $front = 'magenta'; break;
case 36: $front = 'cyan'; break;
case 37: $front = 'white'; break;
case 40: $back = 'black'; break;
case 41: $back = 'red'; break;
case 42: $back = 'green'; break;
case 43: $back = 'yellow'; break;
case 44: $back = 'blue'; break;
case 45: $back = 'magenta'; break;
case 46: $back = 'cyan'; break;
case 47: $back = 'white'; break;
// @codingStandardsIgnoreEnd
default:
//user_error('Unsupported attribute: ' . $mod);
$this->ansi = '';
break 2;
}
}
}
break;
default:
//user_error("{$this->ansi} is unsupported\r\n");
}
}
$this->ansi = '';
continue;
}
$this->tokenization[count($this->tokenization) - 1].= $source[$i];
switch ($source[$i]) {
case "\r":
$this->x = 0;
break;
case "\n":
$this->_newLine();
break;
case "\x08": // backspace
if ($this->x) {
$this->x--;
$this->attrs[$this->y][$this->x] = clone($this->base_attr_cell);
$this->screen[$this->y] = substr_replace(
$this->screen[$this->y],
$source[$i],
$this->x,
1
);
}
break;
case "\x0F": // shift
break;
case "\x1B": // start ANSI escape code
$this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
//if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
// array_pop($this->tokenization);
//}
$this->ansi.= "\x1B";
break;
default:
$this->attrs[$this->y][$this->x] = clone($this->attr_cell);
if ($this->x > strlen($this->screen[$this->y])) {
$this->screen[$this->y] = str_repeat(' ', $this->x);
}
$this->screen[$this->y] = substr_replace(
$this->screen[$this->y],
$source[$i],
$this->x,
1
);
if ($this->x > $this->max_x) {
$this->x = 0;
$this->_newLine();
} else {
$this->x++;
}
}
}
}
/**
* Add a new line
*
* Also update the $this->screen and $this->history buffers
*
* @access private
*/
function _newLine()
{
//if ($this->y < $this->max_y) {
// $this->y++;
//}
while ($this->y >= $this->max_y) {
$this->history = array_merge($this->history, array(array_shift($this->screen)));
$this->screen[] = '';
$this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
$this->attrs[] = $this->attr_row;
if (count($this->history) >= $this->max_history) {
array_shift($this->history);
array_shift($this->history_attrs);
}
$this->y--;
}
$this->y++;
}
/**
* Returns the current coordinate without preformating
*
* @access private
* @return string
*/
function _processCoordinate($last_attr, $cur_attr, $char)
{
$output = '';
if ($last_attr != $cur_attr) {
$close = $open = '';
if ($last_attr->foreground != $cur_attr->foreground) {
if ($cur_attr->foreground != 'white') {
$open.= '<span style="color: ' . $cur_attr->foreground . '">';
}
if ($last_attr->foreground != 'white') {
$close = '</span>' . $close;
}
}
if ($last_attr->background != $cur_attr->background) {
if ($cur_attr->background != 'black') {
$open.= '<span style="background: ' . $cur_attr->background . '">';
}
if ($last_attr->background != 'black') {
$close = '</span>' . $close;
}
}
if ($last_attr->bold != $cur_attr->bold) {
if ($cur_attr->bold) {
$open.= '<b>';
} else {
$close = '</b>' . $close;
}
}
if ($last_attr->underline != $cur_attr->underline) {
if ($cur_attr->underline) {
$open.= '<u>';
} else {
$close = '</u>' . $close;
}
}
if ($last_attr->blink != $cur_attr->blink) {
if ($cur_attr->blink) {
$open.= '<blink>';
} else {
$close = '</blink>' . $close;
}
}
$output.= $close . $open;
}
$output.= htmlspecialchars($char);
return $output;
}
/**
* Returns the current screen without preformating
*
* @access private
* @return string
*/
function _getScreen()
{
$output = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i <= $this->max_y; $i++) {
for ($j = 0; $j <= $this->max_x; $j++) {
$cur_attr = $this->attrs[$i][$j];
$output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
$last_attr = $this->attrs[$i][$j];
}
$output.= "\r\n";
}
$output = substr($output, 0, -2);
// close any remaining open tags
$output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
return rtrim($output);
}
/**
* Returns the current screen
*
* @access public
* @return string
*/
function getScreen()
{
return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->_getScreen() . '</pre>';
}
/**
* Returns the current screen and the x previous lines
*
* @access public
* @return string
*/
function getHistory()
{
$scrollback = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i < count($this->history); $i++) {
for ($j = 0; $j <= $this->max_x + 1; $j++) {
$cur_attr = $this->history_attrs[$i][$j];
$scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
$last_attr = $this->history_attrs[$i][$j];
}
$scrollback.= "\r\n";
}
$base_attr_cell = $this->base_attr_cell;
$this->base_attr_cell = $last_attr;
$scrollback.= $this->_getScreen();
$this->base_attr_cell = $base_attr_cell;
return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
}
}
<?php
/**
* Pure-PHP ASN.1 Parser
*
* PHP versions 4 and 5
*
* ASN.1 provides the semantics for data encoded using various schemes. The most commonly
* utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
* DER blobs.
*
* File_ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
*
* Uses the 1988 ASN.1 syntax.
*
* 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 File
* @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* Tag Classes
*
* @access private
* @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
*/
define('FILE_ASN1_CLASS_UNIVERSAL', 0);
define('FILE_ASN1_CLASS_APPLICATION', 1);
define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
define('FILE_ASN1_CLASS_PRIVATE', 3);
/**#@-*/
/**#@+
* Tag Classes
*
* @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
/**#@-*/
/**#@+
* More Tag Classes
*
* @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);
/**#@-*/
/**#@+
* Tag Aliases
*
* These tags are kinda place holders for other tags.
*
* @access private
*/
define('FILE_ASN1_TYPE_CHOICE', -1);
define('FILE_ASN1_TYPE_ANY', -2);
/**#@-*/
/**
* ASN.1 Element
*
* Bypass normal encoding rules in File_ASN1::encodeDER()
*
* @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class File_ASN1_Element
{
/**
* Raw element value
*
* @var string
* @access private
*/
var $element;
/**
* Constructor
*
* @param string $encoded
* @return File_ASN1_Element
* @access public
*/
function __construct($encoded)
{
$this->element = $encoded;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param int $mode
* @access public
*/
function File_ASN1_Element($encoded)
{
$this->__construct($encoded);
}
}
/**
* Pure-PHP ASN.1 Parser
*
* @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class File_ASN1
{
/**
* ASN.1 object identifier
*
* @var array
* @access private
* @link http://en.wikipedia.org/wiki/Object_identifier
*/
var $oids = array();
/**
* Default date format
*
* @var string
* @access private
* @link http://php.net/class.datetime
*/
var $format = 'D, d M Y H:i:s O';
/**
* Default date format
*
* @var array
* @access private
* @see self::setTimeFormat()
* @see self::asn1map()
* @link http://php.net/class.datetime
*/
var $encoded;
/**
* Filters
*
* If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
*
* @var array
* @access private
* @see self::_encode_der()
*/
var $filters;
/**
* Type mapping table for the ANY type.
*
* Structured or unknown types are mapped to a FILE_ASN1_Element.
* Unambiguous types get the direct mapping (int/real/bool).
* Others are mapped as a choice, with an extra indexing level.
*
* @var array
* @access public
*/
var $ANYmap = array(
FILE_ASN1_TYPE_BOOLEAN => true,
FILE_ASN1_TYPE_INTEGER => true,
FILE_ASN1_TYPE_BIT_STRING => 'bitString',
FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
FILE_ASN1_TYPE_NULL => 'null',
FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
FILE_ASN1_TYPE_REAL => true,
FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
//FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
);
/**
* String type to character size mapping table.
*
* Non-convertable types are absent from this table.
* size == 0 indicates variable length encoding.
*
* @var array
* @access public
*/
var $stringTypeSize = array(
FILE_ASN1_TYPE_UTF8_STRING => 0,
FILE_ASN1_TYPE_BMP_STRING => 2,
FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
FILE_ASN1_TYPE_TELETEX_STRING => 1,
FILE_ASN1_TYPE_IA5_STRING => 1,
FILE_ASN1_TYPE_VISIBLE_STRING => 1,
);
/**
* Default Constructor.
*
* @access public
*/
function __construct()
{
static $static_init = null;
if (!$static_init) {
$static_init = true;
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function File_ASN1()
{
$this->__construct($mode);
}
/**
* Parse BER-encoding
*
* Serves a similar purpose to openssl's asn1parse
*
* @param string $encoded
* @return array
* @access public
*/
function decodeBER($encoded)
{
if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
$encoded = $encoded->element;
}
$this->encoded = $encoded;
// encapsulate in an array for BC with the old decodeBER
return array($this->_decode_ber($encoded));
}
/**
* Parse BER-encoding (Helper function)
*
* Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
* $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
* FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
*
* @param string $encoded
* @param int $start
* @param int $encoded_pos
* @return array
* @access private
*/
function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
{
$current = array('start' => $start);
$type = ord($encoded[$encoded_pos++]);
$start++;
$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($encoded[$encoded_pos++]) & 0x7F;
$start++;
} while ($loop);
}
// Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
$length = ord($encoded[$encoded_pos++]);
$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) - $encoded_pos;
} 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 = substr($encoded, $encoded_pos, $length);
$encoded_pos += $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);
}
if ($length > (strlen($encoded) - $encoded_pos)) {
return false;
}
$content = substr($encoded, $encoded_pos, $length);
$content_pos = 0;
// at this point $length can be overwritten. it's only accurate for definite length things as is
/* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
built-in types. It defines an application-independent data type that must be distinguishable from all other
data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
data type; the term CONTEXT-SPECIFIC does not appear.
-- http://www.obj-sys.com/asn1tutorial/node12.html */
$class = ($type >> 6) & 3;
switch ($class) {
case FILE_ASN1_CLASS_APPLICATION:
case FILE_ASN1_CLASS_PRIVATE:
case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
if (!$constructed) {
return array(
'type' => $class,
'constant' => $tag,
'content' => $content,
'length' => $length + $start - $current['start']
);
}
$newcontent = array();
$remainingLength = $length;
while ($remainingLength > 0) {
$temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
break;
}
$length = $temp['length'];
// end-of-content octets - see paragraph 8.1.5
if (substr($content, $content_pos + $length, 2) == "\0\0") {
$length+= 2;
$start+= $length;
$newcontent[] = $temp;
break;
}
$start+= $length;
$remainingLength-= $length;
$newcontent[] = $temp;
$content_pos += $length;
}
return array(
'type' => $class,
'constant' => $tag,
// the array encapsulation is for BC with the old format
'content' => $newcontent,
// the only time when $content['headerlength'] isn't defined is when the length is indefinite.
// the absence of $content['headerlength'] is how we know if something is indefinite or not.
// technically, it could be defined to be 2 and then another indicator could be used but whatever.
'length' => $start - $current['start']
) + $current;
}
$current+= array('type' => $tag);
// decode UNIVERSAL tags
switch ($tag) {
case FILE_ASN1_TYPE_BOOLEAN:
// "The contents octets shall consist of a single octet." -- paragraph 8.2.1
//if (strlen($content) != 1) {
// return false;
//}
$current['content'] = (bool) ord($content[$content_pos]);
break;
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
$current['content'] = new Math_BigInteger(substr($content, $content_pos), -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'] = substr($content, $content_pos);
} else {
$temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
return false;
}
$length-= (strlen($content) - $content_pos);
$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'] = substr($content, $content_pos);
} else {
$current['content'] = '';
$length = 0;
while (substr($content, $content_pos, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $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, $content_pos, 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();
$content_len = strlen($content);
while ($content_pos < $content_len) {
// 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, $content_pos, 2) == "\0\0") {
$length = $offset + 2; // +2 for the EOC
break 2;
}
$temp = $this->_decode_ber($content, $start + $offset, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $temp['length'];
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
$temp = ord($content[$content_pos++]);
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
$valuen = 0;
// process septets
$content_len = strlen($content);
while ($content_pos < $content_len) {
$temp = ord($content[$content_pos++]);
$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'] = substr($content, $content_pos);
break;
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
$current['content'] = class_exists('DateTime') ?
$this->_decodeDateTime(substr($content, $content_pos), $tag) :
$this->_decodeUnixTime(substr($content, $content_pos), $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 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, $special = array())
{
if (isset($mapping['explicit']) && is_array($decoded['content'])) {
$decoded = $decoded['content'][0];
}
switch (true) {
case $mapping['type'] == FILE_ASN1_TYPE_ANY:
$intype = $decoded['type'];
if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
}
$inmap = $this->ANYmap[$intype];
if (is_string($inmap)) {
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
}
break;
case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
foreach ($mapping['children'] as $key => $option) {
switch (true) {
case isset($option['constant']) && $option['constant'] == $decoded['constant']:
case !isset($option['constant']) && $option['type'] == $decoded['type']:
$value = $this->asn1map($decoded, $option, $special);
break;
case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
$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;
case isset($mapping['implicit']):
case isset($mapping['explicit']):
case $decoded['type'] == $mapping['type']:
break;
default:
// 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'])) {
$decoded['type'] = $mapping['type'];
}
switch ($decoded['type']) {
case FILE_ASN1_TYPE_SEQUENCE:
$map = array();
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children'];
foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
return null;
}
}
return $map;
}
$n = count($decoded['content']);
$i = 0;
foreach ($mapping['children'] as $key => $child) {
$maymatch = $i < $n; // Match only existing input.
if ($maymatch) {
$temp = $decoded['content'][$i];
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
// Get the mapping and input class & constant.
$childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
$constant = null;
if (isset($temp['constant'])) {
$tempClass = $temp['type'];
}
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}
if (isset($constant) && isset($temp['constant'])) {
// Can only match if constants and class match.
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {
// Can only match if no constant expected and type matches or is generic.
$maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
}
}
}
if ($maymatch) {
// Attempt submapping.
$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.
}
}
// Fail mapping if all input items have not been consumed.
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:
$map = array();
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children'];
foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
return null;
}
}
return $map;
}
for ($i = 0; $i < count($decoded['content']); $i++) {
$temp = $decoded['content'][$i];
$tempClass = FILE_ASN1_CLASS_UNIVERSAL;
if (isset($temp['constant'])) {
$tempClass = $temp['type'];
}
foreach ($mapping['children'] as $key => $child) {
if (isset($map[$key])) {
continue;
}
$maymatch = true;
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
$childClass = FILE_ASN1_CLASS_UNIVERSAL;
$constant = null;
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}
if (isset($constant) && isset($temp['constant'])) {
// Can only match if constants and class match.
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {
// Can only match if no constant expected and type matches or is generic.
$maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
}
}
if ($maymatch) {
// Attempt submapping.
$candidate = $this->asn1map($temp, $child, $special);
$maymatch = $candidate !== null;
}
if (!$maymatch) {
break;
}
// Got the match: use it.
if (isset($special[$key])) {
$candidate = call_user_func($special[$key], $candidate);
}
$map[$key] = $candidate;
break;
}
}
foreach ($mapping['children'] as $key => $child) {
if (!isset($map[$key])) {
if (isset($child['default'])) {
$map[$key] = $child['default'];
} elseif (!isset($child['optional'])) {
return null;
}
}
}
return $map;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
if (class_exists('DateTime')) {
if (isset($mapping['implicit'])) {
$decoded['content'] = $this->_decodeDateTime($decoded['content'], $decoded['type']);
}
if (!$decoded['content']) {
return false;
}
return $decoded['content']->format($this->format);
} else {
if (isset($mapping['implicit'])) {
$decoded['content'] = $this->_decodeUnixTime($decoded['content'], $decoded['type']);
}
return @date($this->format, $decoded['content']);
}
case FILE_ASN1_TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$offset = ord($decoded['content'][0]);
$size = (strlen($decoded['content']) - 1) * 8 - $offset;
/*
From X.680-0207.pdf#page=46 (21.7):
"When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
0 bits."
*/
$bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
$current = ord($decoded['content'][$i]);
for ($j = $offset; $j < 8; $j++) {
$bits[] = (bool) ($current & (1 << $j));
}
$offset = 0;
}
$values = array();
$map = array_reverse($mapping['mapping']);
foreach ($map as $i => $value) {
if ($bits[$i]) {
$values[] = $value;
}
}
return $values;
}
case FILE_ASN1_TYPE_OCTET_STRING:
return base64_encode($decoded['content']);
case FILE_ASN1_TYPE_NULL:
return '';
case FILE_ASN1_TYPE_BOOLEAN:
return $decoded['content'];
case FILE_ASN1_TYPE_NUMERIC_STRING:
case FILE_ASN1_TYPE_PRINTABLE_STRING:
case FILE_ASN1_TYPE_TELETEX_STRING:
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
case FILE_ASN1_TYPE_IA5_STRING:
case FILE_ASN1_TYPE_GRAPHIC_STRING:
case FILE_ASN1_TYPE_VISIBLE_STRING:
case FILE_ASN1_TYPE_GENERAL_STRING:
case FILE_ASN1_TYPE_UNIVERSAL_STRING:
case FILE_ASN1_TYPE_UTF8_STRING:
case FILE_ASN1_TYPE_BMP_STRING:
return $decoded['content'];
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
$temp = $decoded['content'];
if (isset($mapping['implicit'])) {
$temp = new Math_BigInteger($decoded['content'], -256);
}
if (isset($mapping['mapping'])) {
$temp = (int) $temp->toString();
return isset($mapping['mapping'][$temp]) ?
$mapping['mapping'][$temp] :
false;
}
return $temp;
}
}
/**
* ASN.1 Encode
*
* 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 int $idx
* @return string
* @access public
*/
function encodeDER($source, $mapping, $special = array())
{
$this->location = array();
return $this->_encode_der($source, $mapping, null, $special);
}
/**
* ASN.1 Encode (Helper function)
*
* @param string $source
* @param string $mapping
* @param int $idx
* @return string
* @access private
*/
function _encode_der($source, $mapping, $idx = null, $special = array())
{
if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
return $source->element;
}
// do not encode (implicitly optional) fields with value set to default
if (isset($mapping['default']) && $source === $mapping['default']) {
return '';
}
if (isset($idx)) {
if (isset($special[$idx])) {
$source = call_user_func($special[$idx], $source);
}
$this->location[] = $idx;
}
$tag = $mapping['type'];
switch ($tag) {
case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
case FILE_ASN1_TYPE_SEQUENCE:
$tag|= 0x20; // set the constructed bit
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
$value = array();
$child = $mapping['children'];
foreach ($source as $content) {
$temp = $this->_encode_der($content, $child, null, $special);
if ($temp === false) {
return false;
}
$value[]= $temp;
}
/* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
as octet strings with the shorter components being padded at their trailing end with 0-octets.
NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
-- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
if ($mapping['type'] == FILE_ASN1_TYPE_SET) {
sort($value);
}
$value = implode($value, '');
break;
}
$value = '';
foreach ($mapping['children'] as $key => $child) {
if (!array_key_exists($key, $source)) {
if (!isset($child['optional'])) {
return false;
}
continue;
}
$temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) {
return false;
}
// An empty child encoding means it has been optimized out.
// Else we should have at least one tag byte.
if ($temp === '') {
continue;
}
// if isset($child['constant']) is true then isset($child['optional']) should be true as well
if (isset($child['constant'])) {
/*
From X.680-0207.pdf#page=58 (30.6):
"The tagging construction specifies explicit tagging if any of the following holds:
...
c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
*/
if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
$value.= $temp;
}
break;
case FILE_ASN1_TYPE_CHOICE:
$temp = false;
foreach ($mapping['children'] as $key => $child) {
if (!isset($source[$key])) {
continue;
}
$temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) {
return false;
}
// An empty child encoding means it has been optimized out.
// Else we should have at least one tag byte.
if ($temp === '') {
continue;
}
$tag = ord($temp[0]);
// if isset($child['constant']) is true then isset($child['optional']) should be true as well
if (isset($child['constant'])) {
if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
}
if (isset($idx)) {
array_pop($this->location);
}
if ($temp && isset($mapping['cast'])) {
$temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
}
return $temp;
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']);
if ($value === false) {
return false;
}
$value = new Math_BigInteger($value);
$value = $value->toBytes(true);
}
if (!strlen($value)) {
$value = chr(0);
}
break;
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
$format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
$format.= 'mdHis';
if (!class_exists('DateTime')) {
$value = @gmdate($format, strtotime($source)) . 'Z';
} else {
$date = new DateTime($source, new DateTimeZone('GMT'));
$value = $date->format($format) . 'Z';
}
break;
case FILE_ASN1_TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$bits = array_fill(0, count($mapping['mapping']), 0);
$size = 0;
for ($i = 0; $i < count($mapping['mapping']); $i++) {
if (in_array($mapping['mapping'][$i], $source)) {
$bits[$i] = 1;
$size = $i;
}
}
if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
$size = $mapping['min'] - 1;
}
$offset = 8 - (($size + 1) & 7);
$offset = $offset !== 8 ? $offset : 0;
$value = chr($offset);
for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
unset($bits[$i]);
}
$bits = implode('', array_pad($bits, $size + $offset + 1, 0));
$bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
foreach ($bytes as $byte) {
$value.= chr(bindec($byte));
}
break;
}
case FILE_ASN1_TYPE_OCTET_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.
-- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
$value = base64_decode($source);
break;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
if ($oid === false) {
user_error('Invalid OID');
return false;
}
$value = '';
$parts = explode('.', $oid);
$value = chr(40 * $parts[0] + $parts[1]);
for ($i = 2; $i < count($parts); $i++) {
$temp = '';
if (!$parts[$i]) {
$temp = "\0";
} else {
while ($parts[$i]) {
$temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
$parts[$i] >>= 7;
}
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
}
$value.= $temp;
}
break;
case FILE_ASN1_TYPE_ANY:
$loc = $this->location;
if (isset($idx)) {
array_pop($this->location);
}
switch (true) {
case !isset($source):
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, null, $special);
case is_float($source):
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, 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, null, $special);
}
}
$filters = $this->filters;
foreach ($loc as $part) {
if (!isset($filters[$part])) {
$filters = false;
break;
}
$filters = $filters[$part];
}
if ($filters === false) {
user_error('No filters defined for ' . implode('/', $loc));
return false;
}
return $this->_encode_der($source, $filters + $mapping, null, $special);
case FILE_ASN1_TYPE_NULL:
$value = '';
break;
case FILE_ASN1_TYPE_NUMERIC_STRING:
case FILE_ASN1_TYPE_TELETEX_STRING:
case FILE_ASN1_TYPE_PRINTABLE_STRING:
case FILE_ASN1_TYPE_UNIVERSAL_STRING:
case FILE_ASN1_TYPE_UTF8_STRING:
case FILE_ASN1_TYPE_BMP_STRING:
case FILE_ASN1_TYPE_IA5_STRING:
case FILE_ASN1_TYPE_VISIBLE_STRING:
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
case FILE_ASN1_TYPE_GRAPHIC_STRING:
case FILE_ASN1_TYPE_GENERAL_STRING:
$value = $source;
break;
case FILE_ASN1_TYPE_BOOLEAN:
$value = $source ? "\xFF" : "\x00";
break;
default:
user_error('Mapping provides no type definition for ' . implode('/', $this->location));
return false;
}
if (isset($idx)) {
array_pop($this->location);
}
if (isset($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;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @access private
* @param int $length
* @return string
*/
function _encodeLength($length)
{
if ($length <= 0x7F) {
return chr($length);
}
$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
/**
* BER-decode the time (using UNIX time)
*
* Called by _decode_ber() and in the case of implicit tags asn1map().
*
* @access private
* @param string $content
* @param int $tag
* @return string
*/
function _decodeUnixTime($content, $tag)
{
/* UTCTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
http://www.obj-sys.com/asn1tutorial/node15.html
GeneralizedTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
http://www.obj-sys.com/asn1tutorial/node14.html */
$pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
'#^(..)(..)(..)(..)(..)(..)?(.*)$#' :
'#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
preg_match($pattern, $content, $matches);
list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
$year = $year >= 50 ? "19$year" : "20$year";
}
if ($timezone == 'Z') {
$mktime = 'gmmktime';
$timezone = 0;
} elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
$mktime = 'gmmktime';
$timezone = 60 * $matches[3] + 3600 * $matches[2];
if ($matches[1] == '-') {
$timezone = -$timezone;
}
} else {
$mktime = 'mktime';
$timezone = 0;
}
return @$mktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year) + $timezone;
}
/**
* BER-decode the time (using DateTime)
*
* Called by _decode_ber() and in the case of implicit tags asn1map().
*
* @access private
* @param string $content
* @param int $tag
* @return string
*/
function _decodeDateTime($content, $tag)
{
/* UTCTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
http://www.obj-sys.com/asn1tutorial/node15.html
GeneralizedTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
http://www.obj-sys.com/asn1tutorial/node14.html */
$format = 'YmdHis';
if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
// https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
// element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
// browsers parse it phpseclib ought to too
if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
$content = $matches[1] . '00' . $matches[2];
}
$prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
$content = $prefix . $content;
} elseif (strpos($content, '.') !== false) {
$format.= '.u';
}
if ($content[strlen($content) - 1] == 'Z') {
$content = substr($content, 0, -1) . '+0000';
}
if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
$format.= 'O';
}
// error supression isn't necessary as of PHP 7.0:
// http://php.net/manual/en/migration70.other-changes.php
return @DateTime::createFromFormat($format, $content);
}
/**
* Set the time format
*
* Sets the time / date format for asn1map().
*
* @access public
* @param string $format
*/
function setTimeFormat($format)
{
$this->format = $format;
}
/**
* Load OIDs
*
* Load the relevant OIDs for a particular ASN.1 semantic mapping.
*
* @access public
* @param array $oids
*/
function loadOIDs($oids)
{
$this->oids = $oids;
}
/**
* Load filters
*
* See File_X509, etc, for an example.
*
* @access public
* @param array $filters
*/
function loadFilters($filters)
{
$this->filters = $filters;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* String type conversion
*
* This is a lazy conversion, dealing only with character size.
* No real conversion table is used.
*
* @param string $in
* @param int $from
* @param int $to
* @return string
* @access public
*/
function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
{
if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
return false;
}
$insize = $this->stringTypeSize[$from];
$outsize = $this->stringTypeSize[$to];
$inlength = strlen($in);
$out = '';
for ($i = 0; $i < $inlength;) {
if ($inlength - $i < $insize) {
return false;
}
// Get an input character as a 32-bit value.
$c = ord($in[$i++]);
switch (true) {
case $insize == 4:
$c = ($c << 8) | ord($in[$i++]);
$c = ($c << 8) | ord($in[$i++]);
case $insize == 2:
$c = ($c << 8) | ord($in[$i++]);
case $insize == 1:
break;
case ($c & 0x80) == 0x00:
break;
case ($c & 0x40) == 0x00:
return false;
default:
$bit = 6;
do {
if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
return false;
}
$c = ($c << 6) | (ord($in[$i++]) & 0x3F);
$bit += 5;
$mask = 1 << $bit;
} while ($c & $bit);
$c &= $mask - 1;
break;
}
// Convert and append the character to output string.
$v = '';
switch (true) {
case $outsize == 4:
$v .= chr($c & 0xFF);
$c >>= 8;
$v .= chr($c & 0xFF);
$c >>= 8;
case $outsize == 2:
$v .= chr($c & 0xFF);
$c >>= 8;
case $outsize == 1:
$v .= chr($c & 0xFF);
$c >>= 8;
if ($c) {
return false;
}
break;
case ($c & 0x80000000) != 0:
return false;
case $c >= 0x04000000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x04000000;
case $c >= 0x00200000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00200000;
case $c >= 0x00010000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00010000;
case $c >= 0x00000800:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00000800;
case $c >= 0x00000080:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x000000C0;
default:
$v .= chr($c);
break;
}
$out .= strrev($v);
}
return $out;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
/**
* 通联支付 类加载
* @file IncludeAllinPay.php
* @datetime 2019-09-03 12:33
* @author Wang Liang<wangliang@lefull.cn>
* @link https://www.lefull.cn/
* @version 1.0
*/
function autoload($classname){
$name = explode("_",$classname);
if (count($name)>2){
include_once(dirname(__FILE__)."/{$name[0]}/{$name[1]}/{$name[2]}.php");
}else{
include_once(dirname(__FILE__)."/{$name[0]}/{$name[1]}.php");
}
}
spl_autoload_register("autoload");
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
/**
* Pure-PHP implementation of SCP.
*
* PHP versions 4 and 5
*
* The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Net/SCP.php';
* include 'Net/SSH2.php';
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
* exit('bad login');
* }
*
* $scp = new Net_SCP($ssh);
* $scp->put('abcd', str_repeat('x', 1024*1024));
* ?>
* </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 Net
* @package Net_SCP
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2010 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* @access public
* @see self::put()
*/
/**
* Reads data from a local file.
*/
define('NET_SCP_LOCAL_FILE', 1);
/**
* Reads data from a string.
*/
define('NET_SCP_STRING', 2);
/**#@-*/
/**#@+
* @access private
* @see self::_send()
* @see self::_receive()
*/
/**
* SSH1 is being used.
*/
define('NET_SCP_SSH1', 1);
/**
* SSH2 is being used.
*/
define('NET_SCP_SSH2', 2);
/**#@-*/
/**
* Pure-PHP implementations of SCP.
*
* @package Net_SCP
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Net_SCP
{
/**
* SSH Object
*
* @var object
* @access private
*/
var $ssh;
/**
* Packet Size
*
* @var int
* @access private
*/
var $packet_size;
/**
* Mode
*
* @var int
* @access private
*/
var $mode;
/**
* Default Constructor.
*
* Connects to an SSH server
*
* @param Net_SSH1|Net_SSH2 $ssh
* @return Net_SCP
* @access public
*/
function __construct($ssh)
{
if (!is_object($ssh)) {
return;
}
switch (strtolower(get_class($ssh))) {
case 'net_ssh2':
$this->mode = NET_SCP_SSH2;
break;
case 'net_ssh1':
$this->packet_size = 50000;
$this->mode = NET_SCP_SSH1;
break;
default:
return;
}
$this->ssh = $ssh;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param Net_SSH1|Net_SSH2 $ssh
* @access public
*/
function Net_SCP($ssh)
{
$this->__construct($ssh);
}
/**
* Uploads a file to the SCP server.
*
* By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
* 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_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.
*
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
* care of that, yourself.
*
* @param string $remote_file
* @param string $data
* @param int $mode
* @param callable $callback
* @return bool
* @access public
*/
function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null)
{
if (!isset($this->ssh)) {
return false;
}
if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
return false;
}
$temp = $this->_receive();
if ($temp !== chr(0)) {
return false;
}
if ($this->mode == NET_SCP_SSH2) {
$this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4;
}
$remote_file = basename($remote_file);
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) {
return false;
}
$size = filesize($data);
}
$this->_send('C0644 ' . $size . ' ' . $remote_file . "\n");
$temp = $this->_receive();
if ($temp !== chr(0)) {
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);
}
}
$this->_close();
if ($mode != NET_SCP_STRING) {
fclose($fp);
}
return true;
}
/**
* Downloads a file from the SCP server.
*
* Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
* the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
* operation
*
* @param string $remote_file
* @param string $local_file
* @return mixed
* @access public
*/
function get($remote_file, $local_file = false)
{
if (!isset($this->ssh)) {
return false;
}
if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
return false;
}
$this->_send("\0");
if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) {
return false;
}
$this->_send("\0");
$size = 0;
if ($local_file !== false) {
$fp = @fopen($local_file, 'wb');
if (!$fp) {
return false;
}
}
$content = '';
while ($size < $info['size']) {
$data = $this->_receive();
// SCP usually seems to split stuff out into 16k chunks
$size+= strlen($data);
if ($local_file === false) {
$content.= $data;
} else {
fputs($fp, $data);
}
}
$this->_close();
if ($local_file !== false) {
fclose($fp);
return true;
}
return $content;
}
/**
* Sends a packet to an SSH server
*
* @param string $data
* @access private
*/
function _send($data)
{
switch ($this->mode) {
case NET_SCP_SSH2:
$this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data);
break;
case NET_SCP_SSH1:
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
$this->ssh->_send_binary_packet($data);
}
}
/**
* Receives a packet from an SSH server
*
* @return string
* @access private
*/
function _receive()
{
switch ($this->mode) {
case NET_SCP_SSH2:
return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true);
case NET_SCP_SSH1:
if (!$this->ssh->bitmap) {
return false;
}
while (true) {
$response = $this->ssh->_get_binary_packet();
switch ($response[NET_SSH1_RESPONSE_TYPE]) {
case NET_SSH1_SMSG_STDOUT_DATA:
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA]));
return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length);
case NET_SSH1_SMSG_STDERR_DATA:
break;
case NET_SSH1_SMSG_EXITSTATUS:
$this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
fclose($this->ssh->fsock);
$this->ssh->bitmap = 0;
return false;
default:
user_error('Unknown packet received', E_USER_NOTICE);
return false;
}
}
}
}
/**
* Closes the connection to an SSH server
*
* @access private
*/
function _close()
{
switch ($this->mode) {
case NET_SCP_SSH2:
$this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true);
break;
case NET_SCP_SSH1:
$this->ssh->disconnect();
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
/**
* SFTP Stream Wrapper
*
* Creates an sftp:// protocol handler that can be used with, for example, fopen(), dir(), etc.
*
* PHP version 5
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Net
* @package Net_SFTP_Stream
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2013 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* SFTP Stream Wrapper
*
* @package Net_SFTP_Stream
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Net_SFTP_Stream
{
/**
* SFTP instances
*
* Rather than re-create the connection we re-use instances if possible
*
* @var array
*/
static $instances;
/**
* SFTP instance
*
* @var object
* @access private
*/
var $sftp;
/**
* Path
*
* @var string
* @access private
*/
var $path;
/**
* Mode
*
* @var string
* @access private
*/
var $mode;
/**
* Position
*
* @var int
* @access private
*/
var $pos;
/**
* Size
*
* @var int
* @access private
*/
var $size;
/**
* Directory entries
*
* @var array
* @access private
*/
var $entries;
/**
* EOF flag
*
* @var bool
* @access private
*/
var $eof;
/**
* Context resource
*
* Technically this needs to be publically accessible so PHP can set it directly
*
* @var resource
* @access public
*/
var $context;
/**
* Notification callback function
*
* @var callable
* @access public
*/
var $notification;
/**
* Registers this class as a URL wrapper.
*
* @param string $protocol The wrapper name to be registered.
* @return bool 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
*
* @access public
*/
function __construct()
{
if (defined('NET_SFTP_STREAM_LOGGING')) {
echo "__construct()\r\n";
}
include_once '../../Net/SFTP.php';
}
/**
* Path Parser
*
* Extract a path from a URI and actually connect to an SSH server if appropriate
*
* If "notification" is set as a context parameter the message code for successful login is
* NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE.
*
* @param string $path
* @return string
* @access private
*/
function _parse_path($path)
{
$orig = $path;
extract(parse_url($path) + array('port' => 22));
if (isset($query)) {
$path.= '?' . $query;
} elseif (preg_match('/(\?|\?#)$/', $orig)) {
$path.= '?';
}
if (isset($fragment)) {
$path.= '#' . $fragment;
} elseif ($orig[strlen($orig) - 1] == '#') {
$path.= '#';
}
if (!isset($host)) {
return false;
}
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') {
return false;
}
$this->sftp = $$host;
} else {
if (isset($this->context)) {
$context = stream_context_get_options($this->context);
}
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[$scheme]['username'])) {
$user = $context[$scheme]['username'];
}
if (isset($context[$scheme]['password'])) {
$pass = $context[$scheme]['password'];
}
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)) {
return false;
}
// casting $pass to a string is necessary in the event that it's a Crypt_RSA object
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, $port);
$this->sftp->disableStatCache();
if (isset($this->notification) && is_callable($this->notification)) {
/* if !is_callable($this->notification) we could do this:
user_error('fopen(): failed to call user notifier', E_USER_WARNING);
the ftp wrapper gives errors like that when the notifier isn't callable.
i've opted not to do that, however, since the ftp wrapper gives the line
on which the fopen occurred as the line number - not the line that the
user_error is on.
*/
call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
if (!$this->sftp->login($user, $pass)) {
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
return false;
}
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
} else {
if (!$this->sftp->login($user, $pass)) {
return false;
}
}
self::$instances[$host][$port][$user][(string) $pass] = $this->sftp;
}
}
return $path;
}
/**
* Opens file or URL
*
* @param string $path
* @param string $mode
* @param int $options
* @param string $opened_path
* @return bool
* @access public
*/
function _stream_open($path, $mode, $options, &$opened_path)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
$this->path = $path;
$this->size = $this->sftp->size($path);
$this->mode = preg_replace('#[bt]$#', '', $mode);
$this->eof = false;
if ($this->size === false) {
if ($this->mode[0] == 'r') {
return false;
} else {
$this->sftp->touch($path);
$this->size = 0;
}
} else {
switch ($this->mode[0]) {
case 'x':
return false;
case 'w':
$this->sftp->truncate($path, 0);
$this->size = 0;
}
}
$this->pos = $this->mode[0] != 'a' ? 0 : $this->size;
return true;
}
/**
* Read from stream
*
* @param int $count
* @return mixed
* @access public
*/
function _stream_read($count)
{
switch ($this->mode) {
case 'w':
case 'a':
case 'x':
case 'c':
return false;
}
// commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite
//if ($this->pos >= $this->size) {
// $this->eof = true;
// return false;
//}
$result = $this->sftp->get($this->path, false, $this->pos, $count);
if (isset($this->notification) && is_callable($this->notification)) {
if ($result === false) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}
// seems that PHP calls stream_read in 8k chunks
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size);
}
if (empty($result)) { // ie. false or empty string
$this->eof = true;
return false;
}
$this->pos+= strlen($result);
return $result;
}
/**
* Write to stream
*
* @param string $data
* @return mixed
* @access public
*/
function _stream_write($data)
{
switch ($this->mode) {
case 'r':
return false;
}
$result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos);
if (isset($this->notification) && is_callable($this->notification)) {
if (!$result) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}
// seems that PHP splits up strings into 8k blocks before calling stream_write
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data));
}
if ($result === false) {
return false;
}
$this->pos+= strlen($data);
if ($this->pos > $this->size) {
$this->size = $this->pos;
}
$this->eof = false;
return strlen($data);
}
/**
* Retrieve the current position of a stream
*
* @return int
* @access public
*/
function _stream_tell()
{
return $this->pos;
}
/**
* Tests for end-of-file on a file pointer
*
* In my testing there are four classes functions that normally effect the pointer:
* fseek, fputs / fwrite, fgets / fread and ftruncate.
*
* Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof()
* will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof()
* will return false. do fread($fp, 1) and feof() will then return true.
*
* @return bool
* @access public
*/
function _stream_eof()
{
return $this->eof;
}
/**
* Seeks to specific location in a stream
*
* @param int $offset
* @param int $whence
* @return bool
* @access public
*/
function _stream_seek($offset, $whence)
{
switch ($whence) {
case SEEK_SET:
if ($offset >= $this->size || $offset < 0) {
return false;
}
break;
case SEEK_CUR:
$offset+= $this->pos;
break;
case SEEK_END:
$offset+= $this->size;
}
$this->pos = $offset;
$this->eof = false;
return true;
}
/**
* Change stream options
*
* @param string $path
* @param int $option
* @param mixed $var
* @return bool
* @access public
*/
function _stream_metadata($path, $option, $var)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
// stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined
// see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246
// and https://github.com/php/php-src/blob/master/main/php_streams.h#L592
switch ($option) {
case 1: // PHP_STREAM_META_TOUCH
return $this->sftp->touch($path, $var[0], $var[1]);
case 2: // PHP_STREAM_OWNER_NAME
case 3: // PHP_STREAM_GROUP_NAME
return false;
case 4: // PHP_STREAM_META_OWNER
return $this->sftp->chown($path, $var);
case 5: // PHP_STREAM_META_GROUP
return $this->sftp->chgrp($path, $var);
case 6: // PHP_STREAM_META_ACCESS
return $this->sftp->chmod($path, $var) !== false;
}
}
/**
* Retrieve the underlaying resource
*
* @param int $cast_as
* @return resource
* @access public
*/
function _stream_cast($cast_as)
{
return $this->sftp->fsock;
}
/**
* Advisory file locking
*
* @param int $operation
* @return bool
* @access public
*/
function _stream_lock($operation)
{
return false;
}
/**
* Renames a file or directory
*
* Attempts to rename oldname to newname, moving it between directories if necessary.
* If newname exists, it will be overwritten. This is a departure from what Net_SFTP
* does.
*
* @param string $path_from
* @param string $path_to
* @return bool
* @access public
*/
function _rename($path_from, $path_to)
{
$path1 = parse_url($path_from);
$path2 = parse_url($path_to);
unset($path1['path'], $path2['path']);
if ($path1 != $path2) {
return false;
}
$path_from = $this->_parse_path($path_from);
$path_to = parse_url($path_to);
if ($path_from === false) {
return false;
}
$path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2
// "It is an error if there already exists a file with the name specified by newpath."
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5
if (!$this->sftp->rename($path_from, $path_to)) {
if ($this->sftp->stat($path_to)) {
return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to);
}
return false;
}
return true;
}
/**
* 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.
*
* 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 int $options
* @return bool
* @access public
*/
function _dir_opendir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
$this->pos = 0;
$this->entries = $this->sftp->nlist($path);
return $this->entries !== false;
}
/**
* Read entry from directory handle
*
* @return mixed
* @access public
*/
function _dir_readdir()
{
if (isset($this->entries[$this->pos])) {
return $this->entries[$this->pos++];
}
return false;
}
/**
* Rewind directory handle
*
* @return bool
* @access public
*/
function _dir_rewinddir()
{
$this->pos = 0;
return true;
}
/**
* Close directory handle
*
* @return bool
* @access public
*/
function _dir_closedir()
{
return true;
}
/**
* Create a directory
*
* Only valid $options is STREAM_MKDIR_RECURSIVE
*
* @param string $path
* @param int $mode
* @param int $options
* @return bool
* @access public
*/
function _mkdir($path, $mode, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE);
}
/**
* Removes a directory
*
* Only valid $options is STREAM_MKDIR_RECURSIVE per <http://php.net/streamwrapper.rmdir>, however,
* <http://php.net/rmdir> does not have a $recursive parameter as mkdir() does so I don't know how
* STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as
* $options. What does 8 correspond to?
*
* @param string $path
* @param int $mode
* @param int $options
* @return bool
* @access public
*/
function _rmdir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
return $this->sftp->rmdir($path);
}
/**
* Flushes the output
*
* See <http://php.net/fflush>. Always returns true because Net_SFTP doesn't cache stuff before writing
*
* @return bool
* @access public
*/
function _stream_flush()
{
return true;
}
/**
* Retrieve information about a file resource
*
* @return mixed
* @access public
*/
function _stream_stat()
{
$results = $this->sftp->stat($this->path);
if ($results === false) {
return false;
}
return $results;
}
/**
* Delete a file
*
* @param string $path
* @return bool
* @access public
*/
function _unlink($path)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
return $this->sftp->delete($path, false);
}
/**
* Retrieve information about a file
*
* Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default
* might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll
* cross that bridge when and if it's reached
*
* @param string $path
* @param int $flags
* @return mixed
* @access public
*/
function _url_stat($path, $flags)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
$results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path);
if ($results === false) {
return false;
}
return $results;
}
/**
* Truncate stream
*
* @param int $new_size
* @return bool
* @access public
*/
function _stream_truncate($new_size)
{
if (!$this->sftp->truncate($this->path, $new_size)) {
return false;
}
$this->eof = false;
$this->size = $new_size;
return true;
}
/**
* Change stream options
*
* STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't.
* The other two aren't supported because of limitations in Net_SFTP.
*
* @param int $option
* @param int $arg1
* @param int $arg2
* @return bool
* @access public
*/
function _stream_set_option($option, $arg1, $arg2)
{
return false;
}
/**
* Close an resource
*
* @access public
*/
function _stream_close()
{
}
/**
* __call Magic Method
*
* When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you.
* Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function
* lets you figure that out.
*
* If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not
* NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method.
*
* @param string
* @param array
* @return mixed
* @access public
*/
function __call($name, $arguments)
{
if (defined('NET_SFTP_STREAM_LOGGING')) {
echo $name . '(';
$last = count($arguments) - 1;
foreach ($arguments as $i => $argument) {
var_export($argument);
if ($i != $last) {
echo ',';
}
}
echo ")\r\n";
}
$name = '_' . $name;
if (!method_exists($this, $name)) {
return false;
}
return call_user_func_array(array($this, $name), $arguments);
}
}
Net_SFTP_Stream::register();
<?php
/**
* Pure-PHP implementation of SSHv1.
*
* PHP versions 4 and 5
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Net/SSH1.php';
*
* $ssh = new Net_SSH1('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
* exit('Login Failed');
* }
*
* echo $ssh->exec('ls -la');
* ?>
* </code>
*
* Here's another short example:
* <code>
* <?php
* include 'Net/SSH1.php';
*
* $ssh = new Net_SSH1('www.domain.tld');
* if (!$ssh->login('username', 'password')) {
* exit('Login Failed');
* }
*
* echo $ssh->read('username@username:~$');
* $ssh->write("ls -la\n");
* echo $ssh->read('username@username:~$');
* ?>
* </code>
*
* More information on the SSHv1 specification can be found by reading
* {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Net
* @package Net_SSH1
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* Encryption Methods
*
* @see self::getSupportedCiphers()
* @access public
*/
/**
* No encryption
*
* Not supported.
*/
define('NET_SSH1_CIPHER_NONE', 0);
/**
* IDEA in CFB mode
*
* Not supported.
*/
define('NET_SSH1_CIPHER_IDEA', 1);
/**
* DES in CBC mode
*/
define('NET_SSH1_CIPHER_DES', 2);
/**
* Triple-DES in CBC mode
*
* All implementations are required to support this
*/
define('NET_SSH1_CIPHER_3DES', 3);
/**
* TRI's Simple Stream encryption CBC
*
* Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
* although it doesn't use it (see cipher.c)
*/
define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
/**
* RC4
*
* Not supported.
*
* @internal According to the SSH1 specs:
*
* "The first 16 bytes of the session key are used as the key for
* the server to client direction. The remaining 16 bytes are used
* as the key for the client to server direction. This gives
* independent 128-bit keys for each direction."
*
* This library currently only supports encryption when the same key is being used for both directions. This is
* because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
*/
define('NET_SSH1_CIPHER_RC4', 5);
/**
* Blowfish
*
* Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
* uses it (see cipher.c)
*/
define('NET_SSH1_CIPHER_BLOWFISH', 6);
/**#@-*/
/**#@+
* Authentication Methods
*
* @see self::getSupportedAuthentications()
* @access public
*/
/**
* .rhosts or /etc/hosts.equiv
*/
define('NET_SSH1_AUTH_RHOSTS', 1);
/**
* pure RSA authentication
*/
define('NET_SSH1_AUTH_RSA', 2);
/**
* password authentication
*
* This is the only method that is supported by this library.
*/
define('NET_SSH1_AUTH_PASSWORD', 3);
/**
* .rhosts with RSA host authentication
*/
define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
/**#@-*/
/**#@+
* Terminal Modes
*
* @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
* @access private
*/
define('NET_SSH1_TTY_OP_END', 0);
/**#@-*/
/**
* The Response Type
*
* @see self::_get_binary_packet()
* @access private
*/
define('NET_SSH1_RESPONSE_TYPE', 1);
/**
* The Response Data
*
* @see self::_get_binary_packet()
* @access private
*/
define('NET_SSH1_RESPONSE_DATA', 2);
/**#@+
* Execution Bitmap Masks
*
* @see self::bitmap
* @access private
*/
define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
define('NET_SSH1_MASK_CONNECTED', 0x00000002);
define('NET_SSH1_MASK_LOGIN', 0x00000004);
define('NET_SSH1_MASK_SHELL', 0x00000008);
/**#@-*/
/**#@+
* @access public
* @see self::getLog()
*/
/**
* Returns the message numbers
*/
define('NET_SSH1_LOG_SIMPLE', 1);
/**
* Returns the message content
*/
define('NET_SSH1_LOG_COMPLEX', 2);
/**
* Outputs the content real-time
*/
define('NET_SSH1_LOG_REALTIME', 3);
/**
* Dumps the content real-time to a file
*/
define('NET_SSH1_LOG_REALTIME_FILE', 4);
/**#@-*/
/**#@+
* @access public
* @see self::read()
*/
/**
* Returns when a string matching $expect exactly is found
*/
define('NET_SSH1_READ_SIMPLE', 1);
/**
* Returns when a string matching the regular expression $expect is found
*/
define('NET_SSH1_READ_REGEX', 2);
/**#@-*/
/**
* Pure-PHP implementation of SSHv1.
*
* @package Net_SSH1
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Net_SSH1
{
/**
* The SSH identifier
*
* @var string
* @access private
*/
var $identifier = 'SSH-1.5-phpseclib';
/**
* The Socket Object
*
* @var object
* @access private
*/
var $fsock;
/**
* The cryptography object
*
* @var object
* @access private
*/
var $crypto = false;
/**
* Execution Bitmap
*
* The bits that are set represent functions that have been called already. This is used to determine
* if a requisite function has been successfully executed. If not, an error should be thrown.
*
* @var int
* @access private
*/
var $bitmap = 0;
/**
* The Server Key Public Exponent
*
* Logged for debug purposes
*
* @see self::getServerKeyPublicExponent()
* @var string
* @access private
*/
var $server_key_public_exponent;
/**
* The Server Key Public Modulus
*
* Logged for debug purposes
*
* @see self::getServerKeyPublicModulus()
* @var string
* @access private
*/
var $server_key_public_modulus;
/**
* The Host Key Public Exponent
*
* Logged for debug purposes
*
* @see self::getHostKeyPublicExponent()
* @var string
* @access private
*/
var $host_key_public_exponent;
/**
* The Host Key Public Modulus
*
* Logged for debug purposes
*
* @see self::getHostKeyPublicModulus()
* @var string
* @access private
*/
var $host_key_public_modulus;
/**
* Supported Ciphers
*
* Logged for debug purposes
*
* @see self::getSupportedCiphers()
* @var array
* @access private
*/
var $supported_ciphers = array(
NET_SSH1_CIPHER_NONE => 'No encryption',
NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
NET_SSH1_CIPHER_DES => 'DES in CBC mode',
NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
NET_SSH1_CIPHER_RC4 => 'RC4',
NET_SSH1_CIPHER_BLOWFISH => 'Blowfish'
);
/**
* Supported Authentications
*
* Logged for debug purposes
*
* @see self::getSupportedAuthentications()
* @var array
* @access private
*/
var $supported_authentications = array(
NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
NET_SSH1_AUTH_RSA => 'pure RSA authentication',
NET_SSH1_AUTH_PASSWORD => 'password authentication',
NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
);
/**
* Server Identification
*
* @see self::getServerIdentification()
* @var string
* @access private
*/
var $server_identification = '';
/**
* Protocol Flags
*
* @see self::Net_SSH1()
* @var array
* @access private
*/
var $protocol_flags = array();
/**
* Protocol Flag Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $protocol_flag_log = array();
/**
* Message Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $message_log = array();
/**
* Real-time log file pointer
*
* @see self::_append_log()
* @var resource
* @access private
*/
var $realtime_log_file;
/**
* Real-time log file size
*
* @see self::_append_log()
* @var int
* @access private
*/
var $realtime_log_size;
/**
* Real-time log file wrap boolean
*
* @see self::_append_log()
* @var bool
* @access private
*/
var $realtime_log_wrap;
/**
* Interactive Buffer
*
* @see self::read()
* @var array
* @access private
*/
var $interactiveBuffer = '';
/**
* Timeout
*
* @see self::setTimeout()
* @access private
*/
var $timeout;
/**
* Current Timeout
*
* @see self::_get_channel_packet()
* @access private
*/
var $curTimeout;
/**
* Log Boundary
*
* @see self::_format_log()
* @access private
*/
var $log_boundary = ':';
/**
* Log Long Width
*
* @see self::_format_log()
* @access private
*/
var $log_long_width = 65;
/**
* Log Short Width
*
* @see self::_format_log()
* @access private
*/
var $log_short_width = 16;
/**
* Hostname
*
* @see self::Net_SSH1()
* @see self::_connect()
* @var string
* @access private
*/
var $host;
/**
* Port Number
*
* @see self::Net_SSH1()
* @see self::_connect()
* @var int
* @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 self::Net_SSH1()
* @see self::_connect()
* @var int
* @access private
*/
var $connectionTimeout;
/**
* Default cipher
*
* @see self::Net_SSH1()
* @see self::_connect()
* @var int
* @access private
*/
var $cipher;
/**
* Default Constructor.
*
* Connects to an SSHv1 server
*
* @param string $host
* @param int $port
* @param int $timeout
* @param int $cipher
* @return Net_SSH1
* @access public
*/
function __construct($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
{
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 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')) {
include_once 'Crypt/Random.php';
}
$this->protocol_flags = array(
1 => 'NET_SSH1_MSG_DISCONNECT',
2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
3 => 'NET_SSH1_CMSG_SESSION_KEY',
4 => 'NET_SSH1_CMSG_USER',
9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
10 => 'NET_SSH1_CMSG_REQUEST_PTY',
12 => 'NET_SSH1_CMSG_EXEC_SHELL',
13 => 'NET_SSH1_CMSG_EXEC_CMD',
14 => 'NET_SSH1_SMSG_SUCCESS',
15 => 'NET_SSH1_SMSG_FAILURE',
16 => 'NET_SSH1_CMSG_STDIN_DATA',
17 => 'NET_SSH1_SMSG_STDOUT_DATA',
18 => 'NET_SSH1_SMSG_STDERR_DATA',
19 => 'NET_SSH1_CMSG_EOF',
20 => 'NET_SSH1_SMSG_EXITSTATUS',
33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
);
$this->_define_array($this->protocol_flags);
$this->host = $host;
$this->port = $port;
$this->connectionTimeout = $timeout;
$this->cipher = $cipher;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param string $host
* @param int $port
* @param int $timeout
* @param int $cipher
* @access public
*/
function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
{
$this->__construct($host, $port, $timeout, $cipher);
}
/**
* Connect to an SSHv1 server
*
* @return bool
* @access private
*/
function _connect()
{
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
if (!$this->fsock) {
user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
return false;
}
$this->server_identification = $init_line = fgets($this->fsock, 255);
if (defined('NET_SSH1_LOGGING')) {
$this->_append_log('<-', $this->server_identification);
$this->_append_log('->', $this->identifier . "\r\n");
}
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
user_error('Can only connect to SSH servers');
return false;
}
if ($parts[1][0] != 1) {
user_error("Cannot connect to SSH $parts[1] servers");
return false;
}
fputs($this->fsock, $this->identifier."\r\n");
$response = $this->_get_binary_packet();
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
user_error('Expected SSH_SMSG_PUBLIC_KEY');
return false;
}
$anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->server_key_public_exponent = $server_key_public_exponent;
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->server_key_public_modulus = $server_key_public_modulus;
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->host_key_public_exponent = $host_key_public_exponent;
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->host_key_public_modulus = $host_key_public_modulus;
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
// get a list of the supported ciphers
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
foreach ($this->supported_ciphers as $mask => $name) {
if (($supported_ciphers_mask & (1 << $mask)) == 0) {
unset($this->supported_ciphers[$mask]);
}
}
// get a list of the supported authentications
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
foreach ($this->supported_authentications as $mask => $name) {
if (($supported_authentications_mask & (1 << $mask)) == 0) {
unset($this->supported_authentications[$mask]);
}
}
$session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
$session_key = crypt_random_string(32);
$double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$server_key_public_exponent,
$server_key_public_modulus
)
);
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$host_key_public_exponent,
$host_key_public_modulus
)
);
} else {
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$host_key_public_exponent,
$host_key_public_modulus
)
);
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$server_key_public_exponent,
$server_key_public_modulus
)
);
}
$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 false;
}
switch ($cipher) {
//case NET_SSH1_CIPHER_NONE:
// $this->crypto = new Crypt_Null();
// break;
case NET_SSH1_CIPHER_DES:
if (!class_exists('Crypt_DES')) {
include_once 'Crypt/DES.php';
}
$this->crypto = new Crypt_DES();
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 8));
break;
case NET_SSH1_CIPHER_3DES:
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 24));
break;
//case NET_SSH1_CIPHER_RC4:
// if (!class_exists('Crypt_RC4')) {
// include_once 'Crypt/RC4.php';
// }
// $this->crypto = new Crypt_RC4();
// $this->crypto->enableContinuousBuffer();
// $this->crypto->setKey(substr($session_key, 0, 16));
// break;
}
$response = $this->_get_binary_packet();
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
}
$this->bitmap = NET_SSH1_MASK_CONNECTED;
return true;
}
/**
* Login
*
* @param string $username
* @param string $password
* @return bool
* @access public
*/
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;
}
$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_USER');
return false;
}
$response = $this->_get_binary_packet();
if ($response === true) {
return false;
}
if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
$this->bitmap |= NET_SSH1_MASK_LOGIN;
return true;
} elseif ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
return false;
}
// remove the username and password from the last logged packet
if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
$this->message_log[count($this->message_log) - 1] = $data;
}
$response = $this->_get_binary_packet();
if ($response === true) {
return false;
}
if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
$this->bitmap |= NET_SSH1_MASK_LOGIN;
return true;
} elseif ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
return false;
} else {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
}
}
/**
* Set Timeout
*
* $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout.
* Setting $timeout to false or 0 will mean there is no timeout.
*
* @param mixed $timeout
*/
function setTimeout($timeout)
{
$this->timeout = $this->curTimeout = $timeout;
}
/**
* Executes a command on a non-interactive shell, returns the output, and quits.
*
* An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
* servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
* shell with the -s option, as discussed in the following links:
*
* {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
* {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
*
* To execute further commands, a new Net_SSH1 object will need to be created.
*
* Returns false on failure and the output, otherwise.
*
* @see self::interactiveRead()
* @see self::interactiveWrite()
* @param string $cmd
* @return mixed
* @access public
*/
function exec($cmd, $block = true)
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_CMD');
return false;
}
if (!$block) {
return true;
}
$output = '';
$response = $this->_get_binary_packet();
if ($response !== false) {
do {
$output.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
$response = $this->_get_binary_packet();
} while (is_array($response) && $response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
}
$data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
// i don't think it's really all that important if this packet gets sent or not.
$this->_send_binary_packet($data);
fclose($this->fsock);
// reset the execution bitmap - a new Net_SSH1 object needs to be created.
$this->bitmap = 0;
return $output;
}
/**
* Creates an interactive shell
*
* @see self::interactiveRead()
* @see self::interactiveWrite()
* @return bool
* @access private
*/
function _initShell()
{
// connect using the sample parameters in protocol-1.5.txt.
// according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
// terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
$data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_REQUEST_PTY');
return false;
}
$response = $this->_get_binary_packet();
if ($response === true) {
return false;
}
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
}
$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_SHELL');
return false;
}
$this->bitmap |= NET_SSH1_MASK_SHELL;
//stream_set_blocking($this->fsock, 0);
return true;
}
/**
* Inputs a command into an interactive shell.
*
* @see self::interactiveWrite()
* @param string $cmd
* @return bool
* @access public
*/
function write($cmd)
{
return $this->interactiveWrite($cmd);
}
/**
* Returns the output of an interactive shell when there's a match for $expect
*
* $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX,
* a regular expression.
*
* @see self::write()
* @param string $expect
* @param int $mode
* @return bool
* @access public
*/
function read($expect, $mode = NET_SSH1_READ_SIMPLE)
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
$match = $expect;
while (true) {
if ($mode == NET_SSH1_READ_REGEX) {
preg_match($expect, $this->interactiveBuffer, $matches);
$match = isset($matches[0]) ? $matches[0] : '';
}
$pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
if ($pos !== false) {
return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
}
$response = $this->_get_binary_packet();
if ($response === true) {
return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
}
$this->interactiveBuffer.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
}
}
/**
* Inputs a command into an interactive shell.
*
* @see self::interactiveRead()
* @param string $cmd
* @return bool
* @access public
*/
function interactiveWrite($cmd)
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_STDIN');
return false;
}
return true;
}
/**
* Returns the output of an interactive shell when no more output is available.
*
* Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
* "^[[00m", you're seeing ANSI escape codes. According to
* {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
* does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
* there's not going to be much recourse.
*
* @see self::interactiveRead()
* @return string
* @access public
*/
function interactiveRead()
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
$read = array($this->fsock);
$write = $except = null;
if (stream_select($read, $write, $except, 0)) {
$response = $this->_get_binary_packet();
return substr($response[NET_SSH1_RESPONSE_DATA], 4);
} else {
return '';
}
}
/**
* Disconnect
*
* @access public
*/
function disconnect()
{
$this->_disconnect();
}
/**
* Destructor.
*
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
* disconnect().
*
* @access public
*/
function __destruct()
{
$this->_disconnect();
}
/**
* Disconnect
*
* @param string $msg
* @access private
*/
function _disconnect($msg = 'Client Quit')
{
if ($this->bitmap) {
$data = pack('C', NET_SSH1_CMSG_EOF);
$this->_send_binary_packet($data);
/*
$response = $this->_get_binary_packet();
if ($response === true) {
$response = array(NET_SSH1_RESPONSE_TYPE => -1);
}
switch ($response[NET_SSH1_RESPONSE_TYPE]) {
case NET_SSH1_SMSG_EXITSTATUS:
$data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
break;
default:
$data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
}
*/
$data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
$this->_send_binary_packet($data);
fclose($this->fsock);
$this->bitmap = 0;
}
}
/**
* Gets Binary Packets
*
* See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
*
* Also, this function could be improved upon by adding detection for the following exploit:
* http://www.securiteam.com/securitynews/5LP042K3FY.html
*
* @see self::_send_binary_packet()
* @return array
* @access private
*/
function _get_binary_packet()
{
if (feof($this->fsock)) {
//user_error('connection closed prematurely');
return false;
}
if ($this->curTimeout) {
$read = array($this->fsock);
$write = $except = null;
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
// on windows this returns a "Warning: Invalid CRT parameters detected" error
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
//$this->_disconnect('Timeout');
return true;
}
$elapsed = strtok(microtime(), ' ') + strtok('') - $start;
$this->curTimeout-= $elapsed;
}
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$data = fread($this->fsock, 4);
if (strlen($data) < 4) {
return false;
}
$temp = unpack('Nlength', $data);
$padding_length = 8 - ($temp['length'] & 7);
$length = $temp['length'] + $padding_length;
$raw = '';
while ($length > 0) {
$temp = fread($this->fsock, $length);
$raw.= $temp;
$length-= strlen($temp);
}
$stop = strtok(microtime(), ' ') + strtok('');
if (strlen($raw) && $this->crypto !== false) {
$raw = $this->crypto->decrypt($raw);
}
$padding = substr($raw, 0, $padding_length);
$type = $raw[$padding_length];
$data = substr($raw, $padding_length + 1, -4);
if (strlen($raw) < 4) {
return false;
}
$temp = unpack('Ncrc', substr($raw, -4));
//if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
// user_error('Bad CRC in packet from server');
// return false;
//}
$type = ord($type);
if (defined('NET_SSH1_LOGGING')) {
$temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
$temp = '<- ' . $temp .
' (' . round($stop - $start, 4) . 's)';
$this->_append_log($temp, $data);
}
return array(
NET_SSH1_RESPONSE_TYPE => $type,
NET_SSH1_RESPONSE_DATA => $data
);
}
/**
* Sends Binary Packets
*
* Returns true on success, false on failure.
*
* @see self::_get_binary_packet()
* @param string $data
* @return bool
* @access private
*/
function _send_binary_packet($data)
{
if (feof($this->fsock)) {
//user_error('connection closed prematurely');
return false;
}
$length = strlen($data) + 4;
$padding = crypt_random_string(8 - ($length & 7));
$orig = $data;
$data = $padding . $data;
$data.= pack('N', $this->_crc($data));
if ($this->crypto !== false) {
$data = $this->crypto->encrypt($data);
}
$packet = pack('Na*', $length, $data);
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$result = strlen($packet) == fputs($this->fsock, $packet);
$stop = strtok(microtime(), ' ') + strtok('');
if (defined('NET_SSH1_LOGGING')) {
$temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
$temp = '-> ' . $temp .
' (' . round($stop - $start, 4) . 's)';
$this->_append_log($temp, $orig);
}
return $result;
}
/**
* Cyclic Redundancy Check (CRC)
*
* PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
* we've reimplemented it. A more detailed discussion of the differences can be found after
* $crc_lookup_table's initialization.
*
* @see self::_get_binary_packet()
* @see self::_send_binary_packet()
* @param string $data
* @return int
* @access private
*/
function _crc($data)
{
static $crc_lookup_table = array(
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
);
// For this function to yield the same output as PHP's crc32 function, $crc would have to be
// set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
$crc = 0x00000000;
$length = strlen($data);
for ($i=0; $i<$length; $i++) {
// We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
// be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
// yields 0xFF800000 - not 0x00800000. The following link elaborates:
// http://www.php.net/manual/en/language.operators.bitwise.php#57281
$crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
}
// In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
// 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
return $crc;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* RSA Encrypt
*
* Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
* should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
* calls this call modexp, instead, but I think this makes things clearer, maybe...
*
* @see self::Net_SSH1()
* @param Math_BigInteger $m
* @param array $key
* @return Math_BigInteger
* @access private
*/
function _rsa_crypt($m, $key)
{
/*
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$rsa = new Crypt_RSA();
$rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
return $rsa->encrypt($m);
*/
// To quote from protocol-1.5.txt:
// The most significant byte (which is only partial as the value must be
// less than the public modulus, which is never a power of two) is zero.
//
// The next byte contains the value 2 (which stands for public-key
// encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
// zero random bytes to fill any unused space, a zero byte, and the data
// to be encrypted in the least significant bytes, the last byte of the
// data in the least significant byte.
// Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
// under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
$modulus = $key[1]->toBytes();
$length = strlen($modulus) - strlen($m) - 3;
$random = '';
while (strlen($random) != $length) {
$block = crypt_random_string($length - strlen($random));
$block = str_replace("\x00", '', $block);
$random.= $block;
}
$temp = chr(0) . chr(2) . $random . chr(0) . $m;
$m = new Math_BigInteger($temp, 256);
$m = $m->modPow($key[0], $key[1]);
return $m->toBytes();
}
/**
* Define Array
*
* Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
* named constants from it, using the value as the name of the constant and the index as the value of the constant.
* If any of the constants that would be defined already exists, none of the constants will be defined.
*
* @param array $array
* @access private
*/
function _define_array()
{
$args = func_get_args();
foreach ($args as $arg) {
foreach ($arg as $key => $value) {
if (!defined($value)) {
define($value, $key);
} else {
break 2;
}
}
}
}
/**
* Returns a log of the packets that have been sent and received.
*
* Returns a string if NET_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 array|false|string
*/
function getLog()
{
if (!defined('NET_SSH1_LOGGING')) {
return false;
}
switch (NET_SSH1_LOGGING) {
case NET_SSH1_LOG_SIMPLE:
return $this->message_number_log;
break;
case NET_SSH1_LOG_COMPLEX:
return $this->_format_log($this->message_log, $this->protocol_flags_log);
break;
default:
return false;
}
}
/**
* Formats a log for printing
*
* @param array $message_log
* @param array $message_number_log
* @access private
* @return string
*/
function _format_log($message_log, $message_number_log)
{
$output = '';
for ($i = 0; $i < count($message_log); $i++) {
$output.= $message_number_log[$i] . "\r\n";
$current_log = $message_log[$i];
$j = 0;
do {
if (strlen($current_log)) {
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
}
$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, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
$j++;
} while (strlen($current_log));
$output.= "\r\n";
}
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
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getServerKeyPublicExponent($raw_output = false)
{
return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
}
/**
* Return the server key public modulus
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getServerKeyPublicModulus($raw_output = false)
{
return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
}
/**
* Return the host key public exponent
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getHostKeyPublicExponent($raw_output = false)
{
return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
}
/**
* Return the host key public modulus
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getHostKeyPublicModulus($raw_output = false)
{
return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
}
/**
* Return a list of ciphers supported by SSH1 server.
*
* Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
* is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
* get array(NET_SSH1_CIPHER_3DES).
*
* @param bool $raw_output
* @return array
* @access public
*/
function getSupportedCiphers($raw_output = false)
{
return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
}
/**
* Return a list of authentications supported by SSH1 server.
*
* Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
* is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
* get array(NET_SSH1_AUTH_PASSWORD).
*
* @param bool $raw_output
* @return array
* @access public
*/
function getSupportedAuthentications($raw_output = false)
{
return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
}
/**
* Return the server identification.
*
* @return string
* @access public
*/
function getServerIdentification()
{
return rtrim($this->server_identification);
}
/**
* Logs data packets
*
* Makes sure that only the last 1MB worth of packets will be logged
*
* @param string $data
* @access private
*/
function _append_log($protocol_flags, $message)
{
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;
}
$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);
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
/**
* Pure-PHP ssh-agent client.
*
* PHP versions 4 and 5
*
* Here are some examples of how to use this library:
* <code>
* <?php
* include 'System/SSH/Agent.php';
* include 'Net/SSH2.php';
*
* $agent = new System_SSH_Agent();
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', $agent)) {
* exit('Login Failed');
* }
*
* echo $ssh->exec('pwd');
* echo $ssh->exec('ls -la');
* ?>
* </code>
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category System
* @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/
/**#@+
* Message numbers
*
* @access private
*/
// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
define('SYSTEM_SSH_AGENT_FAILURE', 5);
// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
/**#@-*/
/**@+
* Agent forwarding status
*
* @access private
*/
// no forwarding requested and not active
define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
// request agent forwarding when opportune
define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
// forwarding has been request and is active
define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
/**#@-*/
/**@+
* Signature Flags
*
* See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3
*
* @access private
*/
define('SYSTEM_SSH_AGENT_RSA2_256', 2);
define('SYSTEM_SSH_AGENT_RSA2_512', 4);
/**#@-*/
/**
* 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 self::getPublicKey()
*/
var $key;
/**
* Key Blob
*
* @var string
* @access private
* @see self::sign()
*/
var $key_blob;
/**
* Socket Resource
*
* @var resource
* @access private
* @see self::sign()
*/
var $fsock;
/**
* Signature flags
*
* @var int
* @access private
* @see self::sign()
* @see self::setHash()
*/
var $flags = 0;
/**
* Default Constructor.
*
* @param resource $fsock
* @return System_SSH_Agent_Identity
* @access private
*/
function __construct($fsock)
{
$this->fsock = $fsock;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param resource $fsock
* @access public
*/
function System_SSH_Agent_Identity($fsock)
{
$this->__construct($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 int $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 int $mode
* @access public
*/
function setSignatureMode($mode)
{
}
/**
* Set Hash
*
* ssh-agent doesn't support using hashes for RSA other than SHA1
*
* @param string $hash
* @access public
*/
function setHash($hash)
{
$this->flags = 0;
switch ($hash) {
case 'sha1':
break;
case 'sha256':
$this->flags = SYSTEM_SSH_AGENT_RSA2_256;
break;
case 'sha512':
$this->flags = SYSTEM_SSH_AGENT_RSA2_512;
break;
default:
user_error('The only supported hashes for RSA are sha1, sha256 and sha512');
}
}
/**
* 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, $this->flags);
$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);
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
if ($length != strlen($signature_blob)) {
user_error('Malformed signature blob');
}
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
if ($length > strlen($signature_blob) + 4) {
user_error('Malformed signature blob');
}
$type = $this->_string_shift($signature_blob, $length);
$this->_string_shift($signature_blob, 4);
return $signature_blob;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
/**
* 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 public
*/
class System_SSH_Agent
{
/**
* Socket Resource
*
* @var resource
* @access private
*/
var $fsock;
/**
* Agent forwarding status
*
* @access private
*/
var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
/**
* Buffer for accumulating forwarded authentication
* agent data arriving on SSH data channel destined
* for agent unix socket
*
* @access private
*/
var $socket_buffer = '';
/**
* Tracking the number of bytes we are expecting
* to arrive for the agent socket on the SSH data
* channel
*/
var $expected_bytes = 0;
/**
* Default Constructor
*
* @return System_SSH_Agent
* @access public
*/
function __construct($address = null)
{
if (!$address) {
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)");
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function System_SSH_Agent($address = null)
{
$this->__construct($address);
}
/**
* 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');
return array();
}
$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');
return array();
}
$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);
$key_str = 'ssh-rsa ' . base64_encode($key_blob);
$length = current(unpack('N', fread($this->fsock, 4)));
if ($length) {
$key_str.= ' ' . 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($key_str);
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;
}
/**
* Signal that agent forwarding should
* be requested when a channel is opened
*
* @param Net_SSH2 $ssh
* @return bool
* @access public
*/
function startSSHForwarding($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
}
}
/**
* Request agent forwarding of remote server
*
* @param Net_SSH2 $ssh
* @return bool
* @access private
*/
function _request_forwarding($ssh)
{
$request_channel = $ssh->_get_open_channel();
if ($request_channel === false) {
return false;
}
$packet = pack(
'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST,
$ssh->server_channels[$request_channel],
strlen('auth-agent-req@openssh.com'),
'auth-agent-req@openssh.com',
1
);
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
if (!$ssh->_send_binary_packet($packet)) {
return false;
}
$response = $ssh->_get_channel_packet($request_channel);
if ($response === false) {
return false;
}
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
return true;
}
/**
* On successful channel open
*
* This method is called upon successful channel
* open to give the SSH Agent an opportunity
* to take further action. i.e. request agent forwarding
*
* @param Net_SSH2 $ssh
* @access private
*/
function _on_channel_open($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
$this->_request_forwarding($ssh);
}
}
/**
* Forward data to SSH Agent and return data reply
*
* @param string $data
* @return data from SSH Agent
* @access private
*/
function _forward_data($data)
{
if ($this->expected_bytes > 0) {
$this->socket_buffer.= $data;
$this->expected_bytes -= strlen($data);
} else {
$agent_data_bytes = current(unpack('N', $data));
$current_data_bytes = strlen($data);
$this->socket_buffer = $data;
if ($current_data_bytes != $agent_data_bytes + 4) {
$this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
return false;
}
}
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
user_error('Connection closed attempting to forward data to SSH agent');
}
$this->socket_buffer = '';
$this->expected_bytes = 0;
$agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
$agent_reply_data = fread($this->fsock, $agent_reply_bytes);
$agent_reply_data = current(unpack('a*', $agent_reply_data));
return pack('Na*', $agent_reply_bytes, $agent_reply_data);
}
}
<?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 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/
require_once 'SSH/Agent.php';
# minimalist openssl.cnf file for use with phpseclib
HOME = .
RANDFILE = $ENV::HOME/.rnd
[ v3_ca ]
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论