PageRenderTime 80ms CodeModel.GetById 15ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 1ms

/apps/files_external/3rdparty/phpseclib/phpseclib/Crypt/DES.php

https://github.com/sezuan/core
PHP | 1334 lines | 822 code | 76 blank | 436 comment | 109 complexity | ab14022fc00c783661dd0da32aba83a9 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3
   4/**
   5 * Pure-PHP implementation of DES.
   6 *
   7 * Uses mcrypt, if available, and an internal implementation, otherwise.
   8 *
   9 * PHP versions 4 and 5
  10 *
  11 * Useful resources are as follows:
  12 *
  13 *  - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
  14 *  - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
  15 *  - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
  16 *
  17 * Here's a short example of how to use this library:
  18 * <code>
  19 * <?php
  20 *    include('Crypt/DES.php');
  21 *
  22 *    $des = new Crypt_DES();
  23 *
  24 *    $des->setKey('abcdefgh');
  25 *
  26 *    $size = 10 * 1024;
  27 *    $plaintext = '';
  28 *    for ($i = 0; $i < $size; $i++) {
  29 *        $plaintext.= 'a';
  30 *    }
  31 *
  32 *    echo $des->decrypt($des->encrypt($plaintext));
  33 * ?>
  34 * </code>
  35 *
  36 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  37 * of this software and associated documentation files (the "Software"), to deal
  38 * in the Software without restriction, including without limitation the rights
  39 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  40 * copies of the Software, and to permit persons to whom the Software is
  41 * furnished to do so, subject to the following conditions:
  42 * 
  43 * The above copyright notice and this permission notice shall be included in
  44 * all copies or substantial portions of the Software.
  45 * 
  46 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  47 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  48 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  49 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  50 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  51 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  52 * THE SOFTWARE.
  53 *
  54 * @category   Crypt
  55 * @package    Crypt_DES
  56 * @author     Jim Wigginton <terrafrost@php.net>
  57 * @copyright  MMVII Jim Wigginton
  58 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
  59 * @version    $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
  60 * @link       http://phpseclib.sourceforge.net
  61 */
  62
  63/**#@+
  64 * @access private
  65 * @see Crypt_DES::_prepareKey()
  66 * @see Crypt_DES::_processBlock()
  67 */
  68/**
  69 * Contains array_reverse($keys[CRYPT_DES_DECRYPT])
  70 */
  71define('CRYPT_DES_ENCRYPT', 0);
  72/**
  73 * Contains array_reverse($keys[CRYPT_DES_ENCRYPT])
  74 */
  75define('CRYPT_DES_DECRYPT', 1);
  76/**#@-*/
  77
  78/**#@+
  79 * @access public
  80 * @see Crypt_DES::encrypt()
  81 * @see Crypt_DES::decrypt()
  82 */
  83/**
  84 * Encrypt / decrypt using the Counter mode.
  85 *
  86 * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
  87 *
  88 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
  89 */
  90define('CRYPT_DES_MODE_CTR', -1);
  91/**
  92 * Encrypt / decrypt using the Electronic Code Book mode.
  93 *
  94 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
  95 */
  96define('CRYPT_DES_MODE_ECB', 1);
  97/**
  98 * Encrypt / decrypt using the Code Book Chaining mode.
  99 *
 100 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
 101 */
 102define('CRYPT_DES_MODE_CBC', 2);
 103/**
 104 * Encrypt / decrypt using the Cipher Feedback mode.
 105 *
 106 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
 107 */
 108define('CRYPT_DES_MODE_CFB', 3);
 109/**
 110 * Encrypt / decrypt using the Cipher Feedback mode.
 111 *
 112 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
 113 */
 114define('CRYPT_DES_MODE_OFB', 4);
 115/**#@-*/
 116
 117/**#@+
 118 * @access private
 119 * @see Crypt_DES::Crypt_DES()
 120 */
 121/**
 122 * Toggles the internal implementation
 123 */
 124define('CRYPT_DES_MODE_INTERNAL', 1);
 125/**
 126 * Toggles the mcrypt implementation
 127 */
 128define('CRYPT_DES_MODE_MCRYPT', 2);
 129/**#@-*/
 130
 131/**
 132 * Pure-PHP implementation of DES.
 133 *
 134 * @author  Jim Wigginton <terrafrost@php.net>
 135 * @version 0.1.0
 136 * @access  public
 137 * @package Crypt_DES
 138 */
 139class Crypt_DES {
 140    /**
 141     * The Key Schedule
 142     *
 143     * @see Crypt_DES::setKey()
 144     * @var Array
 145     * @access private
 146     */
 147    var $keys = "\0\0\0\0\0\0\0\0";
 148
 149    /**
 150     * The Encryption Mode
 151     *
 152     * @see Crypt_DES::Crypt_DES()
 153     * @var Integer
 154     * @access private
 155     */
 156    var $mode;
 157
 158    /**
 159     * Continuous Buffer status
 160     *
 161     * @see Crypt_DES::enableContinuousBuffer()
 162     * @var Boolean
 163     * @access private
 164     */
 165    var $continuousBuffer = false;
 166
 167    /**
 168     * Padding status
 169     *
 170     * @see Crypt_DES::enablePadding()
 171     * @var Boolean
 172     * @access private
 173     */
 174    var $padding = true;
 175
 176    /**
 177     * The Initialization Vector
 178     *
 179     * @see Crypt_DES::setIV()
 180     * @var String
 181     * @access private
 182     */
 183    var $iv = "\0\0\0\0\0\0\0\0";
 184
 185    /**
 186     * A "sliding" Initialization Vector
 187     *
 188     * @see Crypt_DES::enableContinuousBuffer()
 189     * @var String
 190     * @access private
 191     */
 192    var $encryptIV = "\0\0\0\0\0\0\0\0";
 193
 194    /**
 195     * A "sliding" Initialization Vector
 196     *
 197     * @see Crypt_DES::enableContinuousBuffer()
 198     * @var String
 199     * @access private
 200     */
 201    var $decryptIV = "\0\0\0\0\0\0\0\0";
 202
 203    /**
 204     * mcrypt resource for encryption
 205     *
 206     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
 207     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
 208     *
 209     * @see Crypt_DES::encrypt()
 210     * @var String
 211     * @access private
 212     */
 213    var $enmcrypt;
 214
 215    /**
 216     * mcrypt resource for decryption
 217     *
 218     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
 219     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
 220     *
 221     * @see Crypt_DES::decrypt()
 222     * @var String
 223     * @access private
 224     */
 225    var $demcrypt;
 226
 227    /**
 228     * Does the enmcrypt resource need to be (re)initialized?
 229     *
 230     * @see Crypt_DES::setKey()
 231     * @see Crypt_DES::setIV()
 232     * @var Boolean
 233     * @access private
 234     */
 235    var $enchanged = true;
 236
 237    /**
 238     * Does the demcrypt resource need to be (re)initialized?
 239     *
 240     * @see Crypt_DES::setKey()
 241     * @see Crypt_DES::setIV()
 242     * @var Boolean
 243     * @access private
 244     */
 245    var $dechanged = true;
 246
 247    /**
 248     * Is the mode one that is paddable?
 249     *
 250     * @see Crypt_DES::Crypt_DES()
 251     * @var Boolean
 252     * @access private
 253     */
 254    var $paddable = false;
 255
 256    /**
 257     * Encryption buffer for CTR, OFB and CFB modes
 258     *
 259     * @see Crypt_DES::encrypt()
 260     * @var Array
 261     * @access private
 262     */
 263    var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
 264
 265    /**
 266     * Decryption buffer for CTR, OFB and CFB modes
 267     *
 268     * @see Crypt_DES::decrypt()
 269     * @var Array
 270     * @access private
 271     */
 272    var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
 273
 274    /**
 275     * mcrypt resource for CFB mode
 276     *
 277     * @see Crypt_DES::encrypt()
 278     * @see Crypt_DES::decrypt()
 279     * @var String
 280     * @access private
 281     */
 282    var $ecb;
 283
 284    /**
 285     * Default Constructor.
 286     *
 287     * Determines whether or not the mcrypt extension should be used.  $mode should only, at present, be
 288     * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC.  If not explictly set, CRYPT_DES_MODE_CBC will be used.
 289     *
 290     * @param optional Integer $mode
 291     * @return Crypt_DES
 292     * @access public
 293     */
 294    function Crypt_DES($mode = CRYPT_DES_MODE_CBC)
 295    {
 296        if ( !defined('CRYPT_DES_MODE') ) {
 297            switch (true) {
 298                case extension_loaded('mcrypt') && in_array('des', mcrypt_list_algorithms()):
 299                    define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
 300                    break;
 301                default:
 302                    define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
 303            }
 304        }
 305
 306        switch ( CRYPT_DES_MODE ) {
 307            case CRYPT_DES_MODE_MCRYPT:
 308                switch ($mode) {
 309                    case CRYPT_DES_MODE_ECB:
 310                        $this->paddable = true;
 311                        $this->mode = MCRYPT_MODE_ECB;
 312                        break;
 313                    case CRYPT_DES_MODE_CTR:
 314                        $this->mode = 'ctr';
 315                        //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
 316                        break;
 317                    case CRYPT_DES_MODE_CFB:
 318                        $this->mode = 'ncfb';
 319                        $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
 320                        break;
 321                    case CRYPT_DES_MODE_OFB:
 322                        $this->mode = MCRYPT_MODE_NOFB;
 323                        break;
 324                    case CRYPT_DES_MODE_CBC:
 325                    default:
 326                        $this->paddable = true;
 327                        $this->mode = MCRYPT_MODE_CBC;
 328                }
 329                $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
 330                $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
 331
 332                break;
 333            default:
 334                switch ($mode) {
 335                    case CRYPT_DES_MODE_ECB:
 336                    case CRYPT_DES_MODE_CBC:
 337                        $this->paddable = true;
 338                        $this->mode = $mode;
 339                        break;
 340                    case CRYPT_DES_MODE_CTR:
 341                    case CRYPT_DES_MODE_CFB:
 342                    case CRYPT_DES_MODE_OFB:
 343                        $this->mode = $mode;
 344                        break;
 345                    default:
 346                        $this->paddable = true;
 347                        $this->mode = CRYPT_DES_MODE_CBC;
 348                }
 349        }
 350    }
 351
 352    /**
 353     * Sets the key.
 354     *
 355     * Keys can be of any length.  DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
 356     * only use the first eight, if $key has more then eight characters in it, and pad $key with the
 357     * null byte if it is less then eight characters long.
 358     *
 359     * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
 360     *
 361     * If the key is not explicitly set, it'll be assumed to be all zero's.
 362     *
 363     * @access public
 364     * @param String $key
 365     */
 366    function setKey($key)
 367    {
 368        $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key);
 369        $this->enchanged = true;
 370        $this->dechanged = true;
 371    }
 372
 373    /**
 374     * Sets the password.
 375     *
 376     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
 377     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
 378     *         $hash, $salt, $count
 379     *
 380     * @param String $password
 381     * @param optional String $method
 382     * @access public
 383     */
 384    function setPassword($password, $method = 'pbkdf2')
 385    {
 386        $key = '';
 387
 388        switch ($method) {
 389            default: // 'pbkdf2'
 390                list(, , $hash, $salt, $count) = func_get_args();
 391                if (!isset($hash)) {
 392                    $hash = 'sha1';
 393                }
 394                // WPA and WPA2 use the SSID as the salt
 395                if (!isset($salt)) {
 396                    $salt = 'phpseclib/salt';
 397                }
 398                // RFC2898#section-4.2 uses 1,000 iterations by default
 399                // WPA and WPA2 use 4,096.
 400                if (!isset($count)) {
 401                    $count = 1000;
 402                }
 403
 404                if (!class_exists('Crypt_Hash')) {
 405                    require_once('Crypt/Hash.php');
 406                }
 407
 408                $i = 1;
 409                while (strlen($key) < 8) { // $dkLen == 8
 410                    //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
 411                    $hmac = new Crypt_Hash();
 412                    $hmac->setHash($hash);
 413                    $hmac->setKey($password);
 414                    $f = $u = $hmac->hash($salt . pack('N', $i++));
 415                    for ($j = 2; $j <= $count; $j++) {
 416                        $u = $hmac->hash($u);
 417                        $f^= $u;
 418                    }
 419                    $key.= $f;
 420                }
 421        }
 422
 423        $this->setKey($key);
 424    }
 425
 426    /**
 427     * Sets the initialization vector. (optional)
 428     *
 429     * SetIV is not required when CRYPT_DES_MODE_ECB is being used.  If not explictly set, it'll be assumed
 430     * to be all zero's.
 431     *
 432     * @access public
 433     * @param String $iv
 434     */
 435    function setIV($iv)
 436    {
 437        $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
 438        $this->enchanged = true;
 439        $this->dechanged = true;
 440    }
 441
 442    /**
 443     * Generate CTR XOR encryption key
 444     *
 445     * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
 446     * plaintext / ciphertext in CTR mode.
 447     *
 448     * @see Crypt_DES::decrypt()
 449     * @see Crypt_DES::encrypt()
 450     * @access public
 451     * @param String $iv
 452     */
 453    function _generate_xor(&$iv)
 454    {
 455        $xor = $iv;
 456        for ($j = 4; $j <= 8; $j+=4) {
 457            $temp = substr($iv, -$j, 4);
 458            switch ($temp) {
 459                case "\xFF\xFF\xFF\xFF":
 460                    $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
 461                    break;
 462                case "\x7F\xFF\xFF\xFF":
 463                    $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
 464                    break 2;
 465                default:
 466                    extract(unpack('Ncount', $temp));
 467                    $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
 468                    break 2;
 469            }
 470        }
 471
 472        return $xor;
 473    }
 474
 475    /**
 476     * Encrypts a message.
 477     *
 478     * $plaintext will be padded with up to 8 additional bytes.  Other DES implementations may or may not pad in the
 479     * same manner.  Other common approaches to padding and the reasons why it's necessary are discussed in the following
 480     * URL:
 481     *
 482     * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
 483     *
 484     * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
 485     * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
 486     * length.
 487     *
 488     * @see Crypt_DES::decrypt()
 489     * @access public
 490     * @param String $plaintext
 491     */
 492    function encrypt($plaintext)
 493    {
 494        if ($this->paddable) {
 495            $plaintext = $this->_pad($plaintext);
 496        }
 497
 498        if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
 499            if ($this->enchanged) {
 500                mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
 501                if ($this->mode == 'ncfb') {
 502                    mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
 503                }
 504                $this->enchanged = false;
 505            }
 506
 507            if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
 508                $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
 509            } else {
 510                $iv = &$this->encryptIV;
 511                $pos = &$this->enbuffer['pos'];
 512                $len = strlen($plaintext);
 513                $ciphertext = '';
 514                $i = 0;
 515                if ($pos) {
 516                    $orig_pos = $pos;
 517                    $max = 8 - $pos;
 518                    if ($len >= $max) {
 519                        $i = $max;
 520                        $len-= $max;
 521                        $pos = 0;
 522                    } else {
 523                        $i = $len;
 524                        $pos+= $len;
 525                        $len = 0;
 526                    }
 527                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
 528                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
 529                    $this->enbuffer['enmcrypt_init'] = true;
 530                }
 531                if ($len >= 8) {
 532                    if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) {
 533                        if ($this->enbuffer['enmcrypt_init'] === true) {
 534                            mcrypt_generic_init($this->enmcrypt, $this->keys, $iv);
 535                            $this->enbuffer['enmcrypt_init'] = false;
 536                        }
 537                        $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
 538                        $iv = substr($ciphertext, -8);
 539                        $len%= 8;
 540                    } else {
 541                        while ($len >= 8) {
 542                            $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
 543                            $ciphertext.= $iv;
 544                            $len-= 8;
 545                            $i+= 8;
 546                        }
 547                    }
 548                } 
 549                if ($len) {
 550                    $iv = mcrypt_generic($this->ecb, $iv);
 551                    $block = $iv ^ substr($plaintext, -$len);
 552                    $iv = substr_replace($iv, $block, 0, $len);
 553                    $ciphertext.= $block;
 554                    $pos = $len;
 555                }
 556                return $ciphertext;
 557            }
 558
 559            if (!$this->continuousBuffer) {
 560                mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
 561            }
 562
 563            return $ciphertext;
 564        }
 565
 566        if (!is_array($this->keys)) {
 567            $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
 568        }
 569
 570        $buffer = &$this->enbuffer;
 571        $continuousBuffer = $this->continuousBuffer;
 572        $ciphertext = '';
 573        switch ($this->mode) {
 574            case CRYPT_DES_MODE_ECB:
 575                for ($i = 0; $i < strlen($plaintext); $i+=8) {
 576                    $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT);
 577                }
 578                break;
 579            case CRYPT_DES_MODE_CBC:
 580                $xor = $this->encryptIV;
 581                for ($i = 0; $i < strlen($plaintext); $i+=8) {
 582                    $block = substr($plaintext, $i, 8);
 583                    $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT);
 584                    $xor = $block;
 585                    $ciphertext.= $block;
 586                }
 587                if ($this->continuousBuffer) {
 588                    $this->encryptIV = $xor;
 589                }
 590                break;
 591            case CRYPT_DES_MODE_CTR:
 592                $xor = $this->encryptIV;
 593                if (strlen($buffer['encrypted'])) {
 594                    for ($i = 0; $i < strlen($plaintext); $i+=8) {
 595                        $block = substr($plaintext, $i, 8);
 596                        $buffer['encrypted'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
 597                        $key = $this->_string_shift($buffer['encrypted'], 8);
 598                        $ciphertext.= $block ^ $key;
 599                    }
 600                } else {
 601                    for ($i = 0; $i < strlen($plaintext); $i+=8) {
 602                        $block = substr($plaintext, $i, 8);
 603                        $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
 604                        $ciphertext.= $block ^ $key;
 605                    }
 606                }
 607                if ($this->continuousBuffer) {
 608                    $this->encryptIV = $xor;
 609                    if ($start = strlen($plaintext) & 7) {
 610                        $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
 611                    }
 612                }
 613                break;
 614            case CRYPT_DES_MODE_CFB:
 615                if ($this->continuousBuffer) {
 616                    $iv = &$this->encryptIV;
 617                    $pos = &$buffer['pos'];
 618                } else {
 619                    $iv = $this->encryptIV;
 620                    $pos = 0;
 621                }
 622                $len = strlen($plaintext);
 623                $i = 0;
 624                if ($pos) {
 625                    $orig_pos = $pos;
 626                    $max = 8 - $pos;
 627                    if ($len >= $max) {
 628                        $i = $max;
 629                        $len-= $max;
 630                        $pos = 0;
 631                    } else {
 632                        $i = $len;
 633                        $pos+= $len;
 634                        $len = 0;
 635                    }
 636                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
 637                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
 638                }
 639                while ($len >= 8) {
 640                    $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT) ^ substr($plaintext, $i, 8);
 641                    $ciphertext.= $iv;
 642                    $len-= 8;
 643                    $i+= 8;
 644                }
 645                if ($len) {
 646                    $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
 647                    $block = $iv ^ substr($plaintext, $i);
 648                    $iv = substr_replace($iv, $block, 0, $len);
 649                    $ciphertext.= $block;
 650                    $pos = $len;
 651                }
 652                return $ciphertext;
 653            case CRYPT_DES_MODE_OFB:
 654                $xor = $this->encryptIV;
 655                if (strlen($buffer['xor'])) {
 656                    for ($i = 0; $i < strlen($plaintext); $i+=8) {
 657                        $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
 658                        $buffer['xor'].= $xor;
 659                        $key = $this->_string_shift($buffer['xor'], 8);
 660                        $ciphertext.= substr($plaintext, $i, 8) ^ $key;
 661                    }
 662                } else {
 663                    for ($i = 0; $i < strlen($plaintext); $i+=8) {
 664                        $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
 665                        $ciphertext.= substr($plaintext, $i, 8) ^ $xor;
 666                    }
 667                    $key = $xor;
 668                }
 669                if ($this->continuousBuffer) {
 670                    $this->encryptIV = $xor;
 671                    if ($start = strlen($plaintext) & 7) {
 672                         $buffer['xor'] = substr($key, $start) . $buffer['xor'];
 673                    }
 674                }
 675        }
 676
 677        return $ciphertext;
 678    }
 679
 680    /**
 681     * Decrypts a message.
 682     *
 683     * If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
 684     *
 685     * @see Crypt_DES::encrypt()
 686     * @access public
 687     * @param String $ciphertext
 688     */
 689    function decrypt($ciphertext)
 690    {
 691        if ($this->paddable) {
 692            // we pad with chr(0) since that's what mcrypt_generic does.  to quote from http://php.net/function.mcrypt-generic :
 693            // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
 694            $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
 695        }
 696
 697        if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
 698            if ($this->dechanged) {
 699                mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
 700                if ($this->mode == 'ncfb') {
 701                    mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
 702                }
 703                $this->dechanged = false;
 704            }
 705
 706            if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
 707                $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
 708            } else {
 709                $iv = &$this->decryptIV;
 710                $pos = &$this->debuffer['pos'];
 711                $len = strlen($ciphertext);
 712                $plaintext = '';
 713                $i = 0;
 714                if ($pos) {
 715                    $orig_pos = $pos;
 716                    $max = 8 - $pos;
 717                    if ($len >= $max) {
 718                        $i = $max;
 719                        $len-= $max;
 720                        $pos = 0;
 721                    } else {
 722                        $i = $len;
 723                        $pos+= $len;
 724                        $len = 0;
 725                    }
 726                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
 727                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
 728                }
 729                if ($len >= 8) {
 730                    $cb = substr($ciphertext, $i, $len - $len % 8);
 731                    $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
 732                    $iv = substr($cb, -8);
 733                    $len%= 8;
 734                }
 735                if ($len) {
 736                    $iv = mcrypt_generic($this->ecb, $iv);
 737                    $plaintext.= $iv ^ substr($ciphertext, -$len);
 738                    $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
 739                    $pos = $len;
 740                }
 741                return $plaintext;
 742            }
 743
 744            if (!$this->continuousBuffer) {
 745                mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
 746            }
 747
 748            return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
 749        }
 750
 751        if (!is_array($this->keys)) {
 752            $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
 753        }
 754
 755        $buffer = &$this->debuffer;
 756        $continuousBuffer = $this->continuousBuffer;
 757        $plaintext = '';
 758        switch ($this->mode) {
 759            case CRYPT_DES_MODE_ECB:
 760                for ($i = 0; $i < strlen($ciphertext); $i+=8) {
 761                    $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT);
 762                }
 763                break;
 764            case CRYPT_DES_MODE_CBC:
 765                $xor = $this->decryptIV;
 766                for ($i = 0; $i < strlen($ciphertext); $i+=8) {
 767                    $block = substr($ciphertext, $i, 8);
 768                    $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor;
 769                    $xor = $block;
 770                }
 771                if ($this->continuousBuffer) {
 772                    $this->decryptIV = $xor;
 773                }
 774                break;
 775            case CRYPT_DES_MODE_CTR:
 776                $xor = $this->decryptIV;
 777                if (strlen($buffer['ciphertext'])) {
 778                    for ($i = 0; $i < strlen($ciphertext); $i+=8) {
 779                        $block = substr($ciphertext, $i, 8);
 780                        $buffer['ciphertext'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
 781                        $key = $this->_string_shift($buffer['ciphertext'], 8);
 782                        $plaintext.= $block ^ $key;
 783                    }
 784                } else {
 785                    for ($i = 0; $i < strlen($ciphertext); $i+=8) {
 786                        $block = substr($ciphertext, $i, 8);
 787                        $key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
 788                        $plaintext.= $block ^ $key;
 789                    }
 790                }
 791                if ($this->continuousBuffer) {
 792                    $this->decryptIV = $xor;
 793                    if ($start = strlen($ciphertext) % 8) {
 794                        $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
 795                    }
 796                }
 797                break;
 798            case CRYPT_DES_MODE_CFB:
 799                if ($this->continuousBuffer) {
 800                    $iv = &$this->decryptIV;
 801                    $pos = &$buffer['pos'];
 802                } else {
 803                    $iv = $this->decryptIV;
 804                    $pos = 0;
 805                }
 806                $len = strlen($ciphertext);
 807                $i = 0;
 808                if ($pos) {
 809                    $orig_pos = $pos;
 810                    $max = 8 - $pos;
 811                    if ($len >= $max) {
 812                        $i = $max;
 813                        $len-= $max;
 814                        $pos = 0;
 815                    } else {
 816                        $i = $len;
 817                        $pos+= $len;
 818                        $len = 0;
 819                    }
 820                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
 821                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
 822                }
 823                while ($len >= 8) {
 824                    $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
 825                    $cb = substr($ciphertext, $i, 8);
 826                    $plaintext.= $iv ^ $cb;
 827                    $iv = $cb;
 828                    $len-= 8;
 829                    $i+= 8;
 830                }
 831                if ($len) {
 832                    $iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
 833                    $plaintext.= $iv ^ substr($ciphertext, $i);
 834                    $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
 835                    $pos = $len;
 836                }
 837                return $plaintext;
 838            case CRYPT_DES_MODE_OFB:
 839                $xor = $this->decryptIV;
 840                if (strlen($buffer['xor'])) {
 841                    for ($i = 0; $i < strlen($ciphertext); $i+=8) {
 842                        $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
 843                        $buffer['xor'].= $xor;
 844                        $key = $this->_string_shift($buffer['xor'], 8);
 845                        $plaintext.= substr($ciphertext, $i, 8) ^ $key;
 846                    }
 847                } else {
 848                    for ($i = 0; $i < strlen($ciphertext); $i+=8) {
 849                        $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
 850                        $plaintext.= substr($ciphertext, $i, 8) ^ $xor;
 851                    }
 852                    $key = $xor;
 853                }
 854                if ($this->continuousBuffer) {
 855                    $this->decryptIV = $xor;
 856                    if ($start = strlen($ciphertext) % 8) {
 857                         $buffer['xor'] = substr($key, $start) . $buffer['xor'];
 858                    }
 859                }
 860        }
 861
 862        return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
 863    }
 864
 865    /**
 866     * Treat consecutive "packets" as if they are a continuous buffer.
 867     *
 868     * Say you have a 16-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
 869     * will yield different outputs:
 870     *
 871     * <code>
 872     *    echo $des->encrypt(substr($plaintext, 0, 8));
 873     *    echo $des->encrypt(substr($plaintext, 8, 8));
 874     * </code>
 875     * <code>
 876     *    echo $des->encrypt($plaintext);
 877     * </code>
 878     *
 879     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
 880     * another, as demonstrated with the following:
 881     *
 882     * <code>
 883     *    $des->encrypt(substr($plaintext, 0, 8));
 884     *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
 885     * </code>
 886     * <code>
 887     *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
 888     * </code>
 889     *
 890     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
 891     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
 892     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
 893     *
 894     * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
 895     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
 896     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
 897     * however, they are also less intuitive and more likely to cause you problems.
 898     *
 899     * @see Crypt_DES::disableContinuousBuffer()
 900     * @access public
 901     */
 902    function enableContinuousBuffer()
 903    {
 904        $this->continuousBuffer = true;
 905    }
 906
 907    /**
 908     * Treat consecutive packets as if they are a discontinuous buffer.
 909     *
 910     * The default behavior.
 911     *
 912     * @see Crypt_DES::enableContinuousBuffer()
 913     * @access public
 914     */
 915    function disableContinuousBuffer()
 916    {
 917        $this->continuousBuffer = false;
 918        $this->encryptIV = $this->iv;
 919        $this->decryptIV = $this->iv;
 920        $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
 921        $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
 922
 923        if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) {
 924            mcrypt_generic_init($this->enmcrypt, $this->keys, $this->iv);
 925            mcrypt_generic_init($this->demcrypt, $this->keys, $this->iv);
 926        }
 927    }
 928
 929    /**
 930     * Pad "packets".
 931     *
 932     * DES works by encrypting eight bytes at a time.  If you ever need to encrypt or decrypt something that's not
 933     * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
 934     *
 935     * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH1,
 936     * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
 937     * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
 938     * transmitted separately)
 939     *
 940     * @see Crypt_DES::disablePadding()
 941     * @access public
 942     */
 943    function enablePadding()
 944    {
 945        $this->padding = true;
 946    }
 947
 948    /**
 949     * Do not pad packets.
 950     *
 951     * @see Crypt_DES::enablePadding()
 952     * @access public
 953     */
 954    function disablePadding()
 955    {
 956        $this->padding = false;
 957    }
 958
 959    /**
 960     * Pads a string
 961     *
 962     * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
 963     * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
 964     *
 965     * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
 966     * and padding will, hence forth, be enabled.
 967     *
 968     * @see Crypt_DES::_unpad()
 969     * @access private
 970     */
 971    function _pad($text)
 972    {
 973        $length = strlen($text);
 974
 975        if (!$this->padding) {
 976            if (($length & 7) == 0) {
 977                return $text;
 978            } else {
 979                user_error("The plaintext's length ($length) is not a multiple of the block size (8)");
 980                $this->padding = true;
 981            }
 982        }
 983
 984        $pad = 8 - ($length & 7);
 985        return str_pad($text, $length + $pad, chr($pad));
 986    }
 987
 988    /**
 989     * Unpads a string
 990     *
 991     * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
 992     * and false will be returned.
 993     *
 994     * @see Crypt_DES::_pad()
 995     * @access private
 996     */
 997    function _unpad($text)
 998    {
 999        if (!$this->padding) {
1000            return $text;
1001        }
1002
1003        $length = ord($text[strlen($text) - 1]);
1004
1005        if (!$length || $length > 8) {
1006            return false;
1007        }
1008
1009        return substr($text, 0, -$length);
1010    }
1011
1012    /**
1013     * Encrypts or decrypts a 64-bit block
1014     *
1015     * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT.  See
1016     * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
1017     * idea of what this function does.
1018     *
1019     * @access private
1020     * @param String $block
1021     * @param Integer $mode
1022     * @return String
1023     */
1024    function _processBlock($block, $mode)
1025    {
1026        // s-boxes.  in the official DES docs, they're described as being matrices that
1027        // one accesses by using the first and last bits to determine the row and the
1028        // middle four bits to determine the column.  in this implementation, they've
1029        // been converted to vectors
1030        static $sbox = array(
1031            array(
1032                14,  0,  4, 15, 13,  7,  1,  4,  2, 14, 15,  2, 11, 13,  8,  1,
1033                 3, 10 ,10,  6,  6, 12, 12, 11,  5,  9,  9,  5,  0,  3,  7,  8,
1034                 4, 15,  1, 12, 14,  8,  8,  2, 13,  4,  6,  9,  2,  1, 11,  7,
1035                15,  5, 12, 11,  9,  3,  7, 14,  3, 10, 10,  0,  5,  6,  0, 13
1036            ),
1037            array(
1038                15,  3,  1, 13,  8,  4, 14,  7,  6, 15, 11,  2,  3,  8,  4, 14,
1039                 9, 12,  7,  0,  2,  1, 13, 10, 12,  6,  0,  9,  5, 11, 10,  5,
1040                 0, 13, 14,  8,  7, 10, 11,  1, 10,  3,  4, 15, 13,  4,  1,  2,
1041                 5, 11,  8,  6, 12,  7,  6, 12,  9,  0,  3,  5,  2, 14, 15,  9
1042            ),
1043            array(
1044                10, 13,  0,  7,  9,  0, 14,  9,  6,  3,  3,  4, 15,  6,  5, 10,
1045                 1,  2, 13,  8, 12,  5,  7, 14, 11, 12,  4, 11,  2, 15,  8,  1,
1046                13,  1,  6, 10,  4, 13,  9,  0,  8,  6, 15,  9,  3,  8,  0,  7,
1047                11,  4,  1, 15,  2, 14, 12,  3,  5, 11, 10,  5, 14,  2,  7, 12
1048            ),
1049            array(
1050                 7, 13, 13,  8, 14, 11,  3,  5,  0,  6,  6, 15,  9,  0, 10,  3,
1051                 1,  4,  2,  7,  8,  2,  5, 12, 11,  1, 12, 10,  4, 14, 15,  9,
1052                10,  3,  6, 15,  9,  0,  0,  6, 12, 10, 11,  1,  7, 13, 13,  8,
1053                15,  9,  1,  4,  3,  5, 14, 11,  5, 12,  2,  7,  8,  2,  4, 14
1054            ),
1055            array(
1056                 2, 14, 12, 11,  4,  2,  1, 12,  7,  4, 10,  7, 11, 13,  6,  1,
1057                 8,  5,  5,  0,  3, 15, 15, 10, 13,  3,  0,  9, 14,  8,  9,  6,
1058                 4, 11,  2,  8,  1, 12, 11,  7, 10,  1, 13, 14,  7,  2,  8, 13,
1059                15,  6,  9, 15, 12,  0,  5,  9,  6, 10,  3,  4,  0,  5, 14,  3
1060            ),
1061            array(
1062                12, 10,  1, 15, 10,  4, 15,  2,  9,  7,  2, 12,  6,  9,  8,  5,
1063                 0,  6, 13,  1,  3, 13,  4, 14, 14,  0,  7, 11,  5,  3, 11,  8,
1064                 9,  4, 14,  3, 15,  2,  5, 12,  2,  9,  8,  5, 12, 15,  3, 10,
1065                 7, 11,  0, 14,  4,  1, 10,  7,  1,  6, 13,  0, 11,  8,  6, 13
1066            ),
1067            array(
1068                 4, 13, 11,  0,  2, 11, 14,  7, 15,  4,  0,  9,  8,  1, 13, 10,
1069                 3, 14, 12,  3,  9,  5,  7, 12,  5,  2, 10, 15,  6,  8,  1,  6,
1070                 1,  6,  4, 11, 11, 13, 13,  8, 12,  1,  3,  4,  7, 10, 14,  7,
1071                10,  9, 15,  5,  6,  0,  8, 15,  0, 14,  5,  2,  9,  3,  2, 12
1072            ),
1073            array(
1074                13,  1,  2, 15,  8, 13,  4,  8,  6, 10, 15,  3, 11,  7,  1,  4,
1075                10, 12,  9,  5,  3,  6, 14, 11,  5,  0,  0, 14, 12,  9,  7,  2,
1076                 7,  2, 11,  1,  4, 14,  1,  7,  9,  4, 12, 10, 14,  8,  2, 13,
1077                 0, 15,  6, 12, 10,  9, 13,  0, 15,  3,  3,  5,  5,  6,  8, 11
1078            )
1079        );
1080
1081        $keys = $this->keys;
1082
1083        $temp = unpack('Na/Nb', $block);
1084        $block = array($temp['a'], $temp['b']);
1085
1086        // because php does arithmetic right shifts, if the most significant bits are set, right
1087        // shifting those into the correct position will add 1's - not 0's.  this will intefere
1088        // with the | operation unless a second & is done.  so we isolate these bits and left shift
1089        // them into place.  we then & each block with 0x7FFFFFFF to prevennt 1's from being added
1090        // for any other shifts.
1091        $msb = array(
1092            ($block[0] >> 31) & 1,
1093            ($block[1] >> 31) & 1
1094        );
1095        $block[0] &= 0x7FFFFFFF;
1096        $block[1] &= 0x7FFFFFFF;
1097
1098        // we isolate the appropriate bit in the appropriate integer and shift as appropriate.  in
1099        // some cases, there are going to be multiple bits in the same integer that need to be shifted
1100        // in the same way.  we combine those into one shift operation.
1101        $block = array(
1102            (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) |
1103            (($block[1] & 0x00400001) <<  7) | (($block[1] & 0x40000100) >>  2) |
1104            (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) |
1105            (($block[0] & 0x00400001) <<  3) | (($block[0] & 0x40000100) >>  6) |
1106            (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) |
1107            (($block[1] & 0x00100000) <<  1) | (($block[1] & 0x10000000) >>  8) |
1108            (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) <<  6) |
1109            (($block[0] & 0x00100000) >>  3) | (($block[0] & 0x10000000) >> 12) |
1110            (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) <<  4) |
1111            (($block[1] & 0x00040000) >>  5) | (($block[1] & 0x04000000) >> 14) |
1112            (($block[0] & 0x00000004) <<  9) | ( $block[0] & 0x00000400       ) |
1113            (($block[0] & 0x00040000) >>  9) | (($block[0] & 0x04000000) >> 18) |
1114            (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) |
1115            (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24)
1116        ,
1117            (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) |
1118            (($block[1] & 0x00800002) <<  6) | (($block[0] & 0x00000080) << 20) |
1119            (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) <<  2) |
1120            (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) <<  9) |
1121            ( $block[1] & 0x00200000       ) | (($block[1] & 0x20000000) >>  9) |
1122            (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) <<  5) |
1123            (($block[0] & 0x00200000) >>  4) | (($block[0] & 0x20000000) >> 13) |
1124            (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) <<  3) |
1125            (($block[1] & 0x00080000) >>  6) | (($block[1] & 0x08000000) >> 15) |
1126            (($block[0] & 0x00000008) <<  8) | (($block[0] & 0x00000800) >>  1) |
1127            (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) |
1128            (($block[1] & 0x00000200) >>  3) | (($block[0] & 0x00000200) >>  7) |
1129            (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) |
1130            (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) |
1131            ($msb[1] << 28) | ($msb[0] << 24)
1132        );
1133
1134        for ($i = 0; $i < 16; $i++) {
1135            // start of "the Feistel (F) function" - see the following URL:
1136            // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
1137            $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28)
1138                  | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24)
1139                  | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20)
1140                  | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16)
1141                  | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12)
1142                  | (($sbox[5][(($block[1] & 0x00001F80) >>  7) ^ $keys[$mode][$i][5]]) <<  8)
1143                  | (($sbox[6][(($block[1] & 0x000001F8) >>  3) ^ $keys[$mode][$i][6]]) <<  4)
1144                  | ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]);
1145
1146            $msb = ($temp >> 31) & 1;
1147            $temp &= 0x7FFFFFFF;
1148            $newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) <<  5)
1149                      | (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10)
1150                      | (($temp & 0x00000008) << 24) | (($temp & 0x00100000) <<  6)
1151                      | (($temp & 0x00000010) << 21) | (($temp & 0x00008000) <<  9)
1152                      | (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27)
1153                      | (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >>  8)
1154                      | (($temp & 0x00004000) <<  4) | (($temp & 0x00000002) << 16)
1155                      | (($temp & 0x00442000) >>  6) | (($temp & 0x40800000) >> 15)
1156                      | (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20)
1157                      | (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) <<  3)
1158                      | (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >>  7)
1159                      | (($temp & 0x00200000) >> 19) | ($msb << 23);
1160            // end of "the Feistel (F) function" - $newBlock is F's output
1161
1162            $temp = $block[1];
1163            $block[1] = $block[0] ^ $newBlock;
1164            $block[0] = $temp;
1165        }
1166
1167        $msb = array(
1168            ($block[0] >> 31) & 1,
1169            ($block[1] >> 31) & 1
1170        );
1171        $block[0] &= 0x7FFFFFFF;
1172        $block[1] &= 0x7FFFFFFF;
1173
1174        $block = array(
1175            (($block[0] & 0x01000004) <<  7) | (($block[1] & 0x01000004) <<  6) |
1176            (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) |
1177            (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) |
1178            (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) |
1179            (($block[0] & 0x02000008) >>  2) | (($block[1] & 0x02000008) >>  3) |
1180            (($block[0] & 0x00020000) <<  4) | (($block[1] & 0x00020000) <<  3) |
1181            (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) <<  9) |
1182            (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) |
1183            (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) |
1184            (($block[0] & 0x00040000) >>  5) | (($block[1] & 0x00040000) >>  6) |
1185            (($block[0] & 0x00000400) <<  1) | ( $block[1] & 0x00000400       ) |
1186            (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) |
1187            (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) |
1188            (($block[0] & 0x00000800) >>  8) | (($block[1] & 0x00000800) >>  9)
1189        ,
1190            (($block[0] & 0x10000040) <<  3) | (($block[1] & 0x10000040) <<  2) |
1191            (($block[0] & 0x00100000) <<  9) | (($block[1] & 0x00100000) <<  8) |
1192            (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) |
1193            (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) |
1194            (($block[0] & 0x20000080) >>  6) | (($block[1] & 0x20000080) >>  7) |
1195            ( $block[0] & 0x00200000       ) | (($block[1] & 0x00200000) >>  1) |
1196            (($block[0] & 0x00002000) <<  6) | (($block[1] & 0x00002000) <<  5) |
1197            (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) |
1198            (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) |
1199            (($block[0] & 0x00400000) >>  9) | (($block[1] & 0x00400000) >> 10) |
1200            (($block[0] & 0x00004000) >>  3) | (($block[1] & 0x00004000) >>  4) |
1201            (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) |
1202            (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) |
1203            ($msb[0] <<  7) | ($msb[1] <<  6)
1204        );
1205
1206        return pack('NN', $block[0], $block[1]);
1207    }
1208
1209    /**
1210     * Creates the key schedule.
1211     *
1212     * @access private
1213     * @param String $key
1214     * @return Array
1215     */
1216    function _prepareKey($key)
1217    {
1218        static $shifts = array( // number of key bits shifted per round
1219            1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
1220        );
1221
1222        // pad the key and remove extra characters as appropriate.
1223        $key = str_pad(substr($key, 0, 8), 8, chr(0));
1224
1225        $temp = unpack('Na/Nb', $key);
1226        $key = array($temp['a'], $temp['b']);
1227        $msb = array(
1228            ($key[0] >> 31) & 1,
1229            ($key[1] >> 31) & 1
1230        );
1231        $key[0] &= 0x7FFFFFFF;
1232        $key[1] &= 0x7FFFFFFF;
1233
1234        $key = array(
1235            (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) |
1236            (($key[1] & 0x00020408) <<  8) | (($key[1] & 0x02040800) >>  1) |
1237            (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) |
1238            (($key[0] & 0x00020408) <<  4) | (($key[0] & 0x02040800) >>  5) |
1239            (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) |
1240            (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) |
1241            (($key[0] & 0x00000010) >>  1) | (($key[0] & 0x00001000) >> 10) |
1242            (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28)
1243        ,
1244            (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) |
1245            (($key[1] & 0x00800000) <<  2) | (($key[0] & 0x00000080) << 16) |
1246            (($key[0] & 0x00008000) <<  7) | (($key[0] & 0x00800000) >>  2) |
1247            (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) <<  4) |
1248            (($key[1] & 0x00400000) >>  5) | (($key[1] & 0x40000000) >> 14) |
1249            (($key[0] & 0x00000040) <<  9) | ( $key[0] & 0x00004000       ) |
1250            (($key[0] & 0x00400000) >>  9) | (($key[0] & 0x40000000) >> 18) |
1251            (($key[1] & 0x00000020) <<  6) | (($key[1] & 0x00002000) >>  3) |
1252            (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) |
1253            (($key[0] & 0x00000020) <<  2) | (($key[0] & 0x00002000) >>  7) |
1254            (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) |
1255            (($key[1] & 0x00000010) >>  1) | (($key[1] & 0x00001000) >> 10) |
1256            (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) |
1257            ($msb[1] << 24) | ($msb[0] << 20)
1258        ); 
1259
1260        $keys = array();
1261        for ($i = 0; $i < 16; $i++) {
1262            $key[0] <<= $shifts[$i];
1263            $temp = ($key[0] & 0xF0000000) >> 28;
1264            $key[0] = ($key[0] | $temp) & 0x0FFFFFFF;
1265
1266            $key[1] <<= $shifts[$i…

Large files files are truncated, but you can click here to view the full file