diff --git a/README.md b/README.md index 4fa2526..ff5c9b1 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,6 @@ Change your config main: 'modules'=>array( #... 'user'=>array( - # encrypting method (php hash function) - 'hash' => 'md5', - # send activation email 'sendActivationMail' => true, @@ -89,9 +86,6 @@ Change your config console: 'modules'=>array( #... 'user'=>array( - # encrypting method (php hash function) - 'hash' => 'md5', - # send activation email 'sendActivationMail' => true, diff --git a/UserModule.php b/UserModule.php index cc624a9..d7898da 100644 --- a/UserModule.php +++ b/UserModule.php @@ -158,18 +158,23 @@ public static function t($str='',$params=array(),$dic='user') { } /** + * Encrypt a password. * @return hash string. */ public static function encrypting($string="") { - $hash = Yii::app()->getModule('user')->hash; - if ($hash=="md5") - return md5($string); - if ($hash=="sha1") - return sha1($string); - else - return hash($hash,$string); + $bcrypt = new Bcrypt(); + return $bcrypt->hash($string); } - + + /** + * Verify if unencrypted password is same as encrypted hash. + * @return boolean + */ + public static function verifyPassword($password, $hash) { + $bcrypt = new Bcrypt(); + return $bcrypt->verify($password, $hash); + } + /** * @param $place * @return boolean diff --git a/components/Bcrypt.php b/components/Bcrypt.php new file mode 100644 index 0000000..ba7bda7 --- /dev/null +++ b/components/Bcrypt.php @@ -0,0 +1,107 @@ +rounds = $rounds; + } + + public function hash($input) { + $hash = crypt($input, $this->getSalt()); + + if(strlen($hash) > 13) + return $hash; + + return false; + } + + public function verify($input, $existingHash) { + $hash = crypt($input, $existingHash); + + return $hash === $existingHash; + } + + private function getSalt() { + $salt = sprintf('$2a$%02d$', $this->rounds); + + $bytes = $this->getRandomBytes(16); + + $salt .= $this->encodeBytes($bytes); + + return $salt; + } + + private function getRandomBytes($count) { + $bytes = ''; + + if(function_exists('openssl_random_pseudo_bytes') && + (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win + $bytes = openssl_random_pseudo_bytes($count); + } + + if($bytes === '' && is_readable('/dev/urandom') && + ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) { + $bytes = fread($hRand, $count); + fclose($hRand); + } + + if(strlen($bytes) < $count) { + $bytes = ''; + + if($this->randomState === null) { + $this->randomState = microtime(); + if(function_exists('getmypid')) { + $this->randomState .= getmypid(); + } + } + + for($i = 0; $i < $count; $i += 16) { + $this->randomState = md5(microtime() . $this->randomState); + + if (PHP_VERSION >= '5') { + $bytes .= md5($this->randomState, true); + } else { + $bytes .= pack('H*', md5($this->randomState)); + } + } + + $bytes = substr($bytes, 0, $count); + } + + return $bytes; + } + + private function encodeBytes($input) { + // The following is code from the PHP Password Hashing Framework + $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + + $output = ''; + $i = 0; + do { + $c1 = ord($input[$i++]); + $output .= $itoa64[$c1 >> 2]; + $c1 = ($c1 & 0x03) << 4; + if ($i >= 16) { + $output .= $itoa64[$c1]; + break; + } + + $c2 = ord($input[$i++]); + $c1 |= $c2 >> 4; + $output .= $itoa64[$c1]; + $c1 = ($c2 & 0x0f) << 2; + + $c2 = ord($input[$i++]); + $c1 |= $c2 >> 6; + $output .= $itoa64[$c1]; + $output .= $itoa64[$c2 & 0x3f]; + } while (1); + + return $output; + } +} diff --git a/components/UserIdentity.php b/components/UserIdentity.php index 6f8986c..d1ebc64 100644 --- a/components/UserIdentity.php +++ b/components/UserIdentity.php @@ -32,7 +32,7 @@ public function authenticate() } else { $this->errorCode=self::ERROR_USERNAME_INVALID; } - else if(Yii::app()->getModule('user')->encrypting($this->password)!==$user->password) + else if(!Yii::app()->getModule('user')->verifyPassword($this->password, $user->password)) $this->errorCode=self::ERROR_PASSWORD_INVALID; else if($user->status==0&&Yii::app()->getModule('user')->loginNotActiv==false) $this->errorCode=self::ERROR_STATUS_NOTACTIV; @@ -53,4 +53,4 @@ public function getId() { return $this->_id; } -} \ No newline at end of file +} diff --git a/controllers/ActivationController.php b/controllers/ActivationController.php index 13c3a47..b0e157d 100644 --- a/controllers/ActivationController.php +++ b/controllers/ActivationController.php @@ -16,7 +16,7 @@ public function actionActivation () { if (isset($find)&&$find->status) { $this->render('/user/message',array('title'=>UserModule::t("User activation"),'content'=>UserModule::t("You account is active."))); } elseif(isset($find->activkey) && ($find->activkey==$activkey)) { - $find->activkey = UserModule::encrypting(microtime()); + $find->activkey = md5(microtime()); $find->status = 1; $find->save(); $this->render('/user/message',array('title'=>UserModule::t("User activation"),'content'=>UserModule::t("You account is activated."))); @@ -28,4 +28,4 @@ public function actionActivation () { } } -} \ No newline at end of file +} diff --git a/controllers/AdminController.php b/controllers/AdminController.php index ab28421..184b412 100644 --- a/controllers/AdminController.php +++ b/controllers/AdminController.php @@ -81,7 +81,7 @@ public function actionCreate() if(isset($_POST['User'])) { $model->attributes=$_POST['User']; - $model->activkey=Yii::app()->controller->module->encrypting(microtime().$model->password); + $model->activkey=md5(microtime().$model->password); $profile->attributes=$_POST['Profile']; $profile->user_id=0; if($model->validate()&&$profile->validate()) { @@ -118,7 +118,7 @@ public function actionUpdate() $old_password = User::model()->notsafe()->findByPk($model->id); if ($old_password->password!=$model->password) { $model->password=Yii::app()->controller->module->encrypting($model->password); - $model->activkey=Yii::app()->controller->module->encrypting(microtime().$model->password); + $model->activkey=md5(microtime().$model->password); } $model->save(); $profile->save(); @@ -184,4 +184,4 @@ public function loadModel() return $this->_model; } -} \ No newline at end of file +} diff --git a/controllers/ProfileController.php b/controllers/ProfileController.php index 2eb3070..22b3f95 100644 --- a/controllers/ProfileController.php +++ b/controllers/ProfileController.php @@ -76,7 +76,7 @@ public function actionChangepassword() { if($model->validate()) { $new_password = User::model()->notsafe()->findbyPk(Yii::app()->user->id); $new_password->password = UserModule::encrypting($model->password); - $new_password->activkey=UserModule::encrypting(microtime().$model->password); + $new_password->activkey=md5(microtime().$model->password); $new_password->save(); Yii::app()->user->setFlash('profileMessage',UserModule::t("New password is saved.")); $this->redirect(array("profile")); @@ -102,4 +102,4 @@ public function loadUser() } return $this->_model; } -} \ No newline at end of file +} diff --git a/controllers/RecoveryController.php b/controllers/RecoveryController.php index 97d36bc..71781ee 100644 --- a/controllers/RecoveryController.php +++ b/controllers/RecoveryController.php @@ -22,7 +22,7 @@ public function actionRecovery () { $form2->attributes=$_POST['UserChangePassword']; if($form2->validate()) { $find->password = Yii::app()->controller->module->encrypting($form2->password); - $find->activkey=Yii::app()->controller->module->encrypting(microtime().$form2->password); + $find->activkey=md5(microtime().$form2->password); if ($find->status==0) { $find->status = 1; } @@ -64,4 +64,4 @@ public function actionRecovery () { } } -} \ No newline at end of file +} diff --git a/controllers/RegistrationController.php b/controllers/RegistrationController.php index 7890b65..e45b5e5 100644 --- a/controllers/RegistrationController.php +++ b/controllers/RegistrationController.php @@ -40,9 +40,9 @@ public function actionRegistration() { if($model->validate()&&$profile->validate()) { $soucePassword = $model->password; - $model->activkey=UserModule::encrypting(microtime().$model->password); + $model->activkey=md5(microtime().$model->password); $model->password=UserModule::encrypting($model->password); - $model->verifyPassword=UserModule::encrypting($model->verifyPassword); + $model->verifyPassword=$model->password; $model->superuser=0; $model->status=((Yii::app()->controller->module->activeAfterRegister)?User::STATUS_ACTIVE:User::STATUS_NOACTIVE); @@ -77,4 +77,4 @@ public function actionRegistration() { $this->render('/user/registration',array('model'=>$model,'profile'=>$profile)); } } -} \ No newline at end of file +} diff --git a/migrations/m110805_153437_installYiiUser.php b/migrations/m110805_153437_installYiiUser.php index 012d85c..78e9381 100644 --- a/migrations/m110805_153437_installYiiUser.php +++ b/migrations/m110805_153437_installYiiUser.php @@ -119,7 +119,7 @@ public function safeUp() "username" => $this->_model->username, "password" => Yii::app()->getModule('user')->encrypting($this->_model->password), "email" => "webmaster@example.com", - "activkey" => Yii::app()->getModule('user')->encrypting(microtime()), + "activkey" => md5(microtime()), "createtime" => time(), "lastvisit" => "0", "superuser" => "1", @@ -209,4 +209,4 @@ private function readStdinUser($prompt, $field, $default = '') { } return $input; } -} \ No newline at end of file +} diff --git a/models/UserChangePassword.php b/models/UserChangePassword.php index e1256f5..f628736 100644 --- a/models/UserChangePassword.php +++ b/models/UserChangePassword.php @@ -37,9 +37,10 @@ public function attributeLabels() /** * Verify Old Password */ - public function verifyOldPassword($attribute, $params) - { - if (User::model()->notsafe()->findByPk(Yii::app()->user->id)->password != Yii::app()->getModule('user')->encrypting($this->$attribute)) - $this->addError($attribute, UserModule::t("Old Password is incorrect.")); - } -} \ No newline at end of file + public function verifyOldPassword($attribute, $params) + { + $user = User::model()->notsafe()->findByPk(Yii::app()->user->id); + if (!Yii::app()->getModule('user')->verifyPassword($this->$attribute, $user->password)) + $this->addError($attribute, UserModule::t("Old Password is incorrect.")); + } +}