public function compute($password, User $user)
 {
     $fields = ['name', 'email', 'familyName', 'firstName'];
     $parts = [];
     $index = 1;
     foreach ($fields as $field) {
         foreach (preg_split('~[@._\\s+]~', $user->{$field}) as $part) {
             $parts[$part] = $index++;
             $parts[Strings::toAscii($part)] = $index++;
         }
     }
     try {
         $result = $this->computer->passwordStrength($password, $parts);
     } catch (\Exception $e) {
         return NULL;
     }
     return number_format($result['entropy'], 2);
 }
 /**
  * @inheritdoc
  */
 public function validateAttribute($model, $attribute)
 {
     if (!in_array($this->minScore, [1, 2, 3, 4])) {
         throw new InvalidConfigException('The "minScore" property must be in range 1-4.');
     }
     $value = $model->{$attribute};
     if ($this->allowEmpty && $this->isEmpty($value)) {
         return null;
     }
     $zxcvbn = new Zxcvbn();
     $strength = $zxcvbn->passwordStrength($value);
     $score = ArrayHelper::getValue($strength, 'score');
     if ($score < $this->minScore) {
         $message = $this->message !== null ? $this->message : 'A weak password. Use uppercase and lowercase letters, numbers and special characters.';
         $this->addError($model, $attribute, $message);
     }
 }
Beispiel #3
0
 public function testZxcvbn()
 {
     $zxcvbn = new Zxcvbn();
     $result = $zxcvbn->passwordStrength("");
     $this->assertEquals(0, $result['entropy'], "Entropy incorrect");
     $this->assertEquals(0, $result['score'], "Score incorrect");
     $result = $zxcvbn->passwordStrength("password");
     $this->assertEquals(0, $result['entropy'], "Entropy incorrect");
     $this->assertEquals(0, $result['score'], "Score incorrect");
     $result = $zxcvbn->passwordStrength("jjjjj");
     $this->assertSame('repeat', $result['match_sequence'][0]->pattern, "Pattern incorrect");
     $password = '******';
     $result = $zxcvbn->passwordStrength($password);
     $this->assertEquals(1, $result['score'], "Score incorrect");
     $password = '******';
     $result = $zxcvbn->passwordStrength($password);
     $this->assertEquals(4, $result['score'], "Score incorrect");
     $password = '******';
     $result = $zxcvbn->passwordStrength($password, array($password));
     $this->assertEquals(0, $result['score'], "Score incorrect");
 }
Beispiel #4
0
 /**
  * Changes a user's password
  * @param int $uid
  * @param string $currpass
  * @param string $newpass
  * @param string $repeatnewpass
  * @param string $captcha = NULL
  * @return array $return
  */
 public function changePassword($uid, $currpass, $newpass, $repeatnewpass, $captcha = NULL)
 {
     $return['error'] = true;
     $block_status = $this->isBlocked();
     if ($block_status == "verify") {
         if ($this->checkCaptcha($captcha) == false) {
             $return['message'] = $this->lang["user_verify_failed"];
             return $return;
         }
     }
     if ($block_status == "block") {
         $return['message'] = $this->lang["user_blocked"];
         return $return;
     }
     $validatePassword = $this->validatePassword($currpass);
     if ($validatePassword['error'] == 1) {
         $this->addAttempt();
         $return['message'] = $validatePassword['message'];
         return $return;
     }
     $validatePassword = $this->validatePassword($newpass);
     if ($validatePassword['error'] == 1) {
         $return['message'] = $validatePassword['message'];
         return $return;
     } elseif ($newpass !== $repeatnewpass) {
         $return['message'] = $this->lang["newpassword_nomatch"];
         return $return;
     }
     $zxcvbn = new Zxcvbn();
     if ($zxcvbn->passwordStrength($newpass)['score'] < intval($this->config->password_min_score)) {
         $return['message'] = $this->lang['password_weak'];
         return $return;
     }
     $user = $this->getBaseUser($uid);
     if (!$user) {
         $this->addAttempt();
         $return['message'] = $this->lang["system_error"] . " #13";
         return $return;
     }
     if (!password_verify($currpass, $user['password'])) {
         $this->addAttempt();
         $return['message'] = $this->lang["password_incorrect"];
         return $return;
     }
     $newpass = $this->getHash($newpass);
     $query = $this->dbh->prepare("UPDATE {$this->config->table_users} SET password = ? WHERE id = ?");
     $query->execute(array($newpass, $uid));
     $return['error'] = false;
     $return['message'] = $this->lang["password_changed"];
     return $return;
 }
Beispiel #5
0
 /**
  * Execute the keygen command
  *
  * @param array $args - CLI arguments
  * @echo
  * @return null
  * @throws \Error
  */
 public function fire(array $args = [])
 {
     if (count($this->config['suppliers']) === 1) {
         $supplier = \count($args) > 0 ? $args[0] : \array_keys($this->config['suppliers'])[0];
     } else {
         $supplier = \count($args) > 0 ? $args[0] : $this->prompt("Please enter the name of the supplier: ");
     }
     if (!\array_key_exists($supplier, $this->config['suppliers'])) {
         echo 'Please authenticate before attempting to generate a key.', "\n";
         echo 'Run this command: ', $this->c['yellow'], 'barge login', $this->c[''], "\n";
         exit(255);
     }
     if (\count($this->config['suppliers'][$supplier]['signing_keys']) === 0) {
         // Your first key is a master key; always.
         $has_master = false;
         $key_type = 'master';
     } else {
         $has_master = true;
         echo 'Please enter the key type you would like to generate (master, signing).', "\n";
         do {
             $key_type = $this->prompt('Key type: ');
             switch ($key_type) {
                 case 'm':
                 case 'main':
                 case 'master':
                 case 'primary':
                     $key_type = 'master';
                     break;
                 case 's':
                 case 'secondary':
                 case 'sub':
                 case 'subkey':
                 case 'signing':
                     $key_type = 'signing';
                     break;
                 default:
                     echo 'Acceptable key types: master, signing', "\n";
                     $key_type = null;
             }
         } while (empty($key_type));
     }
     // Each key gets its own unique Argon2 salt
     echo 'Generating a unique salt...', "\n";
     $salt = \random_bytes(\Sodium\CRYPTO_PWHASH_SALTBYTES);
     $store_in_cloud = null;
     // This is optional and not recommended, but some people prefer convenience.
     // We really hope this is adequate information to make an informed choice
     // based on personal risk tolerance:
     echo 'Do you wish to store the salt for generating your signing key in the Skyport?', "\n";
     echo 'This is a security-convenience trade-off. The default is NO.', "\n\n";
     echo $this->c['green'], 'Pro:', $this->c[''], ' It\'s there if you need it, and the salt alone is not enough for us to', "\n", '     reproduce your signing key.', "\n";
     echo $this->c['red'], 'Con:', $this->c[''], ' If your salt is stored online, the security of your signing key depends', "\n", '     entirely on your password.', "\n\n";
     // Iterate until we get a valid response
     while ($store_in_cloud === null) {
         $choice = $this->prompt('Store salt in the Skyport? (y/N): ');
         switch ($choice) {
             case 'YES':
             case 'yes':
             case 'Y':
             case 'y':
                 $store_in_cloud = true;
                 break;
             case 'N':
             case 'NO':
             case 'n':
             case 'no':
             case '':
                 // Just pressing enter means "don't store it"!
                 $store_in_cloud = false;
                 break;
             default:
                 echo "\n", $this->c['yellow'], 'Invalid response. Please enter yes or no.', $this->c[''], "\n";
         }
     }
     $zxcvbn = new Zxcvbn();
     $userInput = $this->getZxcvbnKeywords($supplier);
     // If we're storing in the cloud, our standards should be much higher.
     $min_score = $store_in_cloud ? 3 : 2;
     do {
         // Next, let's get a password.
         echo 'Please enter a strong passphrase to use for your signing key.', "\n";
         $password = $this->silentPrompt("Passphrase:");
         $password2 = $this->silentPrompt("Confirm passphrase:");
         if (!\hash_equals($password, $password2)) {
             unset($password);
             echo $this->c['red'], 'Passwords did not match!', $this->c[''], "\n";
             continue;
         }
         // Use zxcvbn to assess password strength
         $strength = $zxcvbn->passwordStrength($password, $userInput);
         if ($strength['score'] < $min_score) {
             echo $this->c['yellow'], 'Sorry, that password is not strong enough. Try making ', 'your password longer and use a wider variety of characters.', $this->c[''], "\n";
             $password = false;
         }
     } while (empty($password));
     echo 'Generating signing key...';
     if ($key_type === 'master') {
         // Master keys are treated as sensitive.
         $sign_level = KeyFactory::SENSITIVE;
     } else {
         // Signing keys (day-to-day) are still moderately sensitive.
         // We're using a KDF locally so we don't have DDoS concerns
         // (which usually calls for INTERACTIVE).
         $sign_level = KeyFactory::MODERATE;
     }
     $keyPair = KeyFactory::deriveSignatureKeyPair($password, $salt, false, $sign_level);
     $sign_public = $keyPair->getPublicKey();
     echo 'DONE!', "\n";
     // Wipe the password from memory
     \Sodium\memzero($password);
     // Store this in the configuration
     $new_key = ['date_generated' => \date('Y-m-d\\TH:i:s'), 'store_in_cloud' => $store_in_cloud, 'salt' => \Sodium\bin2hex($salt), 'public_key' => \Sodium\bin2hex($sign_public->getRawKeyMaterial()), 'type' => $key_type];
     // This is the message we are signing.
     $message = \json_encode(['action' => 'CREATE', 'date_generated' => $new_key['date_generated'], 'public_key' => $new_key['public_key'], 'supplier' => $supplier, 'type' => $new_key['type']]);
     if ($has_master) {
         list($masterSig, $masterPubKey) = $this->signNewKeyWithMasterKey($supplier, $message);
     } else {
         // This is our first key, so we don't need it.
         $masterSig = '';
         $masterPubKey = '';
     }
     // Save the configuration
     $this->config['suppliers'][$supplier]['signing_keys'][] = $new_key;
     // Send the public kay (and, maybe, the salt) to the Skyport.
     $response = $this->sendToSkyport($supplier, $new_key, $message, $masterSig, $masterPubKey);
     if (!empty($response['status'])) {
         if ($response['status'] === 'ERROR') {
             echo "Error message returned!\n";
             throw new \Error($response['message']);
         }
         $pk = Base64UrlSafe::encode(\Sodium\hex2bin($new_key['public_key']));
         if ($new_key['type'] === 'master') {
             echo 'New master key: ', $this->c['red'], $pk, $this->c[''], "\n";
         } else {
             echo 'New signing key: ', $this->c['yellow'], $pk, $this->c[''], "\n";
         }
     }
 }
Beispiel #6
0
 /**
  * 检测输入密码的强壮程度,并返回检测结果,结果越大,密码就越健壮
  *
  * @param $password
  * @return int
  */
 public static function strength($password)
 {
     $zxcvbn = new Zxcvbn();
     $result = $zxcvbn->passwordStrength($password);
     return (int) Arr::get($result, 'score');
 }
Beispiel #7
0
 /**
  * Is this password too weak?
  *
  * @param array $post
  * @return bool
  */
 public function isPasswordWeak(array $post) : bool
 {
     $zxcvbn = new Zxcvbn();
     $pw = $post['passphrase'];
     $userdata = \Airship\keySlice($post, ['username', 'display_name', 'realname', 'email']);
     $strength = $zxcvbn->passwordStrength($pw, \array_values($userdata));
     return $strength['score'] < 3;
 }