[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * PHP Encryption Library 5 * Copyright (c) 2014, Taylor Hornby 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /* 32 * Web: https://defuse.ca/secure-php-encryption.htm 33 * GitHub: https://github.com/defuse/php-encryption 34 * 35 * WARNING: This encryption library is not a silver bullet. It only provides 36 * symmetric encryption given a uniformly random key. This means you MUST NOT 37 * use an ASCII string like a password as the key parameter, it MUST be 38 * a uniformly random key generated by CreateNewRandomKey(). If you want to 39 * encrypt something with a password, apply a password key derivation function 40 * like PBKDF2 or scrypt with a random salt to generate a key. 41 * 42 * WARNING: Error handling is very important, especially for crypto code! 43 * 44 * How to use this code: 45 * 46 * Generating a Key 47 * ---------------- 48 * try { 49 * $key = Crypto::CreateNewRandomKey(); 50 * // WARNING: Do NOT encode $key with bin2hex() or base64_encode(), 51 * // they may leak the key to the attacker through side channels. 52 * } catch (CryptoTestFailedException $ex) { 53 * die('Cannot safely create a key'); 54 * } catch (CannotPerformOperationException $ex) { 55 * die('Cannot safely create a key'); 56 * } 57 * 58 * Encrypting a Message 59 * -------------------- 60 * $message = "ATTACK AT DAWN"; 61 * try { 62 * $ciphertext = Crypto::Encrypt($message, $key); 63 * } catch (CryptoTestFailedException $ex) { 64 * die('Cannot safely perform encryption'); 65 * } catch (CannotPerformOperationException $ex) { 66 * die('Cannot safely perform decryption'); 67 * } 68 * 69 * Decrypting a Message 70 * -------------------- 71 * try { 72 * $decrypted = Crypto::Decrypt($ciphertext, $key); 73 * } catch (InvalidCiphertextException $ex) { // VERY IMPORTANT 74 * // Either: 75 * // 1. The ciphertext was modified by the attacker, 76 * // 2. The key is wrong, or 77 * // 3. $ciphertext is not a valid ciphertext or was corrupted. 78 * // Assume the worst. 79 * die('DANGER! DANGER! The ciphertext has been tampered with!'); 80 * } catch (CryptoTestFailedException $ex) { 81 * die('Cannot safely perform encryption'); 82 * } catch (CannotPerformOperationException $ex) { 83 * die('Cannot safely perform decryption'); 84 * } 85 */ 86 87 /* 88 * Raised by Decrypt() when one of the following conditions are met: 89 * - The key is wrong. 90 * - The ciphertext is invalid or not in the correct format. 91 * - The attacker modified the ciphertext. 92 */ 93 class InvalidCiphertextException extends Exception {} 94 /* If you see these, it means it is NOT SAFE to do encryption on your system. */ 95 class CannotPerformOperationException extends Exception {} 96 class CryptoTestFailedException extends Exception {} 97 98 class Crypto 99 { 100 // Ciphertext format: [____HMAC____][____IV____][____CIPHERTEXT____]. 101 102 /* Do not change these constants! */ 103 const CIPHER = MCRYPT_RIJNDAEL_128; 104 const KEY_BYTE_SIZE = 16; 105 const CIPHER_MODE = 'cbc'; 106 const HASH_FUNCTION = 'sha256'; 107 const MAC_BYTE_SIZE = 32; 108 const ENCRYPTION_INFO = 'DefusePHP|KeyForEncryption'; 109 const AUTHENTICATION_INFO = 'DefusePHP|KeyForAuthentication'; 110 111 /* 112 * Use this to generate a random encryption key. 113 */ 114 public static function CreateNewRandomKey() 115 { 116 Crypto::RuntimeTest(); 117 return self::SecureRandom(self::KEY_BYTE_SIZE); 118 } 119 120 /* 121 * Encrypts a message. 122 * $plaintext is the message to encrypt. 123 * $key is the encryption key, a value generated by CreateNewRandomKey(). 124 * You MUST catch exceptions thrown by this function. See docs above. 125 */ 126 public static function Encrypt($plaintext, $key) 127 { 128 Crypto::RuntimeTest(); 129 130 if (self::our_strlen($key) !== self::KEY_BYTE_SIZE) 131 { 132 throw new CannotPerformOperationException("Bad key."); 133 } 134 135 // Generate a sub-key for encryption. 136 $keysize = self::KEY_BYTE_SIZE; 137 $ekey = self::HKDF(self::HASH_FUNCTION, $key, $keysize, self::ENCRYPTION_INFO); 138 139 // Generate a random initialization vector. 140 self::EnsureFunctionExists("mcrypt_get_iv_size"); 141 $ivsize = mcrypt_get_iv_size(self::CIPHER, self::CIPHER_MODE); 142 if ($ivsize === FALSE || $ivsize <= 0) { 143 throw new CannotPerformOperationException(); 144 } 145 $iv = self::SecureRandom($ivsize); 146 147 $ciphertext = $iv . self::PlainEncrypt($plaintext, $ekey, $iv); 148 149 // Generate a sub-key for authentication and apply the HMAC. 150 $akey = self::HKDF(self::HASH_FUNCTION, $key, self::KEY_BYTE_SIZE, self::AUTHENTICATION_INFO); 151 $auth = hash_hmac(self::HASH_FUNCTION, $ciphertext, $akey, true); 152 $ciphertext = $auth . $ciphertext; 153 154 return $ciphertext; 155 } 156 157 /* 158 * Decrypts a ciphertext. 159 * $ciphertext is the ciphertext to decrypt. 160 * $key is the key that the ciphertext was encrypted with. 161 * You MUST catch exceptions thrown by this function. See docs above. 162 */ 163 public static function Decrypt($ciphertext, $key) 164 { 165 Crypto::RuntimeTest(); 166 167 // Extract the HMAC from the front of the ciphertext. 168 if (self::our_strlen($ciphertext) <= self::MAC_BYTE_SIZE) { 169 throw new InvalidCiphertextException(); 170 } 171 $hmac = self::our_substr($ciphertext, 0, self::MAC_BYTE_SIZE); 172 if ($hmac === FALSE) { 173 throw new CannotPerformOperationException(); 174 } 175 $ciphertext = self::our_substr($ciphertext, self::MAC_BYTE_SIZE); 176 if ($ciphertext === FALSE) { 177 throw new CannotPerformOperationException(); 178 } 179 180 // Regenerate the same authentication sub-key. 181 $akey = self::HKDF(self::HASH_FUNCTION, $key, self::KEY_BYTE_SIZE, self::AUTHENTICATION_INFO); 182 183 if (self::VerifyHMAC($hmac, $ciphertext, $akey)) 184 { 185 // Regenerate the same encryption sub-key. 186 $keysize = self::KEY_BYTE_SIZE; 187 $ekey = self::HKDF(self::HASH_FUNCTION, $key, $keysize, self::ENCRYPTION_INFO); 188 189 // Extract the initialization vector from the ciphertext. 190 self::EnsureFunctionExists("mcrypt_get_iv_size"); 191 $ivsize = mcrypt_get_iv_size(self::CIPHER, self::CIPHER_MODE); 192 if ($ivsize === FALSE || $ivsize <= 0) { 193 throw new CannotPerformOperationException(); 194 } 195 if (self::our_strlen($ciphertext) <= $ivsize) { 196 throw new InvalidCiphertextException(); 197 } 198 $iv = self::our_substr($ciphertext, 0, $ivsize); 199 if ($iv === FALSE) { 200 throw new CannotPerformOperationException(); 201 } 202 $ciphertext = self::our_substr($ciphertext, $ivsize); 203 if ($ciphertext === FALSE) { 204 throw new CannotPerformOperationException(); 205 } 206 207 $plaintext = self::PlainDecrypt($ciphertext, $ekey, $iv); 208 209 return $plaintext; 210 } 211 else 212 { 213 /* 214 * We throw an exception instead of returning FALSE because we want 215 * a script that doesn't handle this condition to CRASH, instead 216 * of thinking the ciphertext decrypted to the value FALSE. 217 */ 218 throw new InvalidCiphertextException(); 219 } 220 } 221 222 /* 223 * Runs tests. 224 * Raises CannotPerformOperationException or CryptoTestFailedException if 225 * one of the tests fail. If any tests fails, your system is not capable of 226 * performing encryption, so make sure you fail safe in that case. 227 */ 228 public static function RuntimeTest() 229 { 230 // 0: Tests haven't been run yet. 231 // 1: Tests have passed. 232 // 2: Tests are running right now. 233 // 3: Tests have failed. 234 static $test_state = 0; 235 236 if ($test_state === 1 || $test_state === 2) { 237 return; 238 } 239 240 try { 241 $test_state = 2; 242 self::AESTestVector(); 243 self::HMACTestVector(); 244 self::HKDFTestVector(); 245 246 self::TestEncryptDecrypt(); 247 if (self::our_strlen(Crypto::CreateNewRandomKey()) != self::KEY_BYTE_SIZE) { 248 throw new CryptoTestFailedException(); 249 } 250 251 if (self::ENCRYPTION_INFO == self::AUTHENTICATION_INFO) { 252 throw new CryptoTestFailedException(); 253 } 254 } catch (CryptoTestFailedException $ex) { 255 // Do this, otherwise it will stay in the "tests are running" state. 256 $test_state = 3; 257 throw $ex; 258 } 259 260 // Change this to '0' make the tests always re-run (for benchmarking). 261 $test_state = 1; 262 } 263 264 /* 265 * Never call this method directly! 266 */ 267 private static function PlainEncrypt($plaintext, $key, $iv) 268 { 269 self::EnsureFunctionExists("mcrypt_module_open"); 270 $crypt = mcrypt_module_open(self::CIPHER, "", self::CIPHER_MODE, ""); 271 if ($crypt === FALSE) { 272 throw new CannotPerformOperationException(); 273 } 274 275 // Pad the plaintext to a multiple of the block size. 276 self::EnsureFunctionExists("mcrypt_enc_get_block_size"); 277 $block = mcrypt_enc_get_block_size($crypt); 278 $pad = $block - (self::our_strlen($plaintext) % $block); 279 $plaintext .= str_repeat(chr($pad), $pad); 280 281 self::EnsureFunctionExists("mcrypt_generic_init"); 282 $ret = mcrypt_generic_init($crypt, $key, $iv); 283 if ($ret !== 0) { 284 throw new CannotPerformOperationException(); 285 } 286 self::EnsureFunctionExists("mcrypt_generic"); 287 $ciphertext = mcrypt_generic($crypt, $plaintext); 288 self::EnsureFunctionExists("mcrypt_generic_deinit"); 289 $ret = mcrypt_generic_deinit($crypt); 290 if ($ret !== TRUE) { 291 throw new CannotPerformOperationException(); 292 } 293 self::EnsureFunctionExists("mcrypt_module_close"); 294 $ret = mcrypt_module_close($crypt); 295 if ($ret !== TRUE) { 296 throw new CannotPerformOperationException(); 297 } 298 299 return $ciphertext; 300 } 301 302 /* 303 * Never call this method directly! 304 */ 305 private static function PlainDecrypt($ciphertext, $key, $iv) 306 { 307 self::EnsureFunctionExists("mcrypt_module_open"); 308 $crypt = mcrypt_module_open(self::CIPHER, "", self::CIPHER_MODE, ""); 309 if ($crypt === FALSE) { 310 throw new CannotPerformOperationException(); 311 } 312 313 self::EnsureFunctionExists("mcrypt_enc_get_block_size"); 314 $block = mcrypt_enc_get_block_size($crypt); 315 self::EnsureFunctionExists("mcrypt_generic_init"); 316 $ret = mcrypt_generic_init($crypt, $key, $iv); 317 if ($ret !== 0) { 318 throw new CannotPerformOperationException(); 319 } 320 self::EnsureFunctionExists("mdecrypt_generic"); 321 $plaintext = mdecrypt_generic($crypt, $ciphertext); 322 self::EnsureFunctionExists("mcrypt_generic_deinit"); 323 $ret = mcrypt_generic_deinit($crypt); 324 if ($ret !== TRUE) { 325 throw new CannotPerformOperationException(); 326 } 327 self::EnsureFunctionExists("mcrypt_module_close"); 328 $ret = mcrypt_module_close($crypt); 329 if ($ret !== TRUE) { 330 throw new CannotPerformOperationException(); 331 } 332 333 // Remove the padding. 334 $pad = ord($plaintext[self::our_strlen($plaintext) - 1]); 335 if ($pad <= 0 || $pad > $block) { 336 throw new CannotPerformOperationException(); 337 } 338 $plaintext = self::our_substr($plaintext, 0, self::our_strlen($plaintext) - $pad); 339 if ($plaintext === FALSE) { 340 throw new CannotPerformOperationException(); 341 } 342 343 return $plaintext; 344 } 345 346 /* 347 * Returns a random binary string of length $octets bytes. 348 */ 349 private static function SecureRandom($octets) 350 { 351 self::EnsureFunctionExists("mcrypt_create_iv"); 352 $random = mcrypt_create_iv($octets, MCRYPT_DEV_URANDOM); 353 if ($random === FALSE) { 354 throw new CannotPerformOperationException(); 355 } else { 356 return $random; 357 } 358 } 359 360 /* 361 * Use HKDF to derive multiple keys from one. 362 * http://tools.ietf.org/html/rfc5869 363 */ 364 private static function HKDF($hash, $ikm, $length, $info = '', $salt = NULL) 365 { 366 // Find the correct digest length as quickly as we can. 367 $digest_length = self::MAC_BYTE_SIZE; 368 if ($hash != self::HASH_FUNCTION) { 369 $digest_length = self::our_strlen(hash_hmac($hash, '', '', true)); 370 } 371 372 // Sanity-check the desired output length. 373 if (empty($length) || !is_int($length) || 374 $length < 0 || $length > 255 * $digest_length) { 375 throw new CannotPerformOperationException(); 376 } 377 378 // "if [salt] not provided, is set to a string of HashLen zeroes." 379 if (is_null($salt)) { 380 $salt = str_repeat("\x00", $digest_length); 381 } 382 383 // HKDF-Extract: 384 // PRK = HMAC-Hash(salt, IKM) 385 // The salt is the HMAC key. 386 $prk = hash_hmac($hash, $ikm, $salt, true); 387 388 // HKDF-Expand: 389 390 // This check is useless, but it serves as a reminder to the spec. 391 if (self::our_strlen($prk) < $digest_length) { 392 throw new CannotPerformOperationException(); 393 } 394 395 // T(0) = '' 396 $t = ''; 397 $last_block = ''; 398 for ($block_index = 1; self::our_strlen($t) < $length; $block_index++) { 399 // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??) 400 $last_block = hash_hmac( 401 $hash, 402 $last_block . $info . chr($block_index), 403 $prk, 404 true 405 ); 406 // T = T(1) | T(2) | T(3) | ... | T(N) 407 $t .= $last_block; 408 } 409 410 // ORM = first L octets of T 411 $orm = self::our_substr($t, 0, $length); 412 if ($orm === FALSE) { 413 throw new CannotPerformOperationException(); 414 } 415 return $orm; 416 } 417 418 private static function VerifyHMAC($correct_hmac, $message, $key) 419 { 420 $message_hmac = hash_hmac(self::HASH_FUNCTION, $message, $key, true); 421 422 // We can't just compare the strings with '==', since it would make 423 // timing attacks possible. We could use the XOR-OR constant-time 424 // comparison algorithm, but I'm not sure if that's good enough way up 425 // here in an interpreted language. So we use the method of HMACing the 426 // strings we want to compare with a random key, then comparing those. 427 428 // NOTE: This leaks information when the strings are not the same 429 // length, but they should always be the same length here. Enforce it: 430 if (self::our_strlen($correct_hmac) !== self::our_strlen($message_hmac)) { 431 throw new CannotPerformOperationException(); 432 } 433 434 $blind = self::CreateNewRandomKey(); 435 $message_compare = hash_hmac(self::HASH_FUNCTION, $message_hmac, $blind); 436 $correct_compare = hash_hmac(self::HASH_FUNCTION, $correct_hmac, $blind); 437 return $correct_compare === $message_compare; 438 } 439 440 private static function TestEncryptDecrypt() 441 { 442 $key = Crypto::CreateNewRandomKey(); 443 $data = "EnCrYpT EvErYThInG\x00\x00"; 444 445 // Make sure encrypting then decrypting doesn't change the message. 446 $ciphertext = Crypto::Encrypt($data, $key); 447 try { 448 $decrypted = Crypto::Decrypt($ciphertext, $key); 449 } catch (InvalidCiphertextException $ex) { 450 // It's important to catch this and change it into a 451 // CryptoTestFailedException, otherwise a test failure could trick 452 // the user into thinking it's just an invalid ciphertext! 453 throw new CryptoTestFailedException(); 454 } 455 if($decrypted !== $data) 456 { 457 throw new CryptoTestFailedException(); 458 } 459 460 // Modifying the ciphertext: Appending a string. 461 try { 462 Crypto::Decrypt($ciphertext . "a", $key); 463 throw new CryptoTestFailedException(); 464 } catch (InvalidCiphertextException $e) { /* expected */ } 465 466 // Modifying the ciphertext: Changing an IV byte. 467 try { 468 $ciphertext[0] = chr((ord($ciphertext[0]) + 1) % 256); 469 Crypto::Decrypt($ciphertext, $key); 470 throw new CryptoTestFailedException(); 471 } catch (InvalidCiphertextException $e) { /* expected */ } 472 473 // Decrypting with the wrong key. 474 $key = Crypto::CreateNewRandomKey(); 475 $data = "abcdef"; 476 $ciphertext = Crypto::Encrypt($data, $key); 477 $wrong_key = Crypto::CreateNewRandomKey(); 478 try { 479 Crypto::Decrypt($ciphertext, $wrong_key); 480 throw new CryptoTestFailedException(); 481 } catch (InvalidCiphertextException $e) { /* expected */ } 482 483 // Ciphertext too small (shorter than HMAC). 484 $key = Crypto::CreateNewRandomKey(); 485 $ciphertext = str_repeat("A", self::MAC_BYTE_SIZE - 1); 486 try { 487 Crypto::Decrypt($ciphertext, $key); 488 throw new CryptoTestFailedException(); 489 } catch (InvalidCiphertextException $e) { /* expected */ } 490 } 491 492 private static function HKDFTestVector() 493 { 494 // HKDF test vectors from RFC 5869 495 496 // Test Case 1 497 $ikm = str_repeat("\x0b", 22); 498 $salt = self::hexToBytes("000102030405060708090a0b0c"); 499 $info = self::hexToBytes("f0f1f2f3f4f5f6f7f8f9"); 500 $length = 42; 501 $okm = self::hexToBytes( 502 "3cb25f25faacd57a90434f64d0362f2a" . 503 "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" . 504 "34007208d5b887185865" 505 ); 506 $computed_okm = self::HKDF("sha256", $ikm, $length, $info, $salt); 507 if ($computed_okm !== $okm) { 508 throw new CryptoTestFailedException(); 509 } 510 511 // Test Case 7 512 $ikm = str_repeat("\x0c", 22); 513 $length = 42; 514 $okm = self::hexToBytes( 515 "2c91117204d745f3500d636a62f64f0a" . 516 "b3bae548aa53d423b0d1f27ebba6f5e5" . 517 "673a081d70cce7acfc48" 518 ); 519 $computed_okm = self::HKDF("sha1", $ikm, $length); 520 if ($computed_okm !== $okm) { 521 throw new CryptoTestFailedException(); 522 } 523 524 } 525 526 private static function HMACTestVector() 527 { 528 // HMAC test vector From RFC 4231 (Test Case 1) 529 $key = str_repeat("\x0b", 20); 530 $data = "Hi There"; 531 $correct = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"; 532 if (hash_hmac(self::HASH_FUNCTION, $data, $key) != $correct) { 533 throw new CryptoTestFailedException(); 534 } 535 } 536 537 private static function AESTestVector() 538 { 539 // AES CBC mode test vector from NIST SP 800-38A 540 $key = self::hexToBytes("2b7e151628aed2a6abf7158809cf4f3c"); 541 $iv = self::hexToBytes("000102030405060708090a0b0c0d0e0f"); 542 $plaintext = self::hexToBytes( 543 "6bc1bee22e409f96e93d7e117393172a" . 544 "ae2d8a571e03ac9c9eb76fac45af8e51" . 545 "30c81c46a35ce411e5fbc1191a0a52ef" . 546 "f69f2445df4f9b17ad2b417be66c3710" 547 ); 548 $ciphertext = self::hexToBytes( 549 "7649abac8119b246cee98e9b12e9197d" . 550 "5086cb9b507219ee95db113a917678b2" . 551 "73bed6b8e3c1743b7116e69e22229516" . 552 "3ff1caa1681fac09120eca307586e1a7" . 553 /* Block due to padding. Not from NIST test vector. 554 Padding Block: 10101010101010101010101010101010 555 Ciphertext: 3ff1caa1681fac09120eca307586e1a7 556 (+) 2fe1dab1780fbc19021eda206596f1b7 557 AES 8cb82807230e1321d3fae00d18cc2012 558 559 */ 560 "8cb82807230e1321d3fae00d18cc2012" 561 ); 562 563 $computed_ciphertext = self::PlainEncrypt($plaintext, $key, $iv); 564 if ($computed_ciphertext !== $ciphertext) { 565 throw new CryptoTestFailedException(); 566 } 567 568 $computed_plaintext = self::PlainDecrypt($ciphertext, $key, $iv); 569 if ($computed_plaintext !== $plaintext) { 570 throw new CryptoTestFailedException(); 571 } 572 } 573 574 /* WARNING: Do not call this function on secrets. It creates side channels. */ 575 private static function hexToBytes($hex_string) 576 { 577 return pack("H*", $hex_string); 578 } 579 580 private static function EnsureFunctionExists($name) 581 { 582 if (!function_exists($name)) { 583 throw new CannotPerformOperationException(); 584 } 585 } 586 587 /* 588 * We need these strlen() and substr() functions because when 589 * 'mbstring.func_overload' is set in php.ini, the standard strlen() and 590 * substr() are replaced by mb_strlen() and mb_substr(). 591 */ 592 593 private static function our_strlen($str) 594 { 595 if (function_exists('mb_strlen')) { 596 $length = mb_strlen($str, '8bit'); 597 if ($length === FALSE) { 598 throw new CannotPerformOperationException(); 599 } 600 return $length; 601 } else { 602 return strlen($str); 603 } 604 } 605 606 private static function our_substr($str, $start, $length = NULL) 607 { 608 if (function_exists('mb_substr')) 609 { 610 // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP 611 // 5.3, so we have to find the length ourselves. 612 if (!isset($length)) { 613 if ($start >= 0) { 614 $length = self::our_strlen($str) - $start; 615 } else { 616 $length = -$start; 617 } 618 } 619 620 return mb_substr($str, $start, $length, '8bit'); 621 } 622 623 // Unlike mb_substr(), substr() doesn't accept NULL for length 624 if (isset($length)) { 625 return substr($str, $start, $length); 626 } else { 627 return substr($str, $start); 628 } 629 } 630 631 } 632 633 /* 634 * We want to catch all uncaught exceptions that come from the Crypto class, 635 * since by default, PHP will leak the key in the stack trace from an uncaught 636 * exception. This is a really ugly hack, but I think it's justified. 637 * 638 * Everything up to handler() getting called should be reliable, so this should 639 * reliably suppress the stack traces. The rest is just a bonus so that we don't 640 * make it impossible to debug other exceptions. 641 * 642 * This bit of code was adapted from: http://stackoverflow.com/a/7939492 643 */ 644 645 class CryptoExceptionHandler 646 { 647 private $rethrow = NULL; 648 649 public function __construct() 650 { 651 set_exception_handler(array($this, "handler")); 652 } 653 654 public function handler($ex) 655 { 656 if ( 657 $ex instanceof InvalidCiphertextException || 658 $ex instanceof CannotPerformOperationException || 659 $ex instanceof CryptoTestFailedException 660 ) { 661 echo "FATAL ERROR: Uncaught crypto exception. Suppresssing output.\n"; 662 } else { 663 /* Re-throw the exception in the destructor. */ 664 $this->rethrow = $ex; 665 } 666 } 667 668 public function __destruct() { 669 if ($this->rethrow) { 670 throw $this->rethrow; 671 } 672 } 673 } 674 675 $crypto_exception_handler_object_dont_touch_me = new CryptoExceptionHandler(); 676
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |