Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
506 views
in Technique[技术] by (71.8m points)

php - 如何使用bcrypt在PHP中对密码进行哈希处理?(How do you use bcrypt for hashing passwords in PHP?)

Every now and then I hear the advice "Use bcrypt for storing passwords in PHP, bcrypt rules".

(我时不时听到“使用bcrypt在PHP中使用密码,bcrypt规则存储密码”的建议。)

But what is bcrypt ?

(但是bcrypt是什么?)

PHP doesn't offer any such functions, Wikipedia babbles about a file-encryption utility and Web searches just reveal a few implementations of Blowfish in different languages.

(PHP不提供任何此类功能,维基百科对文件加密实用程序不屑一顾,而Web搜索仅显示了几种以不同语言实现的Blowfish实现。)

Now Blowfish is also available in PHP via mcrypt , but how does that help with storing passwords?

(现在Blowfish也可以通过mcrypt在PHP中使用,但这对存储密码有何帮助?)

Blowfish is a general purpose cipher, it works two ways.

(河豚是一种通用密码,它有两种工作方式。)

If it could be encrypted, it can be decrypted.

(如果可以加密,则可以解密。)

Passwords need a one-way hashing function.

(密码需要单向散列功能。)

What is the explanation?

(有什么解释?)

  ask by Vilx- translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

bcrypt is a hashing algorithm which is scalable with hardware (via a configurable number of rounds).

(bcrypt是一种哈希算法,可通过硬件(通过可配置的回合数)进行扩展。)

Its slowness and multiple rounds ensures that an attacker must deploy massive funds and hardware to be able to crack your passwords.

(它的缓慢性和多次回合确保了攻击者必须部署大量资金和硬件才能破解您的密码。)

Add to that per-password salts ( bcrypt REQUIRES salts) and you can be sure that an attack is virtually unfeasible without either ludicrous amount of funds or hardware.

(加上每个密码的bcrypt需要盐),您可以确定,在没有可笑的资金或硬件的情况下,攻击实际上是不可行的。)

bcrypt uses the Eksblowfish algorithm to hash passwords.

(bcrypt使用Eksblowfish算法对密码进行哈希处理。)

While the encryption phase of Eksblowfish and Blowfish are exactly the same, the key schedule phase of Eksblowfish ensures that any subsequent state depends on both salt and key (user password), and no state can be precomputed without the knowledge of both.

(虽然EksblowfishBlowfish的加密阶段完全相同,但是Eksblowfish的密钥调度阶段可确保任何后续状态都取决于salt和密钥(用户密码),并且在不了解这两个状态的情况下无法对它们进行预先计算。)

Because of this key difference, bcrypt is a one-way hashing algorithm.

(由于存在密钥差异,因此bcrypt是一种单向哈希算法。)

You cannot retrieve the plain text password without already knowing the salt, rounds and key (password).

(在不知道盐,四舍五入和密钥 (密码)的情况下,您无法检索纯文本密码。)

[ Source ]

([ 来源 ])

How to use bcrypt: (如何使用bcrypt:)

Using PHP >= 5.5-DEV (使用PHP> = 5.5-DEV)

Password hashing functions have now been built directly into PHP >= 5.5 .

(密码哈希函数现已直接内置到PHP> = 5.5中 。)

You may now use password_hash() to create a bcrypt hash of any password:

(您现在可以使用password_hash()创建任何密码的bcrypt哈希:)

<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."
";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

// Usage 2:
$options = [
  'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."
";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

To verify a user provided password against an existing hash, you may use the password_verify() as such:

(要针对现有哈希值验证用户提供的密码,您可以这样使用password_verify() :)

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

Using PHP >= 5.3.7, < 5.5-DEV (also RedHat PHP >= 5.3.3) (使用PHP> = 5.3.7,<5.5-DEV(也是RedHat PHP> = 5.3.3))

There is a compatibility library on GitHub created based on the source code of the above functions originally written in C, which provides the same functionality.

(GitHub上有一个兼容性库 ,该兼容性库是基于最初用C编写的上述函数的源代码创建的,该提供相同的功能。)

Once the compatibility library is installed, usage is the same as above (minus the shorthand array notation if you are still on the 5.3.x branch).

(一旦安装了兼容性库,用法与上面相同(如果仍在5.3.x分支上,请减去简写数组表示法)。)

Using PHP < 5.3.7 (DEPRECATED) (使用PHP <5.3.7 (不建议使用)

You can use crypt() function to generate bcrypt hashes of input strings.

(您可以使用crypt()函数生成输入字符串的bcrypt哈希。)

This class can automatically generate salts and verify existing hashes against an input.

(此类可以自动生成盐,并根据输入来验证现有哈希。)

If you are using a version of PHP higher or equal to 5.3.7, it is highly recommended you use the built-in function or the compat library .

(如果您使用的PHP版本高于或等于5.3.7,则强烈建议您使用内置函数或compat库 。)

This alternative is provided only for historical purposes.

(仅出于历史目的提供此替代方法。)

class Bcrypt{
  private $rounds;

  public function __construct($rounds = 12) {
    if (CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->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 $randomState;
  private function getRandomBytes($count){
    $bytes = '';

    if (function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
      $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 (true);

    return $output;
  }
}

You can use this code like this:

(您可以使用以下代码:)

$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);

Alternatively, you may also use the Portable PHP Hashing Framework .

(另外,您也可以使用Portable PHP Hashing Framework 。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...