[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Encrypt/ -> Aes.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
   7   * @license    GNU General Public License version 2 or later; see LICENSE.txt
   8   * @note    This file has been modified by the Joomla! Project and no longer reflects the original work of its author.
   9   */
  10  
  11  namespace Joomla\CMS\Encrypt;
  12  
  13  use Joomla\CMS\Encrypt\AES\AesInterface;
  14  use Joomla\CMS\Encrypt\AES\Mcrypt;
  15  use Joomla\CMS\Encrypt\AES\OpenSSL;
  16  
  17  // phpcs:disable PSR1.Files.SideEffects
  18  \defined('JPATH_PLATFORM') or die;
  19  // phpcs:enable PSR1.Files.SideEffects
  20  
  21  /**
  22   * A simple implementation of AES-128, AES-192 and AES-256 encryption using the
  23   * high performance mcrypt library.
  24   *
  25   * @since    1.0
  26   */
  27  class Aes
  28  {
  29      /**
  30       * The cipher key.
  31       *
  32       * @var   string
  33       */
  34      protected $key = '';
  35  
  36      /**
  37       * The AES encryption adapter in use.
  38       *
  39       * @var  AesInterface
  40       */
  41      protected $adapter;
  42  
  43      /**
  44       * Initialise the AES encryption object.
  45       *
  46       * Note: If the key is not 16 bytes this class will do a stupid key expansion for legacy reasons (produce the
  47       * SHA-256 of the key string and throw away half of it).
  48       *
  49       * @param   string          $key      The encryption key (password). It can be a raw key (16 bytes) or a passphrase.
  50       * @param   int             $strength Bit strength (128, 192 or 256) – ALWAYS USE 128 BITS. THIS PARAMETER IS DEPRECATED.
  51       * @param   string          $mode     Encryption mode. Can be ebc or cbc. We recommend using cbc.
  52       * @param   string          $priority Priority which adapter we should try first
  53       *
  54       * @deprecated 5.0 $strength will be removed
  55       */
  56      public function __construct($key, $strength = 128, $mode = 'cbc', $priority = 'openssl')
  57      {
  58          if ($priority === 'openssl') {
  59              $this->adapter = new OpenSSL();
  60  
  61              if (!$this->adapter->isSupported()) {
  62                  $this->adapter = new Mcrypt();
  63              }
  64          } else {
  65              $this->adapter = new Mcrypt();
  66  
  67              if (!$this->adapter->isSupported()) {
  68                  $this->adapter = new OpenSSL();
  69              }
  70          }
  71  
  72          $this->adapter->setEncryptionMode($mode, $strength);
  73          $this->setPassword($key, true);
  74      }
  75  
  76      /**
  77       * Sets the password for this instance.
  78       *
  79       * WARNING: Do not use the legacy mode, it's insecure
  80       *
  81       * @param   string $password   The password (either user-provided password or binary encryption key) to use
  82       * @param   bool   $legacyMode True to use the legacy key expansion. We recommend against using it.
  83       *
  84       * @since    4.0.0
  85       * @return   void
  86       */
  87      public function setPassword($password, $legacyMode = false)
  88      {
  89          $this->key = $password;
  90  
  91          $passLength = \strlen($password);
  92  
  93          if (\function_exists('mb_strlen')) {
  94              $passLength = mb_strlen($password, 'ASCII');
  95          }
  96  
  97          // Legacy mode was doing something stupid, requiring a key of 32 bytes. DO NOT USE LEGACY MODE!
  98          if ($legacyMode && ($passLength != 32)) {
  99              // Legacy mode: use the sha256 of the password
 100              $this->key = hash('sha256', $password, true);
 101  
 102              // We have to trim or zero pad the password (we end up throwing half of it away in Rijndael-128 / AES...)
 103              $this->key = $this->adapter->resizeKey($this->key, $this->adapter->getBlockSize());
 104          }
 105      }
 106  
 107      /**
 108       * Encrypts a string using AES
 109       *
 110       * @param   string $stringToEncrypt The plaintext to encrypt
 111       * @param   bool   $base64encoded   Should I Base64-encode the result?
 112       *
 113       * @return   string  The cryptotext. Please note that the first 16 bytes of
 114       *                   the raw string is the IV (initialisation vector) which
 115       *                   is necessary for decoding the string.
 116       */
 117      public function encryptString($stringToEncrypt, $base64encoded = true)
 118      {
 119          $blockSize = $this->adapter->getBlockSize();
 120          $randVal   = new Randval();
 121          $iv        = $randVal->generate($blockSize);
 122  
 123          $key        = $this->getExpandedKey($blockSize, $iv);
 124          $cipherText = $this->adapter->encrypt($stringToEncrypt, $key, $iv);
 125  
 126          // Optionally pass the result through Base64 encoding
 127          if ($base64encoded) {
 128              $cipherText = base64_encode($cipherText);
 129          }
 130  
 131          // Return the result
 132          return $cipherText;
 133      }
 134  
 135      /**
 136       * Decrypts a ciphertext into a plaintext string using AES
 137       *
 138       * @param   string $stringToDecrypt The ciphertext to decrypt. The first 16 bytes of the raw string must contain
 139       *                                  the IV (initialisation vector).
 140       * @param   bool   $base64encoded   Should I Base64-decode the data before decryption?
 141       *
 142       * @return   string  The plain text string
 143       */
 144      public function decryptString($stringToDecrypt, $base64encoded = true)
 145      {
 146          if ($base64encoded) {
 147              $stringToDecrypt = base64_decode($stringToDecrypt);
 148          }
 149  
 150          // Extract IV
 151          $iv_size = $this->adapter->getBlockSize();
 152          $iv      = substr($stringToDecrypt, 0, $iv_size);
 153          $key     = $this->getExpandedKey($iv_size, $iv);
 154  
 155          // Decrypt the data
 156          $plainText = $this->adapter->decrypt($stringToDecrypt, $key);
 157  
 158          return $plainText;
 159      }
 160  
 161      /**
 162       * Is AES encryption supported by this PHP installation?
 163       *
 164       * @return boolean
 165       */
 166      public static function isSupported()
 167      {
 168          $adapter = new OpenSSL();
 169  
 170          if (!$adapter->isSupported()) {
 171              $adapter = new Mcrypt();
 172  
 173              if (!$adapter->isSupported()) {
 174                  return false;
 175              }
 176          }
 177  
 178          if (!\function_exists('base64_encode')) {
 179              return false;
 180          }
 181  
 182          if (!\function_exists('base64_decode')) {
 183              return false;
 184          }
 185  
 186          if (!\function_exists('hash_algos')) {
 187              return false;
 188          }
 189  
 190          $algorithms = hash_algos();
 191  
 192          if (!\in_array('sha256', $algorithms)) {
 193              return false;
 194          }
 195  
 196          return true;
 197      }
 198  
 199      /**
 200       * Get the expanded key
 201       *
 202       * @param   integer  $blockSize  Blocksize to process
 203       * @param   string   $iv         IV
 204       *
 205       * @return   string
 206       */
 207      public function getExpandedKey($blockSize, $iv)
 208      {
 209          $key        = $this->key;
 210          $passLength = \strlen($key);
 211  
 212          if (\function_exists('mb_strlen')) {
 213              $passLength = mb_strlen($key, 'ASCII');
 214          }
 215  
 216          if ($passLength != $blockSize) {
 217              $iterations = 1000;
 218              $salt       = $this->adapter->resizeKey($iv, 16);
 219              $key        = hash_pbkdf2('sha256', $this->key, $salt, $iterations, $blockSize, true);
 220          }
 221  
 222          return $key;
 223      }
 224  }
 225  
 226  if (!\function_exists('hash_pbkdf2')) {
 227      /**
 228       * Shim for missing hash_pbkdf2
 229       *
 230       * @param   string   $algo       Algorithm to use
 231       * @param   string   $password   Plaintext password
 232       * @param   string   $salt       Salt for the hash
 233       * @param   integer  $count      Number of iterations
 234       * @param   integer  $length     Length
 235       * @param   boolean  $rawOutput  Raw output
 236       *
 237       * @return   string  Hashed string
 238       */
 239      function hash_pbkdf2($algo, $password, $salt, $count, $length = 0, $rawOutput = false)
 240      {
 241          if (!\in_array(strtolower($algo), hash_algos())) {
 242              trigger_error(__FUNCTION__ . '(): Unknown hashing algorithm: ' . $algo, E_USER_WARNING);
 243          }
 244  
 245          if (!is_numeric($count)) {
 246              trigger_error(__FUNCTION__ . '(): expects parameter 4 to be long, ' . \gettype($count) . ' given', E_USER_WARNING);
 247          }
 248  
 249          if (!is_numeric($length)) {
 250              trigger_error(__FUNCTION__ . '(): expects parameter 5 to be long, ' . \gettype($length) . ' given', E_USER_WARNING);
 251          }
 252  
 253          if ($count <= 0) {
 254              trigger_error(__FUNCTION__ . '(): Iterations must be a positive integer: ' . $count, E_USER_WARNING);
 255          }
 256  
 257          if ($length < 0) {
 258              trigger_error(__FUNCTION__ . '(): Length must be greater than or equal to 0: ' . $length, E_USER_WARNING);
 259          }
 260  
 261          $output      = '';
 262          $block_count = $length ? ceil($length / \strlen(hash($algo, '', $rawOutput))) : 1;
 263  
 264          for ($i = 1; $i <= $block_count; $i++) {
 265              $last = $xorsum = hash_hmac($algo, $salt . pack('N', $i), $password, true);
 266  
 267              for ($j = 1; $j < $count; $j++) {
 268                  $xorsum ^= ($last = hash_hmac($algo, $last, $password, true));
 269              }
 270  
 271              $output .= $xorsum;
 272          }
 273  
 274          if (!$rawOutput) {
 275              $output = bin2hex($output);
 276          }
 277  
 278          return $length ? substr($output, 0, $length) : $output;
 279      }
 280  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer