|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @author Todd Burry <[email protected]> |
|
4
|
|
|
* @copyright 2009-2014 Vanilla Forums Inc. |
|
5
|
|
|
* @license MIT |
|
6
|
|
|
*/ |
|
7
|
|
|
|
|
8
|
|
|
namespace Garden\Password; |
|
9
|
|
|
|
|
10
|
|
|
/** |
|
11
|
|
|
* Implements the password hash from Simple Machines Forums (SMF). |
|
12
|
|
|
* |
|
13
|
|
|
* Note that smf salts passwords with usernames. In order to use a smf password with this class you must concatenate |
|
14
|
|
|
* the username to the end of the password hash in the following way: |
|
15
|
|
|
* |
|
16
|
|
|
* ```php |
|
17
|
|
|
* // Password hash in php. |
|
18
|
|
|
* $passwordHash = $sha1PasswordHash.'$'.$username; |
|
19
|
|
|
* ``` |
|
20
|
|
|
* |
|
21
|
|
|
* ```sql |
|
22
|
|
|
* -- Password hash in mysql. |
|
23
|
|
|
* select concat(memberName, '$', password) as passwordHash |
|
24
|
|
|
* from smf_members |
|
25
|
|
|
* ``` |
|
26
|
|
|
* |
|
27
|
|
|
* The smf password hash is not a good choice for a default password hashing algorithm for several reasons. |
|
28
|
|
|
* |
|
29
|
|
|
* 1. It uses the username as a salt which could change thus invalidating the hash. |
|
30
|
|
|
* 2. The username is not a secure field and is thus a bad choice for a password salt. |
|
31
|
|
|
* 3. It relies on sha1 which is susceptible to a rainbow table attack. |
|
32
|
|
|
*/ |
|
33
|
|
|
class SmfPassword implements IPassword { |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* Hashes a plaintext password. |
|
37
|
|
|
* |
|
38
|
|
|
* Although smf uses the username as salt, this hashing algorithm generates a random salt. |
|
39
|
|
|
* |
|
40
|
|
|
* @param string $password The password to hash. |
|
41
|
|
|
* @return string Returns the hashed password. |
|
42
|
|
|
*/ |
|
43
|
3 |
|
public function hash($password) { |
|
44
|
3 |
|
$salt = base64_encode(openssl_random_pseudo_bytes(12)); |
|
45
|
3 |
|
$hash = sha1(strtolower($salt).$password); |
|
46
|
|
|
|
|
47
|
3 |
|
return $hash.'$'.$salt; |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* Checks if a given password hash needs to be re-hashed to to a stronger algorithm. |
|
52
|
|
|
* |
|
53
|
|
|
* @param string $hash The hash to check. |
|
54
|
|
|
* @return bool Returns `true` |
|
55
|
|
|
*/ |
|
56
|
1 |
|
public function needsRehash($hash) { |
|
57
|
1 |
|
return false; |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
/** |
|
61
|
|
|
* Check to make sure a password matches its stored hash. |
|
62
|
|
|
* |
|
63
|
|
|
* @param string $password The password to verify. |
|
64
|
|
|
* @param string $hash The stored password hash. |
|
65
|
|
|
* @return bool Returns `true` if the password matches the stored hash. |
|
66
|
|
|
*/ |
|
67
|
3 |
|
public function verify($password, $hash) { |
|
68
|
3 |
|
list($storedHash, $username) = $this->splitHash($hash); |
|
69
|
3 |
|
$result = (sha1(strtolower($username).$password) == $storedHash); |
|
70
|
3 |
|
return $result; |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* Split a password hash and salt into its separate components. |
|
75
|
|
|
* |
|
76
|
|
|
* @param string $hash The full password hash. |
|
77
|
|
|
* @return array An array in the form of [$hash, $username]. |
|
78
|
|
|
*/ |
|
79
|
3 |
|
protected function splitHash($hash) { |
|
80
|
3 |
|
if (strpos($hash, '$') === false) { |
|
81
|
1 |
|
return [false, false]; |
|
82
|
|
|
} else { |
|
83
|
2 |
|
return explode('$', $hash, 2); |
|
84
|
|
|
} |
|
85
|
|
|
} |
|
86
|
|
|
} |
|
87
|
|
|
|