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