Completed
Push — master ( b3af43...6273ca )
by Todd
19:01
created

XenforoPassword::needsRehash()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 4
CRAP Score 3.072
Metric Value
dl 10
loc 10
ccs 4
cts 5
cp 0.8
rs 9.4286
cc 3
eloc 5
nc 2
nop 1
crap 3.072
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 hashing algorithm of Xenforo.
12
 */
13
class XenforoPassword implements IPassword {
14
15
    /**
16
     * @var string The name of the hashing function to use.
17
     */
18
    protected $hashFunction;
19
20
    /**
21
     * Initialize an instance of this class.
22
     *
23
     * @param string $hashFunction The name of the hash function to use.
24
     * This is an function name that can be passed to {@link hash()}.
25
     * @see hash()
26
     */
27
    public function __construct($hashFunction = '') {
28
        if (!$hashFunction) {
29
            $hashFunction = 'sha256';
30
        }
31
        $this->hashFunction = $hashFunction;
32
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37 3
    public function hash($password) {
38 3
        $salt = base64_encode(openssl_random_pseudo_bytes(12));
39
        $result = [
40 3
            'hashFunc' => $this->hashFunction,
41 3
            'hash' => $this->hashRaw($password, $salt, $this->hashFunction),
42 3
            'salt' => $salt
43
        ];
44
45 3
        return serialize($result);
46
    }
47
48
    /**
49
     * Hashes a password with a given salt.
50
     *
51
     * @param string $password The password to hash.
52
     * @param string $salt The password salt.
53
     * @param string $function The hashing function to use.
54
     * @return string Returns the password hash.
55
     */
56 4
    protected function hashRaw($password, $salt, $function = null) {
57 4
        if (!$function) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $function of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
58 1
            $function = $this->hashFunction;
59
        }
60
61 4
        $calc_hash = hash($function, hash($function, $password).$salt);
62
63 4
        return $calc_hash;
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 1 View Code Duplication
    public function needsRehash($hash) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
70 1
        list($stored_hash, $stored_salt) = $this->splitHash($hash);
71
72
        // Unsalted hashes should be rehashed.
73 1
        if ($stored_hash === false || $stored_salt === false) {
74
            return true;
75
        }
76
77 1
        return false;
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83 3
    public function verify($password, $hash) {
84 3
        list($stored_hash, $function, $stored_salt) = $this->splitHash($hash);
85
86 3
        $calc_hash = $this->hashRaw($password, $stored_salt, $function);
87 3
        $result = $calc_hash === $stored_hash;
88
89 3
        return $result;
90
    }
91
92
    /**
93
     * Split the hash into its calculated hash and salt.
94
     *
95
     * @param string $hash The hash to split.
96
     * @return array An array in the form [$hash, $hashFunc, $salt].
97
     */
98 4
    protected function splitHash($hash) {
99 4
        $parts = @unserialize($hash);
100
101 4
        if (!is_array($parts)) {
102 1
            $result = ['', '', ''];
103
        } else {
104 3
            $parts = array_merge(['hash' => '', 'hashFunc' => '', 'salt' => ''], $parts);
105
106 3
            if (!$parts['hashFunc']) {
107
                switch (strlen($parts['hash'])) {
108
                    case 32:
109
                        $parts['hashFunc'] = 'md5';
110
                        break;
111
                    case 40:
112
                        $parts['hashFunc'] = 'sha1';
113
                        break;
114
                }
115
            }
116
117 3
            $result = [$parts['hash'], $parts['hashFunc'], $parts['salt']];
118
        }
119 4
        return $result;
120
    }
121
}
122