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