|
12 | 12 | namespace Symfony\Component\Security\Core\Encoder;
|
13 | 13 |
|
14 | 14 | use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
|
15 |
| -use Symfony\Component\Security\Core\Util\SecureRandomInterface; |
16 | 15 |
|
17 | 16 | /**
|
18 | 17 | * @author Elnur Abdurrakhimov <[email protected]>
|
19 | 18 | * @author Terje Bråten <[email protected]>
|
20 | 19 | */
|
21 | 20 | class BCryptPasswordEncoder extends BasePasswordEncoder
|
22 | 21 | {
|
23 |
| - /** |
24 |
| - * @var SecureRandomInterface |
25 |
| - */ |
26 |
| - private $secureRandom; |
27 |
| - |
28 | 22 | /**
|
29 | 23 | * @var string
|
30 | 24 | */
|
31 | 25 | private $cost;
|
32 | 26 |
|
33 |
| - private static $prefix = null; |
34 |
| - |
35 | 27 | /**
|
36 | 28 | * Constructor.
|
37 | 29 | *
|
38 |
| - * @param SecureRandomInterface $secureRandom A SecureRandomInterface instance |
39 |
| - * @param integer $cost The algorithmic cost that should be used |
| 30 | + * @param integer $cost The algorithmic cost that should be used |
40 | 31 | *
|
41 | 32 | * @throws \InvalidArgumentException if cost is out of range
|
42 | 33 | */
|
43 |
| - public function __construct(SecureRandomInterface $secureRandom, $cost) |
| 34 | + public function __construct($cost) |
44 | 35 | {
|
45 |
| - $this->secureRandom = $secureRandom; |
46 |
| - |
47 | 36 | $cost = (int) $cost;
|
48 | 37 | if ($cost < 4 || $cost > 31) {
|
49 | 38 | throw new \InvalidArgumentException('Cost must be in the range of 4-31.');
|
50 | 39 | }
|
51 |
| - $this->cost = sprintf('%02d', $cost); |
52 | 40 |
|
53 |
| - if (!self::$prefix) { |
54 |
| - self::$prefix = '$'.(version_compare(phpversion(), '5.3.7', '>=') ? '2y' : '2a').'$'; |
55 |
| - } |
| 41 | + $this->cost = sprintf('%02d', $cost); |
56 | 42 | }
|
57 | 43 |
|
58 | 44 | /**
|
59 | 45 | * {@inheritdoc}
|
60 | 46 | */
|
61 | 47 | public function encodePassword($raw, $salt)
|
62 | 48 | {
|
63 |
| - if (function_exists('password_hash')) { |
64 |
| - return password_hash($raw, PASSWORD_BCRYPT, array('cost' => $this->cost)); |
65 |
| - } |
66 |
| - |
67 |
| - $salt = self::$prefix.$this->cost.'$'.$this->encodeSalt($this->getRawSalt()); |
68 |
| - $encoded = crypt($raw, $salt); |
69 |
| - if (!is_string($encoded) || strlen($encoded) <= 13) { |
70 |
| - return false; |
71 |
| - } |
72 |
| - |
73 |
| - return $encoded; |
| 49 | + return password_hash($raw, PASSWORD_BCRYPT, array( |
| 50 | + 'cost' => $this->cost, |
| 51 | + )); |
74 | 52 | }
|
75 | 53 |
|
76 | 54 | /**
|
77 | 55 | * {@inheritdoc}
|
78 | 56 | */
|
79 | 57 | public function isPasswordValid($encoded, $raw, $salt)
|
80 | 58 | {
|
81 |
| - if (function_exists('password_verify')) { |
82 |
| - return password_verify($raw, $encoded); |
83 |
| - } |
84 |
| - |
85 |
| - $crypted = crypt($raw, $encoded); |
86 |
| - if (strlen($crypted) <= 13) { |
87 |
| - return false; |
88 |
| - } |
89 |
| - |
90 |
| - return $this->comparePasswords($encoded, $crypted); |
91 |
| - } |
92 |
| - |
93 |
| - /** |
94 |
| - * Encodes the salt to be used by Bcrypt. |
95 |
| - * |
96 |
| - * The blowfish/bcrypt algorithm used by PHP crypt expects a different |
97 |
| - * set and order of characters than the usual base64_encode function. |
98 |
| - * Regular b64: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ |
99 |
| - * Bcrypt b64: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 |
100 |
| - * We care because the last character in our encoded string will |
101 |
| - * only represent 2 bits. While two known implementations of |
102 |
| - * bcrypt will happily accept and correct a salt string which |
103 |
| - * has the 4 unused bits set to non-zero, we do not want to take |
104 |
| - * chances and we also do not want to waste an additional byte |
105 |
| - * of entropy. |
106 |
| - * |
107 |
| - * @param bytes $random a string of 16 random bytes |
108 |
| - * |
109 |
| - * @return string Properly encoded salt to use with php crypt function |
110 |
| - * |
111 |
| - * @throws \InvalidArgumentException if string of random bytes is too short |
112 |
| - */ |
113 |
| - protected function encodeSalt($random) |
114 |
| - { |
115 |
| - $len = strlen($random); |
116 |
| - if ($len < 16) { |
117 |
| - throw new \InvalidArgumentException('The bcrypt salt needs 16 random bytes.'); |
118 |
| - } |
119 |
| - if ($len > 16) { |
120 |
| - $random = substr($random, 0, 16); |
121 |
| - } |
122 |
| - |
123 |
| - $base64raw = str_replace('+', '.', base64_encode($random)); |
124 |
| - $salt128bit = substr($base64raw, 0, 21); |
125 |
| - $lastchar = substr($base64raw, 21, 1); |
126 |
| - $lastchar = strtr($lastchar, 'AQgw', '.Oeu'); |
127 |
| - $salt128bit .= $lastchar; |
128 |
| - |
129 |
| - return $salt128bit; |
130 |
| - } |
131 |
| - |
132 |
| - /** |
133 |
| - * @return bytes 16 random bytes to be used in the salt |
134 |
| - */ |
135 |
| - protected function getRawSalt() |
136 |
| - { |
137 |
| - $rawSalt = false; |
138 |
| - $numBytes = 16; |
139 |
| - if (function_exists('mcrypt_create_iv')) { |
140 |
| - $rawSalt = mcrypt_create_iv($numBytes, MCRYPT_DEV_URANDOM); |
141 |
| - } |
142 |
| - if (!$rawSalt) { |
143 |
| - $rawSalt = $this->secureRandom->nextBytes($numBytes); |
144 |
| - } |
145 |
| - |
146 |
| - return $rawSalt; |
| 59 | + return password_verify($raw, $encoded); |
147 | 60 | }
|
148 | 61 | }
|
0 commit comments