Subversion Repositories oidplus

Rev

Rev 846 | Rev 1042 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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