Subversion Repositories oidplus

Rev

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

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