我偶尔会听到“使用bcrypt在PHP中存储密码,bcrypt规则”的建议。php
可是什么bcrypt
?PHP不提供任何这样的功能,维基百科关于文件加密实用程序的喋喋不休,Web搜索只是揭示了几种不一样语言的Blowfish实现。如今Blowfish也能够经过PHP得到mcrypt
,但这对于存储密码有什么帮助?河豚是一种通用密码,它有两种工做方式。若是它能够被加密,它能够被解密。密码须要单向散列函数。html
什么是解释?node
bcrypt
是一种哈希算法,能够经过硬件进行扩展(经过可配置的循环次数)。其缓慢和多轮确保攻击者必须部署大量资金和硬件才能破解密码。添加到每一个密码盐(bcrypt
须要盐),你能够确定的是,一个攻击其实是不可行的,没有好笑的金额或硬件。git
bcrypt
使用Eksblowfish算法来散列密码。虽然Eksblowfish和Blowfish的加密阶段彻底相同,但Eksblowfish的关键调度阶段确保任何后续状态都依赖salt和key(用户密码),而且在没有二者都知道的状况下不能预先计算状态。因为这个关键差别,bcrypt
是一种单向哈希算法。若是不知道盐,圆和密码(密码),则没法检索纯文本密码。[ 来源 ]github
密码散列函数如今已直接构建到PHP> = 5.5中。您如今可使用password_hash()
建立bcrypt
任何密码的哈希值:算法
<?php // Usage 1: echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n"; // $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // For example: // $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a // Usage 2: $options = [ 'cost' => 11 ]; echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n"; // $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C
要根据现有的散列验证用户提供的密码,可使用如下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.'; }
GitHub上有一个兼容库,它基于上面用C编写的函数的源代码,它提供了相同的功能。安装兼容性库后,用法与上述相同(若是仍在5.3.x分支上,则减去速记数组表示法)。dom
您可使用crypt()
函数来生成输入字符串的bcrypt散列。这个类能够自动生成salt并根据输入验证现有的散列。若是您使用的PHP版本高于或等于5.3.7,强烈建议您使用内置函数或compat库。此替代方案仅用于历史目的。函数
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; } }
你可使用这样的代码:ui
或者,您也可使用Portable PHP Hashing Framework$bcrypt = new Bcrypt(15); $hash = $bcrypt->hash('password'); $isGood = $bcrypt->verify('password', $hash);