@@ -8,198 +8,41 @@ class DrupalPasswordEncoder implements PasswordEncoderInterface
88{
99 const DRUPAL_HASH_COUNT = 15 ;
1010
11+ /**
12+ * @var \Mdespeuilles\DrupalPasswordEncoderBundle\Services\Password\PhpassHashedPassword
13+ */
1114 protected $ drupalPasswordService ;
1215
16+ /**
17+ * DrupalPasswordEncoder constructor.
18+ */
1319 public function __construct ()
1420 {
1521 $ this ->drupalPasswordService = new PhpassHashedPassword (self ::DRUPAL_HASH_COUNT );
1622 }
1723
24+ /**
25+ * Encode a password to a Drupal way
26+ *
27+ * @param string $password
28+ * @param string $salt
29+ * @return string
30+ */
1831 public function encodePassword ($ password , $ salt )
1932 {
2033 return $ this ->drupalPasswordService ->hash ($ password );
21- //return $this->_password_crypt('sha512', $password, $this->_password_generate_salt(self::DRUPAL_HASH_COUNT));
2234 }
2335
36+ /**
37+ * Check if password is valid
38+ *
39+ * @param string $encoded
40+ * @param string $raw
41+ * @param string $salt
42+ * @return bool
43+ */
2444 public function isPasswordValid ($ encoded , $ raw , $ salt )
2545 {
2646 return $ this ->drupalPasswordService ->check ($ raw , $ encoded );
27- //return $this->user_check_password($raw, $encoded);
28- }
29-
30- private function _password_generate_salt ($ count_log2 ) {
31- $ output = '$S$ ' ;
32- // We encode the final log2 iteration count in base 64.
33- $ itoa64 = $ this ->_password_itoa64 ();
34- $ output .= $ itoa64 [$ count_log2 ];
35- // 6 bytes is the standard salt for a portable phpass hash.
36- $ output .= $ this ->_password_base64_encode ($ this ->drupal_random_bytes (6 ), 6 );
37- return $ output ;
38- }
39-
40- private function _password_itoa64 () {
41- return './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' ;
42- }
43-
44- private function _password_base64_encode ($ input , $ count ) {
45- $ output = '' ;
46- $ i = 0 ;
47- $ itoa64 = $ this ->_password_itoa64 ();
48- do {
49- $ value = ord ($ input [$ i ++]);
50- $ output .= $ itoa64 [$ value & 0x3f ];
51- if ($ i < $ count ) {
52- $ value |= ord ($ input [$ i ]) << 8 ;
53- }
54- $ output .= $ itoa64 [($ value >> 6 ) & 0x3f ];
55- if ($ i ++ >= $ count ) {
56- break ;
57- }
58- if ($ i < $ count ) {
59- $ value |= ord ($ input [$ i ]) << 16 ;
60- }
61- $ output .= $ itoa64 [($ value >> 12 ) & 0x3f ];
62- if ($ i ++ >= $ count ) {
63- break ;
64- }
65- $ output .= $ itoa64 [($ value >> 18 ) & 0x3f ];
66- } while ($ i < $ count );
67-
68- return $ output ;
69- }
70-
71- private function drupal_random_bytes ($ count ) {
72- // $random_state does not use drupal_static as it stores random bytes.
73- static $ random_state , $ bytes , $ has_openssl ;
74-
75- $ missing_bytes = $ count - strlen ($ bytes );
76-
77- if ($ missing_bytes > 0 ) {
78- // PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
79- // locking on Windows and rendered it unusable.
80- if (!isset ($ has_openssl )) {
81- $ has_openssl = version_compare (PHP_VERSION , '5.3.4 ' , '>= ' ) && function_exists ('openssl_random_pseudo_bytes ' );
82- }
83-
84- // openssl_random_pseudo_bytes() will find entropy in a system-dependent
85- // way.
86- if ($ has_openssl ) {
87- $ bytes .= openssl_random_pseudo_bytes ($ missing_bytes );
88- }
89-
90- // Else, read directly from /dev/urandom, which is available on many *nix
91- // systems and is considered cryptographically secure.
92- elseif ($ fh = @fopen ('/dev/urandom ' , 'rb ' )) {
93- // PHP only performs buffered reads, so in reality it will always read
94- // at least 4096 bytes. Thus, it costs nothing extra to read and store
95- // that much so as to speed any additional invocations.
96- $ bytes .= fread ($ fh , max (4096 , $ missing_bytes ));
97- fclose ($ fh );
98- }
99-
100- // If we couldn't get enough entropy, this simple hash-based PRNG will
101- // generate a good set of pseudo-random bytes on any system.
102- // Note that it may be important that our $random_state is passed
103- // through hash() prior to being rolled into $output, that the two hash()
104- // invocations are different, and that the extra input into the first one -
105- // the microtime() - is prepended rather than appended. This is to avoid
106- // directly leaking $random_state via the $output stream, which could
107- // allow for trivial prediction of further "random" numbers.
108- if (strlen ($ bytes ) < $ count ) {
109- // Initialize on the first call. The contents of $_SERVER includes a mix of
110- // user-specific and system information that varies a little with each page.
111- if (!isset ($ random_state )) {
112- $ random_state = print_r ($ _SERVER , TRUE );
113- if (function_exists ('getmypid ' )) {
114- // Further initialize with the somewhat random PHP process ID.
115- $ random_state .= getmypid ();
116- }
117- $ bytes = '' ;
118- }
119-
120- do {
121- $ random_state = hash ('sha256 ' , microtime () . mt_rand () . $ random_state );
122- $ bytes .= hash ('sha256 ' , mt_rand () . $ random_state , TRUE );
123- }
124- while (strlen ($ bytes ) < $ count );
125- }
126- }
127- $ output = substr ($ bytes , 0 , $ count );
128- $ bytes = substr ($ bytes , $ count );
129- return $ output ;
130- }
131-
132- private function _password_get_count_log2 ($ setting ) {
133- $ itoa64 = $ this ->_password_itoa64 ();
134- return strpos ($ itoa64 , $ setting [3 ]);
135- }
136-
137- private function user_check_password ($ password , $ hash ) {
138- if (substr ($ hash , 0 , 2 ) == 'U$ ' ) {
139- // This may be an updated password from user_update_7000(). Such hashes
140- // have 'U' added as the first character and need an extra md5().
141- $ stored_hash = substr ($ hash , 1 );
142- $ password = md5 ($ password );
143- }
144- else {
145- $ stored_hash = $ hash ;
146- }
147-
148- $ type = substr ($ stored_hash , 0 , 3 );
149- switch ($ type ) {
150- case '$S$ ' :
151- // A normal Drupal 7 password using sha512.
152- $ hash = $ this ->_password_crypt ('sha512 ' , $ password , $ stored_hash );
153- break ;
154- case '$H$ ' :
155- // phpBB3 uses "$H$" for the same thing as "$P$".
156- case '$P$ ' :
157- // A phpass password generated using md5. This is an
158- // imported password or from an earlier Drupal version.
159- $ hash = $ this ->_password_crypt ('md5 ' , $ password , $ stored_hash );
160- break ;
161- default :
162- return FALSE ;
163- }
164- return ($ hash && $ stored_hash == $ hash );
165- }
166-
167- private function _password_crypt ($ algo , $ password , $ setting ) {
168- // Prevent DoS attacks by refusing to hash large passwords.
169- if (strlen ($ password ) > 512 ) {
170- return FALSE ;
171- }
172- // The first 12 characters of an existing hash are its setting string.
173- $ setting = substr ($ setting , 0 , 12 );
174-
175- if ($ setting [0 ] != '$ ' || $ setting [2 ] != '$ ' ) {
176- return FALSE ;
177- }
178- $ count_log2 = $ this ->_password_get_count_log2 ($ setting );
179- // Hashes may be imported from elsewhere, so we allow != DRUPAL_HASH_COUNT
180- if ($ count_log2 < 7 || $ count_log2 > 30 ) {
181- return FALSE ;
182- }
183- $ salt = substr ($ setting , 4 , 8 );
184- // Hashes must have an 8 character salt.
185- if (strlen ($ salt ) != 8 ) {
186- return FALSE ;
187- }
188-
189- // Convert the base 2 logarithm into an integer.
190- $ count = 1 << $ count_log2 ;
191-
192- // We rely on the hash() function being available in PHP 5.2+.
193- $ hash = hash ($ algo , $ salt . $ password , TRUE );
194- do {
195- $ hash = hash ($ algo , $ hash . $ password , TRUE );
196- } while (--$ count );
197-
198- $ len = strlen ($ hash );
199- $ output = $ setting . $ this ->_password_base64_encode ($ hash , $ len );
200- // _password_base64_encode() of a 16 byte MD5 will always be 22 characters.
201- // _password_base64_encode() of a 64 byte sha512 will always be 86 characters.
202- $ expected = 12 + ceil ((8 * $ len ) / 6 );
203- return (strlen ($ output ) == $ expected ) ? substr ($ output , 0 , 55 ) : FALSE ;
20447 }
20548}
0 commit comments