diff options
Diffstat (limited to 'Core/Encoder')
-rw-r--r-- | Core/Encoder/BCryptPasswordEncoder.php | 117 | ||||
-rw-r--r-- | Core/Encoder/Pbkdf2PasswordEncoder.php | 2 |
2 files changed, 27 insertions, 92 deletions
diff --git a/Core/Encoder/BCryptPasswordEncoder.php b/Core/Encoder/BCryptPasswordEncoder.php index 1b7572d..9349291 100644 --- a/Core/Encoder/BCryptPasswordEncoder.php +++ b/Core/Encoder/BCryptPasswordEncoder.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Core\Encoder; use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder; -use Symfony\Component\Security\Core\Util\SecureRandomInterface; /** * @author Elnur Abdurrakhimov <elnur@elnur.pro> @@ -21,128 +20,64 @@ use Symfony\Component\Security\Core\Util\SecureRandomInterface; class BCryptPasswordEncoder extends BasePasswordEncoder { /** - * @var SecureRandomInterface - */ - private $secureRandom; - - /** * @var string */ private $cost; - private static $prefix = null; - /** * Constructor. * - * @param SecureRandomInterface $secureRandom A SecureRandomInterface instance - * @param integer $cost The algorithmic cost that should be used + * @param integer $cost The algorithmic cost that should be used * * @throws \InvalidArgumentException if cost is out of range */ - public function __construct(SecureRandomInterface $secureRandom, $cost) + public function __construct($cost) { - $this->secureRandom = $secureRandom; + if (!function_exists('password_hash')) { + throw new \RuntimeException('To use the BCrypt encoder, you need to upgrade to PHP 5.5 or install the "ircmaxell/password-compat" via Composer.'); + } $cost = (int) $cost; if ($cost < 4 || $cost > 31) { throw new \InvalidArgumentException('Cost must be in the range of 4-31.'); } - $this->cost = sprintf('%02d', $cost); - - if (!self::$prefix) { - self::$prefix = '$'.(version_compare(phpversion(), '5.3.7', '>=') ? '2y' : '2a').'$'; - } - } - - /** - * {@inheritdoc} - */ - public function encodePassword($raw, $salt) - { - if (function_exists('password_hash')) { - return password_hash($raw, PASSWORD_BCRYPT, array('cost' => $this->cost)); - } - - $salt = self::$prefix.$this->cost.'$'.$this->encodeSalt($this->getRawSalt()); - $encoded = crypt($raw, $salt); - if (!is_string($encoded) || strlen($encoded) <= 13) { - return false; - } - - return $encoded; - } - - /** - * {@inheritdoc} - */ - public function isPasswordValid($encoded, $raw, $salt) - { - if (function_exists('password_verify')) { - return password_verify($raw, $encoded); - } - $crypted = crypt($raw, $encoded); - if (strlen($crypted) <= 13) { - return false; - } - - return $this->comparePasswords($encoded, $crypted); + $this->cost = $cost; } /** - * Encodes the salt to be used by Bcrypt. + * Encodes the raw password. + * + * It doesn't work with PHP versions lower than 5.3.7, since + * the password compat library uses CRYPT_BLOWFISH hash type with + * the "$2y$" salt prefix (which is not available in the early PHP versions). + * @see https://github.com/ircmaxell/password_compat/issues/10#issuecomment-11203833 * - * The blowfish/bcrypt algorithm used by PHP crypt expects a different - * set and order of characters than the usual base64_encode function. - * Regular b64: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ - * Bcrypt b64: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 - * We care because the last character in our encoded string will - * only represent 2 bits. While two known implementations of - * bcrypt will happily accept and correct a salt string which - * has the 4 unused bits set to non-zero, we do not want to take - * chances and we also do not want to waste an additional byte - * of entropy. + * It is almost best to **not** pass a salt and let PHP generate one for you. * - * @param bytes $random a string of 16 random bytes + * @param string $raw The password to encode + * @param string $salt The salt * - * @return string Properly encoded salt to use with php crypt function + * @return string The encoded password * - * @throws \InvalidArgumentException if string of random bytes is too short + * @link http://lxr.php.net/xref/PHP_5_5/ext/standard/password.c#111 */ - protected function encodeSalt($random) + public function encodePassword($raw, $salt) { - $len = strlen($random); - if ($len < 16) { - throw new \InvalidArgumentException('The bcrypt salt needs 16 random bytes.'); - } - if ($len > 16) { - $random = substr($random, 0, 16); - } + $options = array('cost' => $this->cost); - $base64raw = str_replace('+', '.', base64_encode($random)); - $salt128bit = substr($base64raw, 0, 21); - $lastchar = substr($base64raw, 21, 1); - $lastchar = strtr($lastchar, 'AQgw', '.Oeu'); - $salt128bit .= $lastchar; + if ($salt) { + $options['salt'] = $salt; + } - return $salt128bit; + return password_hash($raw, PASSWORD_BCRYPT, $options); } /** - * @return bytes 16 random bytes to be used in the salt + * {@inheritdoc} */ - protected function getRawSalt() + public function isPasswordValid($encoded, $raw, $salt) { - $rawSalt = false; - $numBytes = 16; - if (function_exists('mcrypt_create_iv')) { - $rawSalt = mcrypt_create_iv($numBytes, MCRYPT_DEV_URANDOM); - } - if (!$rawSalt) { - $rawSalt = $this->secureRandom->nextBytes($numBytes); - } - - return $rawSalt; + return password_verify($raw, $encoded); } } diff --git a/Core/Encoder/Pbkdf2PasswordEncoder.php b/Core/Encoder/Pbkdf2PasswordEncoder.php index 656545f..4f37ba3 100644 --- a/Core/Encoder/Pbkdf2PasswordEncoder.php +++ b/Core/Encoder/Pbkdf2PasswordEncoder.php @@ -82,7 +82,7 @@ class Pbkdf2PasswordEncoder extends BasePasswordEncoder $digest = ''; for ($i = 1; $i <= $blocks; $i++) { - $ib = $block = hash_hmac($algorithm, $salt . pack('N', $i), $password, true); + $ib = $block = hash_hmac($algorithm, $salt.pack('N', $i), $password, true); // Iterations for ($j = 1; $j < $iterations; $j++) { |