PageRenderTime 90ms CodeModel.GetById 26ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/phpseclib/Crypt/Rijndael.php

https://github.com/kea/phpseclib
PHP | 1476 lines | 830 code | 108 blank | 538 comment | 106 complexity | b3d9f0e1c9771c4a339cf456803d0ca2 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 Rijndael.
   6 *
   7 * Does not use mcrypt, even when available, for reasons that are explained below.
   8 *
   9 * PHP versions 4 and 5
  10 *
  11 * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits.  If
  12 * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
  13 * {@link Crypt_Rijndael::setKey() setKey()}.  ie. if the key is 128-bits, the key length will be 128-bits.  If it's
  14 * 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until
  15 * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
  16 *
  17 * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length.  mcrypt, for example,
  18 * does not.  AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
  19 * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
  20 * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224.  Indeed, 160 and 224
  21 * are first defined as valid key / block lengths in
  22 * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
  23 * Extensions: Other block and Cipher Key lengths.
  24 *
  25 * {@internal The variable names are the same as those in
  26 * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
  27 *
  28 * Here's a short example of how to use this library:
  29 * <code>
  30 * <?php
  31 *    include('Crypt/Rijndael.php');
  32 *
  33 *    $rijndael = new Crypt_Rijndael();
  34 *
  35 *    $rijndael->setKey('abcdefghijklmnop');
  36 *
  37 *    $size = 10 * 1024;
  38 *    $plaintext = '';
  39 *    for ($i = 0; $i < $size; $i++) {
  40 *        $plaintext.= 'a';
  41 *    }
  42 *
  43 *    echo $rijndael->decrypt($rijndael->encrypt($plaintext));
  44 * ?>
  45 * </code>
  46 *
  47 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  48 * of this software and associated documentation files (the "Software"), to deal
  49 * in the Software without restriction, including without limitation the rights
  50 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  51 * copies of the Software, and to permit persons to whom the Software is
  52 * furnished to do so, subject to the following conditions:
  53 *
  54 * The above copyright notice and this permission notice shall be included in
  55 * all copies or substantial portions of the Software.
  56 *
  57 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  58 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  59 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  60 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  61 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  62 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  63 * THE SOFTWARE.
  64 *
  65 * @category   Crypt
  66 * @package    Crypt_Rijndael
  67 * @author     Jim Wigginton <terrafrost@php.net>
  68 * @copyright  MMVIII Jim Wigginton
  69 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
  70 * @version    $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
  71 * @link       http://phpseclib.sourceforge.net
  72 */
  73
  74namespace phpseclib;
  75
  76/**
  77 * Pure-PHP implementation of Rijndael.
  78 *
  79 * @author  Jim Wigginton <terrafrost@php.net>
  80 * @version 0.1.0
  81 * @access  public
  82 * @package Crypt_Rijndael
  83 */
  84class Crypt_Rijndael {
  85    /**#@+
  86     * @access public
  87     * @see Crypt_Rijndael::encrypt()
  88     * @see Crypt_Rijndael::decrypt()
  89     */
  90    /**
  91     * Encrypt / decrypt using the Counter mode.
  92     *
  93     * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
  94     *
  95     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
  96     */
  97    const MODE_CTR = -1;
  98    /**
  99     * Encrypt / decrypt using the Electronic Code Book mode.
 100     *
 101     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
 102     */
 103    const MODE_ECB = 1;
 104    /**
 105     * Encrypt / decrypt using the Code Book Chaining mode.
 106     *
 107     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
 108     */
 109    const MODE_CBC = 2;
 110    /**
 111     * Encrypt / decrypt using the Cipher Feedback mode.
 112     *
 113     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
 114     */
 115    const MODE_CFB = 3;
 116    /**
 117     * Encrypt / decrypt using the Cipher Feedback mode.
 118     *
 119     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
 120     */
 121    const MODE_OFB = 4;
 122    /**#@-*/
 123
 124    /**#@+
 125     * @access private
 126     * @see Crypt_Rijndael::Crypt_Rijndael()
 127     */
 128    /**
 129     * Toggles the internal implementation
 130     */
 131    const MODE_INTERNAL = 1;
 132    /**
 133     * Toggles the mcrypt implementation
 134     */
 135    const MODE_MCRYPT = 2;
 136    /**#@-*/
 137
 138    /**
 139     * The Encryption Mode
 140     *
 141     * @see Crypt_Rijndael::Crypt_Rijndael()
 142     * @var Integer
 143     * @access private
 144     */
 145    var $mode;
 146
 147    /**
 148     * The Key
 149     *
 150     * @see Crypt_Rijndael::setKey()
 151     * @var String
 152     * @access private
 153     */
 154    var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
 155
 156    /**
 157     * The Initialization Vector
 158     *
 159     * @see Crypt_Rijndael::setIV()
 160     * @var String
 161     * @access private
 162     */
 163    var $iv = '';
 164
 165    /**
 166     * A "sliding" Initialization Vector
 167     *
 168     * @see Crypt_Rijndael::enableContinuousBuffer()
 169     * @var String
 170     * @access private
 171     */
 172    var $encryptIV = '';
 173
 174    /**
 175     * A "sliding" Initialization Vector
 176     *
 177     * @see Crypt_Rijndael::enableContinuousBuffer()
 178     * @var String
 179     * @access private
 180     */
 181    var $decryptIV = '';
 182
 183    /**
 184     * Continuous Buffer status
 185     *
 186     * @see Crypt_Rijndael::enableContinuousBuffer()
 187     * @var Boolean
 188     * @access private
 189     */
 190    var $continuousBuffer = false;
 191
 192    /**
 193     * Padding status
 194     *
 195     * @see Crypt_Rijndael::enablePadding()
 196     * @var Boolean
 197     * @access private
 198     */
 199    var $padding = true;
 200
 201    /**
 202     * Does the key schedule need to be (re)calculated?
 203     *
 204     * @see setKey()
 205     * @see setBlockLength()
 206     * @see setKeyLength()
 207     * @var Boolean
 208     * @access private
 209     */
 210    var $changed = true;
 211
 212    /**
 213     * Has the key length explicitly been set or should it be derived from the key, itself?
 214     *
 215     * @see setKeyLength()
 216     * @var Boolean
 217     * @access private
 218     */
 219    var $explicit_key_length = false;
 220
 221    /**
 222     * The Key Schedule
 223     *
 224     * @see _setup()
 225     * @var Array
 226     * @access private
 227     */
 228    var $w;
 229
 230    /**
 231     * The Inverse Key Schedule
 232     *
 233     * @see _setup()
 234     * @var Array
 235     * @access private
 236     */
 237    var $dw;
 238
 239    /**
 240     * The Block Length
 241     *
 242     * @see setBlockLength()
 243     * @var Integer
 244     * @access private
 245     * @internal The max value is 32, the min value is 16.  All valid values are multiples of 4.  Exists in conjunction with
 246     *     $Nb because we need this value and not $Nb to pad strings appropriately.
 247     */
 248    var $block_size = 16;
 249
 250    /**
 251     * The Block Length divided by 32
 252     *
 253     * @see setBlockLength()
 254     * @var Integer
 255     * @access private
 256     * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4.  Exists in conjunction with $block_size
 257     *    because the encryption / decryption / key schedule creation requires this number and not $block_size.  We could
 258     *    derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
 259     *    of that, we'll just precompute it once.
 260     *
 261     */
 262    var $Nb = 4;
 263
 264    /**
 265     * The Key Length
 266     *
 267     * @see setKeyLength()
 268     * @var Integer
 269     * @access private
 270     * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $key_size
 271     *    because the encryption / decryption / key schedule creation requires this number and not $key_size.  We could
 272     *    derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
 273     *    of that, we'll just precompute it once.
 274     */
 275    var $key_size = 16;
 276
 277    /**
 278     * The Key Length divided by 32
 279     *
 280     * @see setKeyLength()
 281     * @var Integer
 282     * @access private
 283     * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
 284     */
 285    var $Nk = 4;
 286
 287    /**
 288     * The Number of Rounds
 289     *
 290     * @var Integer
 291     * @access private
 292     * @internal The max value is 14, the min value is 10.
 293     */
 294    var $Nr;
 295
 296    /**
 297     * Shift offsets
 298     *
 299     * @var Array
 300     * @access private
 301     */
 302    var $c;
 303
 304    /**
 305     * Precomputed mixColumns table
 306     *
 307     * @see Crypt_Rijndael()
 308     * @var Array
 309     * @access private
 310     */
 311    var $t0;
 312
 313    /**
 314     * Precomputed mixColumns table
 315     *
 316     * @see Crypt_Rijndael()
 317     * @var Array
 318     * @access private
 319     */
 320    var $t1;
 321
 322    /**
 323     * Precomputed mixColumns table
 324     *
 325     * @see Crypt_Rijndael()
 326     * @var Array
 327     * @access private
 328     */
 329    var $t2;
 330
 331    /**
 332     * Precomputed mixColumns table
 333     *
 334     * @see Crypt_Rijndael()
 335     * @var Array
 336     * @access private
 337     */
 338    var $t3;
 339
 340    /**
 341     * Precomputed invMixColumns table
 342     *
 343     * @see Crypt_Rijndael()
 344     * @var Array
 345     * @access private
 346     */
 347    var $dt0;
 348
 349    /**
 350     * Precomputed invMixColumns table
 351     *
 352     * @see Crypt_Rijndael()
 353     * @var Array
 354     * @access private
 355     */
 356    var $dt1;
 357
 358    /**
 359     * Precomputed invMixColumns table
 360     *
 361     * @see Crypt_Rijndael()
 362     * @var Array
 363     * @access private
 364     */
 365    var $dt2;
 366
 367    /**
 368     * Precomputed invMixColumns table
 369     *
 370     * @see Crypt_Rijndael()
 371     * @var Array
 372     * @access private
 373     */
 374    var $dt3;
 375
 376    /**
 377     * Is the mode one that is paddable?
 378     *
 379     * @see Crypt_Rijndael::Crypt_Rijndael()
 380     * @var Boolean
 381     * @access private
 382     */
 383    var $paddable = false;
 384
 385    /**
 386     * Encryption buffer for CTR, OFB and CFB modes
 387     *
 388     * @see Crypt_Rijndael::encrypt()
 389     * @var String
 390     * @access private
 391     */
 392    var $enbuffer = array('encrypted' => '', 'xor' => '');
 393
 394    /**
 395     * Decryption buffer for CTR, OFB and CFB modes
 396     *
 397     * @see Crypt_Rijndael::decrypt()
 398     * @var String
 399     * @access private
 400     */
 401    var $debuffer = array('ciphertext' => '');
 402
 403    /**
 404     * Default Constructor.
 405     *
 406     * Determines whether or not the mcrypt extension should be used.  $mode should only, at present, be
 407     * self::MODE_ECB or self::MODE_CBC.  If not explictly set, self::MODE_CBC will be used.
 408     *
 409     * @param optional Integer $mode
 410     * @return Crypt_Rijndael
 411     * @access public
 412     */
 413    function __construct($mode = self::MODE_CBC)
 414    {
 415        switch ($mode) {
 416            case self::MODE_ECB:
 417            case self::MODE_CBC:
 418                $this->paddable = true;
 419                $this->mode = $mode;
 420                break;
 421            case self::MODE_CTR:
 422            case self::MODE_CFB:
 423            case self::MODE_OFB:
 424                $this->mode = $mode;
 425                break;
 426            default:
 427                $this->paddable = true;
 428                $this->mode = self::MODE_CBC;
 429        }
 430
 431        $t3 = &$this->t3;
 432        $t2 = &$this->t2;
 433        $t1 = &$this->t1;
 434        $t0 = &$this->t0;
 435
 436        $dt3 = &$this->dt3;
 437        $dt2 = &$this->dt2;
 438        $dt1 = &$this->dt1;
 439        $dt0 = &$this->dt0;
 440
 441        // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
 442        // precomputed tables can be used in the mixColumns phase.  in that example, they're assigned t0...t3, so
 443        // those are the names we'll use.
 444        $t3 = array(
 445                0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
 446                0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
 447                0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
 448                0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
 449                0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
 450                0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
 451                0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
 452                0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
 453                0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
 454                0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
 455                0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
 456                0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
 457                0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
 458                0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
 459                0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
 460                0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
 461                0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
 462                0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
 463                0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
 464                0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
 465                0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
 466                0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
 467                0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
 468                0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
 469                0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
 470                0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
 471                0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
 472                0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
 473                0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
 474                0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
 475                0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
 476                0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
 477                    );
 478
 479        $dt3 = array(
 480                0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
 481                0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
 482                0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
 483                0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
 484                0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
 485                0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
 486                0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
 487                0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
 488                0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
 489                0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
 490                0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
 491                0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
 492                0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
 493                0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
 494                0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
 495                0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
 496                0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
 497                0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
 498                0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
 499                0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
 500                0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
 501                0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
 502                0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
 503                0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
 504                0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
 505                0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
 506                0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
 507                0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
 508                0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
 509                0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
 510                0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
 511                0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
 512                    );
 513
 514        for ($i = 0; $i < 256; $i++) {
 515            $t2[$i <<  8] = (($t3[$i] <<  8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
 516            $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
 517            $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >>  8) & 0x00FFFFFF);
 518
 519            $dt2[$i <<  8] = (($this->dt3[$i] <<  8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
 520            $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
 521            $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >>  8) & 0x00FFFFFF);
 522        }
 523    }
 524
 525    /**
 526     * Sets the key.
 527     *
 528     * Keys can be of any length.  Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
 529     * 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
 530     * up to the closest valid key length, padding $key with null bytes.  If the key is more than 256-bits, we trim the
 531     * excess bits.
 532     *
 533     * If the key is not explicitly set, it'll be assumed to be all null bytes.
 534     *
 535     * @access public
 536     * @param String $key
 537     */
 538    function setKey($key)
 539    {
 540        $this->key = $key;
 541        $this->changed = true;
 542    }
 543
 544    /**
 545     * Sets the initialization vector. (optional)
 546     *
 547     * SetIV is not required when self::MODE_ECB is being used.  If not explictly set, it'll be assumed
 548     * to be all zero's.
 549     *
 550     * @access public
 551     * @param String $iv
 552     */
 553    function setIV($iv)
 554    {
 555        $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));
 556    }
 557
 558    /**
 559     * Sets the key length
 560     *
 561     * Valid key lengths are 128, 160, 192, 224, and 256.  If the length is less than 128, it will be rounded up to
 562     * 128.  If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
 563     *
 564     * @access public
 565     * @param Integer $length
 566     */
 567    function setKeyLength($length)
 568    {
 569        $length >>= 5;
 570        if ($length > 8) {
 571            $length = 8;
 572        } else if ($length < 4) {
 573            $length = 4;
 574        }
 575        $this->Nk = $length;
 576        $this->key_size = $length << 2;
 577
 578        $this->explicit_key_length = true;
 579        $this->changed = true;
 580    }
 581
 582    /**
 583     * Sets the password.
 584     *
 585     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
 586     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
 587     *         $hash, $salt, $count
 588     *     Set $dkLen by calling setKeyLength()
 589     *
 590     * @param String $password
 591     * @param optional String $method
 592     * @access public
 593     */
 594    function setPassword($password, $method = 'pbkdf2')
 595    {
 596        $key = '';
 597
 598        switch ($method) {
 599            default: // 'pbkdf2'
 600                //not the prettiest thing ever, but solves the undefined index issue with list()
 601                $args = func_get_args();
 602                $hash = 'sha1';
 603                $salt = 'phpseclib/salt';
 604                $count = 1000;
 605                switch(count($args)){
 606                    case 6:
 607                    case 5:
 608                        $count = $args[4];
 609                    case 4:
 610                        $salt = $args[3];
 611                    case 3:
 612                        $hash = $args[2];
 613                }
 614                $i = 1;
 615                while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size
 616                    //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
 617                    $hmac = new Crypt_Hash();
 618                    $hmac->setHash($hash);
 619                    $hmac->setKey($password);
 620                    $f = $u = $hmac->hash($salt . pack('N', $i++));
 621                    for ($j = 2; $j <= $count; $j++) {
 622                        $u = $hmac->hash($u);
 623                        $f^= $u;
 624                    }
 625                    $key.= $f;
 626                }
 627        }
 628
 629        $this->setKey(substr($key, 0, $this->key_size));
 630    }
 631
 632    /**
 633     * Sets the block length
 634     *
 635     * Valid block lengths are 128, 160, 192, 224, and 256.  If the length is less than 128, it will be rounded up to
 636     * 128.  If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
 637     *
 638     * @access public
 639     * @param Integer $length
 640     */
 641    function setBlockLength($length)
 642    {
 643        $length >>= 5;
 644        if ($length > 8) {
 645            $length = 8;
 646        } else if ($length < 4) {
 647            $length = 4;
 648        }
 649        $this->Nb = $length;
 650        $this->block_size = $length << 2;
 651        $this->changed = true;
 652    }
 653
 654    /**
 655     * Generate CTR XOR encryption key
 656     *
 657     * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
 658     * plaintext / ciphertext in CTR mode.
 659     *
 660     * @see Crypt_Rijndael::decrypt()
 661     * @see Crypt_Rijndael::encrypt()
 662     * @access public
 663     * @param Integer $length
 664     * @param String $iv
 665     */
 666    function _generate_xor($length, &$iv)
 667    {
 668        $xor = '';
 669        $block_size = $this->block_size;
 670        $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
 671        for ($i = 0; $i < $num_blocks; $i++) {
 672            $xor.= $iv;
 673            for ($j = 4; $j <= $block_size; $j+=4) {
 674                $temp = substr($iv, -$j, 4);
 675                switch ($temp) {
 676                    case "\xFF\xFF\xFF\xFF":
 677                        $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
 678                    break;
 679                    case "\x7F\xFF\xFF\xFF":
 680                        $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
 681                    break 2;
 682                    default:
 683                    extract(unpack('Ncount', $temp));
 684                    $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
 685                    break 2;
 686                }
 687            }
 688        }
 689
 690        return $xor;
 691    }
 692
 693    /**
 694     * Encrypts a message.
 695     *
 696     * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size.  Other Rjindael
 697     * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
 698     * necessary are discussed in the following
 699     * URL:
 700     *
 701     * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
 702     *
 703     * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
 704     * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
 705     * length.
 706     *
 707     * @see Crypt_Rijndael::decrypt()
 708     * @access public
 709     * @param String $plaintext
 710     */
 711    function encrypt($plaintext)
 712    {
 713        $this->_setup();
 714        if ($this->paddable) {
 715            $plaintext = $this->_pad($plaintext);
 716        }
 717
 718        $block_size = $this->block_size;
 719        $buffer = &$this->enbuffer;
 720        $continuousBuffer = $this->continuousBuffer;
 721        $ciphertext = '';
 722        switch ($this->mode) {
 723            case self::MODE_ECB:
 724                for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 725                    $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
 726                }
 727                break;
 728            case self::MODE_CBC:
 729                $xor = $this->encryptIV;
 730                for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 731                    $block = substr($plaintext, $i, $block_size);
 732                    $block = $this->_encryptBlock($block ^ $xor);
 733                    $xor = $block;
 734                    $ciphertext.= $block;
 735                }
 736                if ($this->continuousBuffer) {
 737                    $this->encryptIV = $xor;
 738                }
 739                break;
 740            case self::MODE_CTR:
 741                $xor = $this->encryptIV;
 742                if (!empty($buffer['encrypted'])) {
 743                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 744                        $block = substr($plaintext, $i, $block_size);
 745                        $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
 746                        $key = $this->_string_shift($buffer['encrypted'], $block_size);
 747                        $ciphertext.= $block ^ $key;
 748                    }
 749                } else {
 750                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 751                        $block = substr($plaintext, $i, $block_size);
 752                        $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
 753                        $ciphertext.= $block ^ $key;
 754                    }
 755                }
 756                if ($this->continuousBuffer) {
 757                    $this->encryptIV = $xor;
 758                    if ($start = strlen($plaintext) % $block_size) {
 759                        $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
 760                    }
 761                }
 762                break;
 763            case self::MODE_CFB:
 764                if (!empty($buffer['xor'])) {
 765                    $ciphertext = $plaintext ^ $buffer['xor'];
 766                    $iv = $buffer['encrypted'] . $ciphertext;
 767                    $start = strlen($ciphertext);
 768                    $buffer['encrypted'].= $ciphertext;
 769                    $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
 770                } else {
 771                    $ciphertext = '';
 772                    $iv = $this->encryptIV;
 773                    $start = 0;
 774                }
 775
 776                for ($i = $start; $i < strlen($plaintext); $i+=$block_size) {
 777                    $block = substr($plaintext, $i, $block_size);
 778                    $xor = $this->_encryptBlock($iv);
 779                    $iv = $block ^ $xor;
 780                    if ($continuousBuffer && strlen($iv) != $block_size) {
 781                        $buffer = array(
 782                                'encrypted' => $iv,
 783                                'xor' => substr($xor, strlen($iv))
 784                                );
 785                    }
 786                    $ciphertext.= $iv;
 787                }
 788
 789                if ($this->continuousBuffer) {
 790                    $this->encryptIV = $iv;
 791                }
 792                break;
 793            case self::MODE_OFB:
 794                $xor = $this->encryptIV;
 795                if (is_string($buffer) && strlen($buffer)) {
 796                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 797                        $xor = $this->_encryptBlock($xor);
 798                        $buffer.= $xor;
 799                        $key = $this->_string_shift($buffer, $block_size);
 800                        $ciphertext.= substr($plaintext, $i, $block_size) ^ $key;
 801                    }
 802                } else {
 803                    for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
 804                        $xor = $this->_encryptBlock($xor);
 805                        $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
 806                    }
 807                    $key = $xor;
 808                }
 809                if ($this->continuousBuffer) {
 810                    $this->encryptIV = $xor;
 811                    if ($start = strlen($plaintext) % $block_size) {
 812                        $buffer = substr($key, $start) . $buffer;
 813                    }
 814                }
 815        }
 816
 817        return $ciphertext;
 818    }
 819
 820    /**
 821     * Decrypts a message.
 822     *
 823     * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
 824     * it is.
 825     *
 826     * @see Crypt_Rijndael::encrypt()
 827     * @access public
 828     * @param String $ciphertext
 829     */
 830    function decrypt($ciphertext)
 831    {
 832        $this->_setup();
 833
 834        if ($this->paddable) {
 835            // we pad with chr(0) since that's what mcrypt_generic does.  to quote from http://php.net/function.mcrypt-generic :
 836            // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
 837            $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
 838        }
 839
 840        $block_size = $this->block_size;
 841        $buffer = &$this->debuffer;
 842        $continuousBuffer = $this->continuousBuffer;
 843        $plaintext = '';
 844        switch ($this->mode) {
 845            case self::MODE_ECB:
 846                for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 847                    $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
 848                }
 849                break;
 850            case self::MODE_CBC:
 851                $xor = $this->decryptIV;
 852                for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 853                    $block = substr($ciphertext, $i, $block_size);
 854                    $plaintext.= $this->_decryptBlock($block) ^ $xor;
 855                    $xor = $block;
 856                }
 857                if ($this->continuousBuffer) {
 858                    $this->decryptIV = $xor;
 859                }
 860                break;
 861            case self::MODE_CTR:
 862                $xor = $this->decryptIV;
 863                if (!empty($buffer['ciphertext'])) {
 864                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 865                        $block = substr($ciphertext, $i, $block_size);
 866                        $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
 867                        $key = $this->_string_shift($buffer['ciphertext'], $block_size);
 868                        $plaintext.= $block ^ $key;
 869                    }
 870                } else {
 871                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 872                        $block = substr($ciphertext, $i, $block_size);
 873                        $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
 874                        $plaintext.= $block ^ $key;
 875                    }
 876                }
 877                if ($this->continuousBuffer) {
 878                    $this->decryptIV = $xor;
 879                    if ($start = strlen($ciphertext) % $block_size) {
 880                        $buffer['ciphertext'] = substr($key, $start) . $buffer['encrypted'];
 881                    }
 882                }
 883                break;
 884            case self::MODE_CFB:
 885                if (!empty($buffer['ciphertext'])) {
 886                    $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
 887                    $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
 888                    if (strlen($buffer['ciphertext']) == $block_size) {
 889                        $xor = $this->_encryptBlock($buffer['ciphertext']);
 890                        $buffer['ciphertext'] = '';
 891                    }
 892                    $start = strlen($plaintext);
 893                    $block = $this->decryptIV;
 894                } else {
 895                    $plaintext = '';
 896                    $xor = $this->_encryptBlock($this->decryptIV);
 897                    $start = 0;
 898                }
 899
 900                for ($i = $start; $i < strlen($ciphertext); $i+=$block_size) {
 901                    $block = substr($ciphertext, $i, $block_size);
 902                    $plaintext.= $block ^ $xor;
 903                    if ($continuousBuffer && strlen($block) != $block_size) {
 904                        $buffer['ciphertext'].= $block;
 905                        $block = $xor;
 906                    } else if (strlen($block) == $block_size) {
 907                        $xor = $this->_encryptBlock($block);
 908                    }
 909                }
 910                if ($this->continuousBuffer) {
 911                    $this->decryptIV = $block;
 912                }
 913                break;
 914            case self::MODE_OFB:
 915                $xor = $this->decryptIV;
 916                if (is_string($buffer) && strlen($buffer)) {
 917                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 918                        $xor = $this->_encryptBlock($xor);
 919                        $buffer.= $xor;
 920                        $key = $this->_string_shift($buffer, $block_size);
 921                        $plaintext.= substr($ciphertext, $i, $block_size) ^ $key;
 922                    }
 923                } else {
 924                    for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
 925                        $xor = $this->_encryptBlock($xor);
 926                        $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
 927                    }
 928                    $key = $xor;
 929                }
 930                if ($this->continuousBuffer) {
 931                    $this->decryptIV = $xor;
 932                    if ($start = strlen($ciphertext) % $block_size) {
 933                        $buffer = substr($key, $start) . $buffer;
 934                    }
 935                }
 936        }
 937
 938        return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
 939    }
 940
 941    /**
 942     * Encrypts a block
 943     *
 944     * @access private
 945     * @param String $in
 946     * @return String
 947     */
 948    function _encryptBlock($in)
 949    {
 950        $state = array();
 951        $words = unpack('N*word', $in);
 952
 953        $w = $this->w;
 954        $t0 = $this->t0;
 955        $t1 = $this->t1;
 956        $t2 = $this->t2;
 957        $t3 = $this->t3;
 958        $Nb = $this->Nb;
 959        $Nr = $this->Nr;
 960        $c = $this->c;
 961
 962        // addRoundKey
 963        $i = 0;
 964        foreach ($words as $word) {
 965            $state[] = $word ^ $w[0][$i++];
 966        }
 967
 968        // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
 969        // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
 970        // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
 971        // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
 972        // Unfortunately, the description given there is not quite correct.  Per aes.spec.v316.pdf#page=19 [1],
 973        // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
 974
 975        // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
 976        $temp = array();
 977        for ($round = 1; $round < $Nr; $round++) {
 978            $i = 0; // $c[0] == 0
 979            $j = $c[1];
 980            $k = $c[2];
 981            $l = $c[3];
 982
 983            while ($i < $this->Nb) {
 984                $temp[$i] = $t0[$state[$i] & 0xFF000000] ^
 985                    $t1[$state[$j] & 0x00FF0000] ^
 986                    $t2[$state[$k] & 0x0000FF00] ^
 987                    $t3[$state[$l] & 0x000000FF] ^
 988                    $w[$round][$i];
 989                $i++;
 990                $j = ($j + 1) % $Nb;
 991                $k = ($k + 1) % $Nb;
 992                $l = ($l + 1) % $Nb;
 993            }
 994
 995            for ($i = 0; $i < $Nb; $i++) {
 996                $state[$i] = $temp[$i];
 997            }
 998        }
 999
1000        // subWord
1001        for ($i = 0; $i < $Nb; $i++) {
1002            $state[$i] = $this->_subWord($state[$i]);
1003        }
1004
1005        // shiftRows + addRoundKey
1006        $i = 0; // $c[0] == 0
1007        $j = $c[1];
1008        $k = $c[2];
1009        $l = $c[3];
1010        while ($i < $this->Nb) {
1011            $temp[$i] = ($state[$i] & 0xFF000000) ^
1012                ($state[$j] & 0x00FF0000) ^
1013                ($state[$k] & 0x0000FF00) ^
1014                ($state[$l] & 0x000000FF) ^
1015                $w[$Nr][$i];
1016            $i++;
1017            $j = ($j + 1) % $Nb;
1018            $k = ($k + 1) % $Nb;
1019            $l = ($l + 1) % $Nb;
1020        }
1021        $state = $temp;
1022
1023        array_unshift($state, 'N*');
1024
1025        return call_user_func_array('pack', $state);
1026    }
1027
1028    /**
1029     * Decrypts a block
1030     *
1031     * @access private
1032     * @param String $in
1033     * @return String
1034     */
1035    function _decryptBlock($in)
1036    {
1037        $state = array();
1038        $words = unpack('N*word', $in);
1039
1040        $num_states = count($state);
1041        $dw = $this->dw;
1042        $dt0 = $this->dt0;
1043        $dt1 = $this->dt1;
1044        $dt2 = $this->dt2;
1045        $dt3 = $this->dt3;
1046        $Nb = $this->Nb;
1047        $Nr = $this->Nr;
1048        $c = $this->c;
1049
1050        // addRoundKey
1051        $i = 0;
1052        foreach ($words as $word) {
1053            $state[] = $word ^ $dw[$Nr][$i++];
1054        }
1055
1056        $temp = array();
1057        for ($round = $Nr - 1; $round > 0; $round--) {
1058            $i = 0; // $c[0] == 0
1059            $j = $Nb - $c[1];
1060            $k = $Nb - $c[2];
1061            $l = $Nb - $c[3];
1062
1063            while ($i < $Nb) {
1064                $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^
1065                    $dt1[$state[$j] & 0x00FF0000] ^
1066                    $dt2[$state[$k] & 0x0000FF00] ^
1067                    $dt3[$state[$l] & 0x000000FF] ^
1068                    $dw[$round][$i];
1069                $i++;
1070                $j = ($j + 1) % $Nb;
1071                $k = ($k + 1) % $Nb;
1072                $l = ($l + 1) % $Nb;
1073            }
1074
1075            for ($i = 0; $i < $Nb; $i++) {
1076                $state[$i] = $temp[$i];
1077            }
1078        }
1079
1080        // invShiftRows + invSubWord + addRoundKey
1081        $i = 0; // $c[0] == 0
1082        $j = $Nb - $c[1];
1083        $k = $Nb - $c[2];
1084        $l = $Nb - $c[3];
1085
1086        while ($i < $Nb) {
1087            $temp[$i] = $dw[0][$i] ^
1088                $this->_invSubWord(($state[$i] & 0xFF000000) |
1089                        ($state[$j] & 0x00FF0000) |
1090                        ($state[$k] & 0x0000FF00) |
1091                        ($state[$l] & 0x000000FF));
1092            $i++;
1093            $j = ($j + 1) % $Nb;
1094            $k = ($k + 1) % $Nb;
1095            $l = ($l + 1) % $Nb;
1096        }
1097
1098        $state = $temp;
1099
1100        array_unshift($state, 'N*');
1101
1102        return call_user_func_array('pack', $state);
1103    }
1104
1105    /**
1106     * Setup Rijndael
1107     *
1108     * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
1109     * key schedule.
1110     *
1111     * @access private
1112     */
1113    function _setup()
1114    {
1115        // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
1116        // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
1117        static $rcon = array(0,
1118                0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
1119                0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
1120                0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
1121                0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
1122                0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
1123                0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
1124                );
1125
1126        if (!$this->changed) {
1127            return;
1128        }
1129
1130        if (!$this->explicit_key_length) {
1131            // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
1132            $length = strlen($this->key) >> 2;
1133            if ($length > 8) {
1134                $length = 8;
1135            } else if ($length < 4) {
1136                $length = 4;
1137            }
1138            $this->Nk = $length;
1139            $this->key_size = $length << 2;
1140        }
1141
1142        $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
1143        $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
1144
1145        // see Rijndael-ammended.pdf#page=44
1146        $this->Nr = max($this->Nk, $this->Nb) + 6;
1147
1148        // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
1149        //     "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
1150        // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
1151        //     "Table 2: Shift offsets for different block lengths"
1152        switch ($this->Nb) {
1153            case 4:
1154            case 5:
1155            case 6:
1156                $this->c = array(0, 1, 2, 3);
1157                break;
1158            case 7:
1159                $this->c = array(0, 1, 2, 4);
1160                break;
1161            case 8:
1162                $this->c = array(0, 1, 3, 4);
1163        }
1164
1165        $key = $this->key;
1166
1167        $w = array_values(unpack('N*words', $key));
1168
1169        $length = $this->Nb * ($this->Nr + 1);
1170        for ($i = $this->Nk; $i < $length; $i++) {
1171            $temp = $w[$i - 1];
1172            if ($i % $this->Nk == 0) {
1173                // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
1174                // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
1175                // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
1176                // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
1177                $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
1178                $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
1179            } else if ($this->Nk > 6 && $i % $this->Nk == 4) {
1180                $temp = $this->_subWord($temp);
1181            }
1182            $w[$i] = $w[$i - $this->Nk] ^ $temp;
1183        }
1184
1185        // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
1186        // and generate the inverse key schedule.  more specifically,
1187        // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
1188        // "The key expansion for the Inverse Cipher is defined as follows:
1189        //        1. Apply the Key Expansion.
1190        //        2. Apply InvMixColumn to all Round Keys except the first and the last one."
1191        // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
1192        $temp = array();
1193        for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
1194            if ($col == $this->Nb) {
1195                if ($row == 0) {
1196                    $this->dw[0] = $this->w[0];
1197                } else {
1198                    // subWord + invMixColumn + invSubWord = invMixColumn
1199                    $j = 0;
1200                    while ($j < $this->Nb) {
1201                        $dw = $this->_subWord($this->w[$row][$j]);
1202                        $temp[$j] = $this->dt0[$dw & 0xFF000000] ^
1203                            $this->dt1[$dw & 0x00FF0000] ^
1204                            $this->dt2[$dw & 0x0000FF00] ^
1205                            $this->dt3[$dw & 0x000000FF];
1206                        $j++;
1207                    }
1208                    $this->dw[$row] = $temp;
1209                }
1210
1211                $col = 0;
1212                $row++;
1213            }
1214            $this->w[$row][$col] = $w[$i];
1215        }
1216
1217        $this->dw[$row] = $this->w[$row];
1218
1219        $this->changed = false;
1220    }
1221
1222    /**
1223     * Performs S-Box substitutions
1224     *
1225     * @access private
1226     */
1227    function _subWord($word)
1228    {
1229        static $sbox0, $sbox1, $sbox2, $sbox3;
1230
1231        if (empty($sbox0)) {
1232            $sbox0 = array(
1233                    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
1234                    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
1235                    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
1236                    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
1237                    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
1238                    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
1239                    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
1240                    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
1241                    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
1242                    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
1243                    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
1244                    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
1245                    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
1246                    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
1247                    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
1248                    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
1249                    );
1250
1251            $sbox1 = array();
1252            $sbox2 = array();
1253            $sbox3 = array();
1254
1255            for ($i = 0; $i < 256; $i++) {
1256                $sbox1[$i <<  8] = $sbox0[$i] <<  8;
1257                $sbox2[$i << 16] = $sbox0[$i] << 16;
1258                $sbox3[$i << 24] = $sbox0[$i] << 24;
1259            }
1260        }
1261
1262        return $sbox0[$word & 0x000000FF] |
1263            $sbox1[$word & 0x0000FF00] |
1264            $sbox2[$word & 0x00FF0000] |
1265            $sbox3[$word & 0xFF000000];
1266    }
1267
1268    /**
1269     * Performs inverse S-Box substitutions
1270     *
1271     * @access private
1272     */
1273    function _invSubWord($word)
1274    {
1275        static $sbox0, $sbox1, $sbox2, $sbox3;
1276
1277        if (empty($sbox0)) {
1278            $sbox0 = array(
1279                    0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
1280                    0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
1281                    0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
1282                    0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
1283                    0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
1284                    0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0

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