Subversion Repositories oidplus

Rev

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