/**
  * Formats a password using the current encryption.
  *
  * @param   string   $plaintext     The plaintext password to encrypt.
  * @param   string   $salt          The salt to use to encrypt the password. []
  *                                  If not present, a new salt will be
  *                                  generated.
  * @param   string   $encryption    The kind of password encryption to use.
  *                                  Defaults to md5-hex.
  * @param   boolean  $show_encrypt  Some password systems prepend the kind of
  *                                  encryption to the crypted password ({SHA},
  *                                  etc). Defaults to false.
  *
  * @return  string  The encrypted password.
  *
  * @since   11.1
  * @note    In Joomla! CMS 3.2 the default encrytion has been changed to bcrypt. When PHP 5.5 is the minimum
  *          supported version it will be changed to the PHP PASSWORD_DEFAULT constant.
  */
 public static function getCryptedPassword($plaintext, $salt = '', $encryption = 'bcrypt', $show_encrypt = false)
 {
     $app = JFactory::getApplication();
     if ($app->getClientId() != 2) {
         $joomlaPluginEnabled = JPluginHelper::isEnabled('user', 'joomla');
     }
     // The Joomla user plugin allows you to use weaker passwords if necessary.
     if (!empty($joomlaPluginEnabled)) {
         JPluginHelper::importPlugin('user', 'joomla');
         $userPlugin = JPluginHelper::getPlugin('user', 'joomla');
         $userPluginParams = new JRegistry($userPlugin->params);
         PlgUserJoomla::setDefaultEncryption($userPluginParams);
     }
     // Not all controllers check the length, although they should to avoid DOS attacks.
     // The maximum password length for bcrypt is 55:
     if (strlen($plaintext) > 55) {
         $app->enqueueMessage(JText::_('JLIB_USER_ERROR_PASSWORD_TOO_LONG'), 'error');
         return false;
     }
     // Get the salt to use.
     if (empty($salt)) {
         $salt = self::getSalt($encryption, $salt, $plaintext);
     }
     // Encrypt the password.
     switch ($encryption) {
         case 'plain':
             return $plaintext;
         case 'sha':
             $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext));
             return $show_encrypt ? '{SHA}' . $encrypted : $encrypted;
         case 'crypt':
         case 'crypt-des':
         case 'crypt-md5':
         case 'crypt-blowfish':
             return ($show_encrypt ? '{crypt}' : '') . crypt($plaintext, $salt);
         case 'md5-base64':
             $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext));
             return $show_encrypt ? '{MD5}' . $encrypted : $encrypted;
         case 'ssha':
             $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext . $salt) . $salt);
             return $show_encrypt ? '{SSHA}' . $encrypted : $encrypted;
         case 'smd5':
             $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext . $salt) . $salt);
             return $show_encrypt ? '{SMD5}' . $encrypted : $encrypted;
         case 'aprmd5':
             $length = strlen($plaintext);
             $context = $plaintext . '$apr1$' . $salt;
             $binary = self::_bin(md5($plaintext . $salt . $plaintext));
             for ($i = $length; $i > 0; $i -= 16) {
                 $context .= substr($binary, 0, $i > 16 ? 16 : $i);
             }
             for ($i = $length; $i > 0; $i >>= 1) {
                 $context .= $i & 1 ? chr(0) : $plaintext[0];
             }
             $binary = self::_bin(md5($context));
             for ($i = 0; $i < 1000; $i++) {
                 $new = $i & 1 ? $plaintext : substr($binary, 0, 16);
                 if ($i % 3) {
                     $new .= $salt;
                 }
                 if ($i % 7) {
                     $new .= $plaintext;
                 }
                 $new .= $i & 1 ? substr($binary, 0, 16) : $plaintext;
                 $binary = self::_bin(md5($new));
             }
             $p = array();
             for ($i = 0; $i < 5; $i++) {
                 $k = $i + 6;
                 $j = $i + 12;
                 if ($j == 16) {
                     $j = 5;
                 }
                 $p[] = self::_toAPRMD5(ord($binary[$i]) << 16 | ord($binary[$k]) << 8 | ord($binary[$j]), 5);
             }
             return '$apr1$' . $salt . '$' . implode('', $p) . self::_toAPRMD5(ord($binary[11]), 3);
         case 'md5-hex':
             $encrypted = $salt ? md5($plaintext . $salt) : md5($plaintext);
             return $show_encrypt ? '{MD5}' . $encrypted : $encrypted;
         case 'sha256':
             $encrypted = $salt ? hash('sha256', $plaintext . $salt) . ':' . $salt : hash('sha256', $plaintext);
             return $show_encrypt ? '{SHA256}' . $encrypted : '{SHA256}' . $encrypted;
             // 'bcrypt' is the default case starting in CMS 3.2.
         // 'bcrypt' is the default case starting in CMS 3.2.
         case 'bcrypt':
         default:
             $useStrongEncryption = JCrypt::hasStrongPasswordSupport();
             if ($useStrongEncryption === true) {
                 $encrypted = password_hash($plaintext, PASSWORD_BCRYPT);
                 if (!$encrypted) {
                     // Something went wrong fall back to sha256.
                     return static::getCryptedPassword($plaintext, '', 'sha256', false);
                 }
                 return $show_encrypt ? '{BCRYPT}' . $encrypted : $encrypted;
             } else {
                 // BCrypt isn't available but we want strong passwords, fall back to sha256.
                 return static::getCryptedPassword($plaintext, '', 'sha256', false);
             }
     }
 }
 /**
  * Method to bind an associative array of data to a user object
  *
  * @param   array  &$array  The associative array to bind to the object
  *
  * @return  boolean  True on success
  *
  * @since   11.1
  */
 public function bind(&$array)
 {
     // The Joomla user plugin allows you to use weaker passwords if necessary.
     $joomlaPluginEnabled = JPluginHelper::isEnabled('user', 'joomla');
     if ($joomlaPluginEnabled) {
         $userPlugin = JPluginHelper::getPlugin('user', 'joomla');
         $userPluginParams = new JRegistry($userPlugin->params);
         JPluginHelper::importPlugin('user', 'joomla');
         $defaultEncryption = PlgUserJoomla::setDefaultEncryption($userPluginParams);
     } else {
         $defaultEncryption = 'bcrypt';
     }
     // Let's check to see if the user is new or not
     if (empty($this->id)) {
         // Check the password and create the crypted password
         if (empty($array['password'])) {
             $array['password'] = JUserHelper::genRandomPassword();
             $array['password2'] = $array['password'];
         }
         // Not all controllers check the password, although they should.
         // Hence this code is required:
         if (isset($array['password2']) && $array['password'] != $array['password2']) {
             JFactory::getApplication()->enqueueMessage(JText::_('JLIB_USER_ERROR_PASSWORD_NOT_MATCH'), 'error');
             return false;
         }
         $this->password_clear = JArrayHelper::getValue($array, 'password', '', 'string');
         $salt = JUserHelper::genRandomPassword(32);
         $crypt = JUserHelper::getCryptedPassword($array['password'], $salt, $defaultEncryption);
         $array['password'] = $crypt;
         // Set the registration timestamp
         $this->set('registerDate', JFactory::getDate()->toSql());
         // Check that username is not greater than 150 characters
         $username = $this->get('username');
         if (strlen($username) > 150) {
             $username = substr($username, 0, 150);
             $this->set('username', $username);
         }
         // Use a limit to prevent abuse since it is unfiltered
         // The maximum password length for bcrypt is 55 characters.
         $password = $this->get('password');
         if (strlen($password) > 55) {
             $password = substr($password, 0, 55);
             $this->set('password', $password);
             JFactory::getApplication()->enqueueMessage(JText::_('JLIB_USER_ERROR_PASSWORD_TRUNCATED'), 'notice');
         }
     } else {
         // Updating an existing user
         if (!empty($array['password'])) {
             if ($array['password'] != $array['password2']) {
                 $this->setError(JText::_('JLIB_USER_ERROR_PASSWORD_NOT_MATCH'));
                 return false;
             }
             $this->password_clear = JArrayHelper::getValue($array, 'password', '', 'string');
             $salt = JUserHelper::genRandomPassword(32);
             $crypt = JUserHelper::getCryptedPassword($array['password'], $salt, $defaultEncryption);
             $array['password'] = $crypt . ':' . $salt;
         } else {
             $array['password'] = $this->password;
         }
     }
     if (array_key_exists('params', $array)) {
         $this->_params->loadArray($array['params']);
         if (is_array($array['params'])) {
             $params = (string) $this->_params;
         } else {
             $params = $array['params'];
         }
         $this->params = $params;
     }
     // Bind the array
     if (!$this->setProperties($array)) {
         $this->setError(JText::_('JLIB_USER_ERROR_BIND_ARRAY'));
         return false;
     }
     // Make sure its an integer
     $this->id = (int) $this->id;
     return true;
 }