[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/ -> Rijndael.php (source)

   1  <?php
   2  
   3  /**
   4   * Pure-PHP implementation of Rijndael.
   5   *
   6   * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
   7   *
   8   * PHP version 5
   9   *
  10   * If {@link self::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits.  If
  11   * {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
  12   * {@link self::setKey() setKey()}.  ie. if the key is 128-bits, the key length will be 128-bits.  If it's
  13   * 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until
  14   * {@link self::setKey() setKey()} is called, again, at which point, it'll be recalculated.
  15   *
  16   * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length.  mcrypt, for example,
  17   * does not.  AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
  18   * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
  19   * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224.  Indeed, 160 and 224
  20   * are first defined as valid key / block lengths in
  21   * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
  22   * Extensions: Other block and Cipher Key lengths.
  23   * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224).
  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 'vendor/autoload.php';
  32   *
  33   *    $rijndael = new \phpseclib\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   * @category  Crypt
  48   * @package   Rijndael
  49   * @author    Jim Wigginton <terrafrost@php.net>
  50   * @copyright 2008 Jim Wigginton
  51   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  52   * @link      http://phpseclib.sourceforge.net
  53   */
  54  
  55  namespace phpseclib\Crypt;
  56  
  57  /**
  58   * Pure-PHP implementation of Rijndael.
  59   *
  60   * @package Rijndael
  61   * @author  Jim Wigginton <terrafrost@php.net>
  62   * @access  public
  63   */
  64  class Rijndael extends Base
  65  {
  66      /**
  67       * The mcrypt specific name of the cipher
  68       *
  69       * Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
  70       * \phpseclib\Crypt\Rijndael determines automatically whether mcrypt is useable
  71       * or not for the current $block_size/$key_length.
  72       * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
  73       *
  74       * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
  75       * @see \phpseclib\Crypt\Base::engine
  76       * @see self::isValidEngine()
  77       * @var string
  78       * @access private
  79       */
  80      var $cipher_name_mcrypt = 'rijndael-128';
  81  
  82      /**
  83       * The default salt used by setPassword()
  84       *
  85       * @see \phpseclib\Crypt\Base::password_default_salt
  86       * @see \phpseclib\Crypt\Base::setPassword()
  87       * @var string
  88       * @access private
  89       */
  90      var $password_default_salt = 'phpseclib';
  91  
  92      /**
  93       * The Key Schedule
  94       *
  95       * @see self::_setup()
  96       * @var array
  97       * @access private
  98       */
  99      var $w;
 100  
 101      /**
 102       * The Inverse Key Schedule
 103       *
 104       * @see self::_setup()
 105       * @var array
 106       * @access private
 107       */
 108      var $dw;
 109  
 110      /**
 111       * The Block Length divided by 32
 112       *
 113       * @see self::setBlockLength()
 114       * @var int
 115       * @access private
 116       * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4.  Exists in conjunction with $block_size
 117       *    because the encryption / decryption / key schedule creation requires this number and not $block_size.  We could
 118       *    derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
 119       *    of that, we'll just precompute it once.
 120       */
 121      var $Nb = 4;
 122  
 123      /**
 124       * The Key Length (in bytes)
 125       *
 126       * @see self::setKeyLength()
 127       * @var int
 128       * @access private
 129       * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $Nk
 130       *    because the encryption / decryption / key schedule creation requires this number and not $key_length.  We could
 131       *    derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
 132       *    of that, we'll just precompute it once.
 133       */
 134      var $key_length = 16;
 135  
 136      /**
 137       * The Key Length divided by 32
 138       *
 139       * @see self::setKeyLength()
 140       * @var int
 141       * @access private
 142       * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
 143       */
 144      var $Nk = 4;
 145  
 146      /**
 147       * The Number of Rounds
 148       *
 149       * @var int
 150       * @access private
 151       * @internal The max value is 14, the min value is 10.
 152       */
 153      var $Nr;
 154  
 155      /**
 156       * Shift offsets
 157       *
 158       * @var array
 159       * @access private
 160       */
 161      var $c;
 162  
 163      /**
 164       * Holds the last used key- and block_size information
 165       *
 166       * @var array
 167       * @access private
 168       */
 169      var $kl;
 170  
 171      /**
 172       * Sets the key length.
 173       *
 174       * Valid key lengths are 128, 160, 192, 224, and 256.  If the length is less than 128, it will be rounded up to
 175       * 128.  If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
 176       *
 177       * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
 178       *       and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
 179       *       192/256 bits as, for example, mcrypt will do.
 180       *
 181       *       That said, if you want be compatible with other Rijndael and AES implementations,
 182       *       you should not setKeyLength(160) or setKeyLength(224).
 183       *
 184       * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
 185       *             the mcrypt php extension, even if available.
 186       *             This results then in slower encryption.
 187       *
 188       * @access public
 189       * @param int $length
 190       */
 191      function setKeyLength($length)
 192      {
 193          switch (true) {
 194              case $length <= 128:
 195                  $this->key_length = 16;
 196                  break;
 197              case $length <= 160:
 198                  $this->key_length = 20;
 199                  break;
 200              case $length <= 192:
 201                  $this->key_length = 24;
 202                  break;
 203              case $length <= 224:
 204                  $this->key_length = 28;
 205                  break;
 206              default:
 207                  $this->key_length = 32;
 208          }
 209  
 210          parent::setKeyLength($length);
 211      }
 212  
 213      /**
 214       * Sets the block length
 215       *
 216       * Valid block lengths are 128, 160, 192, 224, and 256.  If the length is less than 128, it will be rounded up to
 217       * 128.  If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
 218       *
 219       * @access public
 220       * @param int $length
 221       */
 222      function setBlockLength($length)
 223      {
 224          $length >>= 5;
 225          if ($length > 8) {
 226              $length = 8;
 227          } elseif ($length < 4) {
 228              $length = 4;
 229          }
 230          $this->Nb = $length;
 231          $this->block_size = $length << 2;
 232          $this->changed = true;
 233          $this->_setEngine();
 234      }
 235  
 236      /**
 237       * Test for engine validity
 238       *
 239       * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
 240       *
 241       * @see \phpseclib\Crypt\Base::__construct()
 242       * @param int $engine
 243       * @access public
 244       * @return bool
 245       */
 246      function isValidEngine($engine)
 247      {
 248          switch ($engine) {
 249              case self::ENGINE_OPENSSL:
 250                  if ($this->block_size != 16) {
 251                      return false;
 252                  }
 253                  $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
 254                  $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
 255                  break;
 256              case self::ENGINE_MCRYPT:
 257                  $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
 258                  if ($this->key_length % 8) { // is it a 160/224-bit key?
 259                      // mcrypt is not usable for them, only for 128/192/256-bit keys
 260                      return false;
 261                  }
 262          }
 263  
 264          return parent::isValidEngine($engine);
 265      }
 266  
 267      /**
 268       * Encrypts a block
 269       *
 270       * @access private
 271       * @param string $in
 272       * @return string
 273       */
 274      function _encryptBlock($in)
 275      {
 276          static $tables;
 277          if (empty($tables)) {
 278              $tables = &$this->_getTables();
 279          }
 280          $t0   = $tables[0];
 281          $t1   = $tables[1];
 282          $t2   = $tables[2];
 283          $t3   = $tables[3];
 284          $sbox = $tables[4];
 285  
 286          $state = array();
 287          $words = unpack('N*', $in);
 288  
 289          $c = $this->c;
 290          $w = $this->w;
 291          $Nb = $this->Nb;
 292          $Nr = $this->Nr;
 293  
 294          // addRoundKey
 295          $wc = $Nb - 1;
 296          foreach ($words as $word) {
 297              $state[] = $word ^ $w[++$wc];
 298          }
 299  
 300          // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
 301          // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
 302          // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
 303          // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
 304          // Unfortunately, the description given there is not quite correct.  Per aes.spec.v316.pdf#page=19 [1],
 305          // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
 306  
 307          // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
 308          $temp = array();
 309          for ($round = 1; $round < $Nr; ++$round) {
 310              $i = 0; // $c[0] == 0
 311              $j = $c[1];
 312              $k = $c[2];
 313              $l = $c[3];
 314  
 315              while ($i < $Nb) {
 316                  $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
 317                              $t1[$state[$j] >> 16 & 0x000000FF] ^
 318                              $t2[$state[$k] >>  8 & 0x000000FF] ^
 319                              $t3[$state[$l]       & 0x000000FF] ^
 320                              $w[++$wc];
 321                  ++$i;
 322                  $j = ($j + 1) % $Nb;
 323                  $k = ($k + 1) % $Nb;
 324                  $l = ($l + 1) % $Nb;
 325              }
 326              $state = $temp;
 327          }
 328  
 329          // subWord
 330          for ($i = 0; $i < $Nb; ++$i) {
 331              $state[$i] =   $sbox[$state[$i]       & 0x000000FF]        |
 332                            ($sbox[$state[$i] >>  8 & 0x000000FF] <<  8) |
 333                            ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
 334                            ($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
 335          }
 336  
 337          // shiftRows + addRoundKey
 338          $i = 0; // $c[0] == 0
 339          $j = $c[1];
 340          $k = $c[2];
 341          $l = $c[3];
 342          while ($i < $Nb) {
 343              $temp[$i] = ($state[$i] & 0xFF000000) ^
 344                          ($state[$j] & 0x00FF0000) ^
 345                          ($state[$k] & 0x0000FF00) ^
 346                          ($state[$l] & 0x000000FF) ^
 347                           $w[$i];
 348              ++$i;
 349              $j = ($j + 1) % $Nb;
 350              $k = ($k + 1) % $Nb;
 351              $l = ($l + 1) % $Nb;
 352          }
 353  
 354          switch ($Nb) {
 355              case 8:
 356                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
 357              case 7:
 358                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
 359              case 6:
 360                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
 361              case 5:
 362                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
 363              default:
 364                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
 365          }
 366      }
 367  
 368      /**
 369       * Decrypts a block
 370       *
 371       * @access private
 372       * @param string $in
 373       * @return string
 374       */
 375      function _decryptBlock($in)
 376      {
 377          static $invtables;
 378          if (empty($invtables)) {
 379              $invtables = &$this->_getInvTables();
 380          }
 381          $dt0   = $invtables[0];
 382          $dt1   = $invtables[1];
 383          $dt2   = $invtables[2];
 384          $dt3   = $invtables[3];
 385          $isbox = $invtables[4];
 386  
 387          $state = array();
 388          $words = unpack('N*', $in);
 389  
 390          $c  = $this->c;
 391          $dw = $this->dw;
 392          $Nb = $this->Nb;
 393          $Nr = $this->Nr;
 394  
 395          // addRoundKey
 396          $wc = $Nb - 1;
 397          foreach ($words as $word) {
 398              $state[] = $word ^ $dw[++$wc];
 399          }
 400  
 401          $temp = array();
 402          for ($round = $Nr - 1; $round > 0; --$round) {
 403              $i = 0; // $c[0] == 0
 404              $j = $Nb - $c[1];
 405              $k = $Nb - $c[2];
 406              $l = $Nb - $c[3];
 407  
 408              while ($i < $Nb) {
 409                  $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
 410                              $dt1[$state[$j] >> 16 & 0x000000FF] ^
 411                              $dt2[$state[$k] >>  8 & 0x000000FF] ^
 412                              $dt3[$state[$l]       & 0x000000FF] ^
 413                              $dw[++$wc];
 414                  ++$i;
 415                  $j = ($j + 1) % $Nb;
 416                  $k = ($k + 1) % $Nb;
 417                  $l = ($l + 1) % $Nb;
 418              }
 419              $state = $temp;
 420          }
 421  
 422          // invShiftRows + invSubWord + addRoundKey
 423          $i = 0; // $c[0] == 0
 424          $j = $Nb - $c[1];
 425          $k = $Nb - $c[2];
 426          $l = $Nb - $c[3];
 427  
 428          while ($i < $Nb) {
 429              $word = ($state[$i] & 0xFF000000) |
 430                      ($state[$j] & 0x00FF0000) |
 431                      ($state[$k] & 0x0000FF00) |
 432                      ($state[$l] & 0x000000FF);
 433  
 434              $temp[$i] = $dw[$i] ^ ($isbox[$word       & 0x000000FF]        |
 435                                    ($isbox[$word >>  8 & 0x000000FF] <<  8) |
 436                                    ($isbox[$word >> 16 & 0x000000FF] << 16) |
 437                                    ($isbox[$word >> 24 & 0x000000FF] << 24));
 438              ++$i;
 439              $j = ($j + 1) % $Nb;
 440              $k = ($k + 1) % $Nb;
 441              $l = ($l + 1) % $Nb;
 442          }
 443  
 444          switch ($Nb) {
 445              case 8:
 446                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
 447              case 7:
 448                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
 449              case 6:
 450                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
 451              case 5:
 452                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
 453              default:
 454                  return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
 455          }
 456      }
 457  
 458      /**
 459       * Setup the key (expansion)
 460       *
 461       * @see \phpseclib\Crypt\Base::_setupKey()
 462       * @access private
 463       */
 464      function _setupKey()
 465      {
 466          // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
 467          // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
 468          static $rcon = array(0,
 469              0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
 470              0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
 471              0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
 472              0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
 473              0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
 474              0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
 475          );
 476  
 477          if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
 478              // already expanded
 479              return;
 480          }
 481          $this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);
 482  
 483          $this->Nk = $this->key_length >> 2;
 484          // see Rijndael-ammended.pdf#page=44
 485          $this->Nr = max($this->Nk, $this->Nb) + 6;
 486  
 487          // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
 488          //     "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
 489          // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
 490          //     "Table 2: Shift offsets for different block lengths"
 491          switch ($this->Nb) {
 492              case 4:
 493              case 5:
 494              case 6:
 495                  $this->c = array(0, 1, 2, 3);
 496                  break;
 497              case 7:
 498                  $this->c = array(0, 1, 2, 4);
 499                  break;
 500              case 8:
 501                  $this->c = array(0, 1, 3, 4);
 502          }
 503  
 504          $w = array_values(unpack('N*words', $this->key));
 505  
 506          $length = $this->Nb * ($this->Nr + 1);
 507          for ($i = $this->Nk; $i < $length; $i++) {
 508              $temp = $w[$i - 1];
 509              if ($i % $this->Nk == 0) {
 510                  // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
 511                  // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
 512                  // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
 513                  // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
 514                  $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
 515                  $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
 516              } elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
 517                  $temp = $this->_subWord($temp);
 518              }
 519              $w[$i] = $w[$i - $this->Nk] ^ $temp;
 520          }
 521  
 522          // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
 523          // and generate the inverse key schedule.  more specifically,
 524          // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
 525          // "The key expansion for the Inverse Cipher is defined as follows:
 526          //        1. Apply the Key Expansion.
 527          //        2. Apply InvMixColumn to all Round Keys except the first and the last one."
 528          // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
 529          list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
 530          $temp = $this->w = $this->dw = array();
 531          for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
 532              if ($col == $this->Nb) {
 533                  if ($row == 0) {
 534                      $this->dw[0] = $this->w[0];
 535                  } else {
 536                      // subWord + invMixColumn + invSubWord = invMixColumn
 537                      $j = 0;
 538                      while ($j < $this->Nb) {
 539                          $dw = $this->_subWord($this->w[$row][$j]);
 540                          $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
 541                                      $dt1[$dw >> 16 & 0x000000FF] ^
 542                                      $dt2[$dw >>  8 & 0x000000FF] ^
 543                                      $dt3[$dw       & 0x000000FF];
 544                          $j++;
 545                      }
 546                      $this->dw[$row] = $temp;
 547                  }
 548  
 549                  $col = 0;
 550                  $row++;
 551              }
 552              $this->w[$row][$col] = $w[$i];
 553          }
 554  
 555          $this->dw[$row] = $this->w[$row];
 556  
 557          // Converting to 1-dim key arrays (both ascending)
 558          $this->dw = array_reverse($this->dw);
 559          $w  = array_pop($this->w);
 560          $dw = array_pop($this->dw);
 561          foreach ($this->w as $r => $wr) {
 562              foreach ($wr as $c => $wc) {
 563                  $w[]  = $wc;
 564                  $dw[] = $this->dw[$r][$c];
 565              }
 566          }
 567          $this->w  = $w;
 568          $this->dw = $dw;
 569      }
 570  
 571      /**
 572       * Performs S-Box substitutions
 573       *
 574       * @access private
 575       * @param int $word
 576       */
 577      function _subWord($word)
 578      {
 579          static $sbox;
 580          if (empty($sbox)) {
 581              list(, , , , $sbox) = $this->_getTables();
 582          }
 583  
 584          return  $sbox[$word       & 0x000000FF]        |
 585                 ($sbox[$word >>  8 & 0x000000FF] <<  8) |
 586                 ($sbox[$word >> 16 & 0x000000FF] << 16) |
 587                 ($sbox[$word >> 24 & 0x000000FF] << 24);
 588      }
 589  
 590      /**
 591       * Provides the mixColumns and sboxes tables
 592       *
 593       * @see self::_encryptBlock()
 594       * @see self::_setupInlineCrypt()
 595       * @see self::_subWord()
 596       * @access private
 597       * @return array &$tables
 598       */
 599      function &_getTables()
 600      {
 601          static $tables;
 602          if (empty($tables)) {
 603              // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
 604              // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
 605              // those are the names we'll use.
 606              $t3 = array_map('intval', array(
 607                  // with array_map('intval', ...) we ensure we have only int's and not
 608                  // some slower floats converted by php automatically on high values
 609                  0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
 610                  0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
 611                  0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
 612                  0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
 613                  0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
 614                  0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
 615                  0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
 616                  0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
 617                  0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
 618                  0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
 619                  0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
 620                  0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
 621                  0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
 622                  0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
 623                  0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
 624                  0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
 625                  0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
 626                  0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
 627                  0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
 628                  0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
 629                  0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
 630                  0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
 631                  0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
 632                  0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
 633                  0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
 634                  0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
 635                  0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
 636                  0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
 637                  0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
 638                  0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
 639                  0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
 640                  0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
 641              ));
 642  
 643              foreach ($t3 as $t3i) {
 644                  $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >>  8) & 0x00FFFFFF);
 645                  $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
 646                  $t2[] = (($t3i <<  8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
 647              }
 648  
 649              $tables = array(
 650                  // The Precomputed mixColumns tables t0 - t3
 651                  $t0,
 652                  $t1,
 653                  $t2,
 654                  $t3,
 655                  // The SubByte S-Box
 656                  array(
 657                      0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
 658                      0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
 659                      0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
 660                      0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
 661                      0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
 662                      0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
 663                      0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
 664                      0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
 665                      0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
 666                      0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
 667                      0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
 668                      0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
 669                      0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
 670                      0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
 671                      0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
 672                      0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
 673                  )
 674              );
 675          }
 676          return $tables;
 677      }
 678  
 679      /**
 680       * Provides the inverse mixColumns and inverse sboxes tables
 681       *
 682       * @see self::_decryptBlock()
 683       * @see self::_setupInlineCrypt()
 684       * @see self::_setupKey()
 685       * @access private
 686       * @return array &$tables
 687       */
 688      function &_getInvTables()
 689      {
 690          static $tables;
 691          if (empty($tables)) {
 692              $dt3 = array_map('intval', array(
 693                  0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
 694                  0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
 695                  0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
 696                  0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
 697                  0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
 698                  0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
 699                  0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
 700                  0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
 701                  0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
 702                  0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
 703                  0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
 704                  0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
 705                  0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
 706                  0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
 707                  0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
 708                  0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
 709                  0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
 710                  0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
 711                  0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
 712                  0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
 713                  0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
 714                  0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
 715                  0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
 716                  0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
 717                  0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
 718                  0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
 719                  0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
 720                  0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
 721                  0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
 722                  0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
 723                  0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
 724                  0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
 725              ));
 726  
 727              foreach ($dt3 as $dt3i) {
 728                  $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >>  8) & 0x00FFFFFF);
 729                  $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
 730                  $dt2[] = (($dt3i <<  8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
 731              };
 732  
 733              $tables = array(
 734                  // The Precomputed inverse mixColumns tables dt0 - dt3
 735                  $dt0,
 736                  $dt1,
 737                  $dt2,
 738                  $dt3,
 739                  // The inverse SubByte S-Box
 740                  array(
 741                      0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
 742                      0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
 743                      0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
 744                      0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
 745                      0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
 746                      0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
 747                      0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
 748                      0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
 749                      0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
 750                      0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
 751                      0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
 752                      0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
 753                      0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
 754                      0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
 755                      0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
 756                      0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
 757                  )
 758              );
 759          }
 760          return $tables;
 761      }
 762  
 763      /**
 764       * Setup the performance-optimized function for de/encrypt()
 765       *
 766       * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
 767       * @access private
 768       */
 769      function _setupInlineCrypt()
 770      {
 771          // Note: _setupInlineCrypt() will be called only if $this->changed === true
 772          // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
 773          // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
 774  
 775          $lambda_functions =& self::_getLambdaFunctions();
 776  
 777          // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
 778          // (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
 779          // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
 780          $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
 781  
 782          // Generation of a uniqe hash for our generated code
 783          $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
 784          if ($gen_hi_opt_code) {
 785              $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
 786          }
 787  
 788          if (!isset($lambda_functions[$code_hash])) {
 789              switch (true) {
 790                  case $gen_hi_opt_code:
 791                      // The hi-optimized $lambda_functions will use the key-words hardcoded for better performance.
 792                      $w  = $this->w;
 793                      $dw = $this->dw;
 794                      $init_encrypt = '';
 795                      $init_decrypt = '';
 796                      break;
 797                  default:
 798                      for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
 799                          $w[]  = '$w['  . $i . ']';
 800                          $dw[] = '$dw[' . $i . ']';
 801                      }
 802                      $init_encrypt = '$w  = $self->w;';
 803                      $init_decrypt = '$dw = $self->dw;';
 804              }
 805  
 806              $Nr = $this->Nr;
 807              $Nb = $this->Nb;
 808              $c  = $this->c;
 809  
 810              // Generating encrypt code:
 811              $init_encrypt.= '
 812                  static $tables;
 813                  if (empty($tables)) {
 814                      $tables = &$self->_getTables();
 815                  }
 816                  $t0   = $tables[0];
 817                  $t1   = $tables[1];
 818                  $t2   = $tables[2];
 819                  $t3   = $tables[3];
 820                  $sbox = $tables[4];
 821              ';
 822  
 823              $s  = 'e';
 824              $e  = 's';
 825              $wc = $Nb - 1;
 826  
 827              // Preround: addRoundKey
 828              $encrypt_block = '$in = unpack("N*", $in);'."\n";
 829              for ($i = 0; $i < $Nb; ++$i) {
 830                  $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
 831              }
 832  
 833              // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
 834              for ($round = 1; $round < $Nr; ++$round) {
 835                  list($s, $e) = array($e, $s);
 836                  for ($i = 0; $i < $Nb; ++$i) {
 837                      $encrypt_block.=
 838                          '$'.$e.$i.' =
 839                          $t0[($'.$s.$i                  .' >> 24) & 0xff] ^
 840                          $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
 841                          $t2[($'.$s.(($i + $c[2]) % $Nb).' >>  8) & 0xff] ^
 842                          $t3[ $'.$s.(($i + $c[3]) % $Nb).'        & 0xff] ^
 843                          '.$w[++$wc].";\n";
 844                  }
 845              }
 846  
 847              // Finalround: subWord + shiftRows + addRoundKey
 848              for ($i = 0; $i < $Nb; ++$i) {
 849                  $encrypt_block.=
 850                      '$'.$e.$i.' =
 851                       $sbox[ $'.$e.$i.'        & 0xff]        |
 852                      ($sbox[($'.$e.$i.' >>  8) & 0xff] <<  8) |
 853                      ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
 854                      ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
 855              }
 856              $encrypt_block .= '$in = pack("N*"'."\n";
 857              for ($i = 0; $i < $Nb; ++$i) {
 858                  $encrypt_block.= ',
 859                      ($'.$e.$i                  .' & '.((int)0xFF000000).') ^
 860                      ($'.$e.(($i + $c[1]) % $Nb).' &         0x00FF0000   ) ^
 861                      ($'.$e.(($i + $c[2]) % $Nb).' &         0x0000FF00   ) ^
 862                      ($'.$e.(($i + $c[3]) % $Nb).' &         0x000000FF   ) ^
 863                      '.$w[$i]."\n";
 864              }
 865              $encrypt_block .= ');';
 866  
 867              // Generating decrypt code:
 868              $init_decrypt.= '
 869                  static $invtables;
 870                  if (empty($invtables)) {
 871                      $invtables = &$self->_getInvTables();
 872                  }
 873                  $dt0   = $invtables[0];
 874                  $dt1   = $invtables[1];
 875                  $dt2   = $invtables[2];
 876                  $dt3   = $invtables[3];
 877                  $isbox = $invtables[4];
 878              ';
 879  
 880              $s  = 'e';
 881              $e  = 's';
 882              $wc = $Nb - 1;
 883  
 884              // Preround: addRoundKey
 885              $decrypt_block = '$in = unpack("N*", $in);'."\n";
 886              for ($i = 0; $i < $Nb; ++$i) {
 887                  $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
 888              }
 889  
 890              // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
 891              for ($round = 1; $round < $Nr; ++$round) {
 892                  list($s, $e) = array($e, $s);
 893                  for ($i = 0; $i < $Nb; ++$i) {
 894                      $decrypt_block.=
 895                          '$'.$e.$i.' =
 896                          $dt0[($'.$s.$i                        .' >> 24) & 0xff] ^
 897                          $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
 898                          $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >>  8) & 0xff] ^
 899                          $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).'        & 0xff] ^
 900                          '.$dw[++$wc].";\n";
 901                  }
 902              }
 903  
 904              // Finalround: subWord + shiftRows + addRoundKey
 905              for ($i = 0; $i < $Nb; ++$i) {
 906                  $decrypt_block.=
 907                      '$'.$e.$i.' =
 908                       $isbox[ $'.$e.$i.'        & 0xff]        |
 909                      ($isbox[($'.$e.$i.' >>  8) & 0xff] <<  8) |
 910                      ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
 911                      ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
 912              }
 913              $decrypt_block .= '$in = pack("N*"'."\n";
 914              for ($i = 0; $i < $Nb; ++$i) {
 915                  $decrypt_block.= ',
 916                      ($'.$e.$i.                        ' & '.((int)0xFF000000).') ^
 917                      ($'.$e.(($Nb + $i - $c[1]) % $Nb).' &         0x00FF0000   ) ^
 918                      ($'.$e.(($Nb + $i - $c[2]) % $Nb).' &         0x0000FF00   ) ^
 919                      ($'.$e.(($Nb + $i - $c[3]) % $Nb).' &         0x000000FF   ) ^
 920                      '.$dw[$i]."\n";
 921              }
 922              $decrypt_block .= ');';
 923  
 924              $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
 925                  array(
 926                     'init_crypt'    => '',
 927                     'init_encrypt'  => $init_encrypt,
 928                     'init_decrypt'  => $init_decrypt,
 929                     'encrypt_block' => $encrypt_block,
 930                     'decrypt_block' => $decrypt_block
 931                  )
 932              );
 933          }
 934          $this->inline_crypt = $lambda_functions[$code_hash];
 935      }
 936  }