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