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