PhpbbPassword   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 158
Duplicated Lines 6.96 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 87.1%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 23
c 1
b 0
f 0
lcom 1
cbo 0
dl 11
loc 158
ccs 54
cts 62
cp 0.871
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A verify() 0 7 4
C cryptPrivate() 11 47 8
B encode64() 0 34 6
A hash() 0 10 2
A gensaltPrivate() 0 9 2
A needsRehash() 0 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2005 phpBB Group (Original source code)
5
 * @copyright 2009-2014 Vanilla Forums Inc. (Source code changes)
6
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
7
 *
8
 * This class adapts functions from phpBB 3 (/includes/functions.php). Any source code that was taken from the
9
 * phpBB project is copyright 2005 phpBB Group. Any source code changes are copyright 2009-2014 Vanilla Forums Inc.
10
 *
11
 */
12
13
namespace Garden\Password;
14
15
/**
16
 * Implements phpBB's password hashing algorithm.
17
 */
18
class PhpbbPassword implements IPassword {
19
    const ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
20
21
    /**
22
     * Check for a correct password.
23
     *
24
     * @param string $password The password in plain text.
25
     * @param string $hash The stored password hash.
26
     * @return bool Returns true if the password is correct, false if not.
27
     */
28 3
    public function verify($password, $hash) {
29 3
        if (strlen($hash) == 34) {
30 2
            return ($this->cryptPrivate($password, $hash) === $hash) ? true : false;
31
        }
32
33 1
        return (md5($password) === $hash) ? true : false;
34
    }
35
36
    /**
37
     * The crypt function/replacement.
38
     *
39
     * @param string $password The password to encrypt.
40
     * @param string $setting The hash prefix setting. It should start with $H$.
41
     * @return string The encypted password.
42
     */
43 3
    private function cryptPrivate($password, $setting) {
44 3
        $itoa64 = PhpbbPassword::ITOA64;
45 3
        $output = '*';
46
47
        // Check for correct hash
48 3
        if (substr($setting, 0, 3) != '$H$') {
49
            return $output;
50
        }
51
52 3
        $count_log2 = strpos($itoa64, $setting[3]);
53
54 3
        if ($count_log2 < 7 || $count_log2 > 30) {
55
            return $output;
56
        }
57
58 3
        $count = 1 << $count_log2;
59 3
        $salt = substr($setting, 4, 8);
60
61 3
        if (strlen($salt) != 8) {
62
            return $output;
63
        }
64
65
        /**
66
         * We're kind of forced to use MD5 here since it's the only
67
         * cryptographic primitive available in all versions of PHP
68
         * currently in use.  To implement our own low-level crypto
69
         * in PHP would result in much worse performance and
70
         * consequently in lower iteration counts and hashes that are
71
         * quicker to crack (by non-PHP code).
72
         */
73 3 View Code Duplication
        if (PHP_VERSION >= 5) {
74 3
            $hash = md5($salt.$password, true);
75
            do {
76 3
                $hash = md5($hash.$password, true);
77 3
            } while (--$count);
78 3
        } else {
79
            $hash = pack('H*', md5($salt.$password));
80
            do {
81
                $hash = pack('H*', md5($hash.$password));
82
            } while (--$count);
83
        }
84
85 3
        $output = substr($setting, 0, 12);
86 3
        $output .= $this->encode64($hash, 16);
87
88 3
        return $output;
89
    }
90
91
    /**
92
     * Encode hash.
93
     *
94
     * @param string $input The input to encode.
95
     * @param int $count The number of characters to encode.
96
     * @return string The encoded string.
97
     */
98 3
    protected function encode64($input, $count) {
99 3
        $itoa64 = PhpbbPassword::ITOA64;
100 3
        $output = '';
101 3
        $i = 0;
102
103
        do {
104 3
            $value = ord($input[$i++]);
105 3
            $output .= $itoa64[$value & 0x3f];
106
107 3
            if ($i < $count) {
108 3
                $value |= ord($input[$i]) << 8;
109 3
            }
110
111 3
            $output .= $itoa64[($value >> 6) & 0x3f];
112
113 3
            if ($i++ >= $count) {
114 3
                break;
115
            }
116
117 3
            if ($i < $count) {
118 3
                $value |= ord($input[$i]) << 16;
119 3
            }
120
121 3
            $output .= $itoa64[($value >> 12) & 0x3f];
122
123 3
            if ($i++ >= $count) {
124
                break;
125
            }
126
127 3
            $output .= $itoa64[($value >> 18) & 0x3f];
128 3
        } while ($i < $count);
129
130 3
        return $output;
131
    }
132
133
    /**
134
     * Hashes a plaintext password.
135
     *
136
     * @param string $password The password to hash.
137
     * @return string Returns the hashed password.
138
     */
139 3
    public function hash($password) {
140 3
        $random = openssl_random_pseudo_bytes(6);
141
142 3
        $hash = $this->cryptPrivate($password, $this->gensaltPrivate($random));
143 3
        if (strlen($hash) == 34) {
144 3
            return $hash;
145
        }
146
147
        return null;
148
    }
149
150
    /**
151
     * Generate a password salt based on the given input string.
152
     *
153
     * @param string $input The input string to generate the salt from.
154
     * @return string Returns the password salt prefixed with `$P$`.
155
     */
156 3
    private function gensaltPrivate($input) {
157 3
        $itoa64 = PhpbbPassword::ITOA64;
158
159 3
        $output = '$H$';
160 3
        $output .= $itoa64[min(8 + ((PHP_VERSION >= '5') ? 5 : 3), 30)];
161 3
        $output .= $this->encode64($input, 6);
162
163 3
        return $output;
164
    }
165
166
    /**
167
     * Checks if a given password hash needs to be re-hashed to to a stronger algorithm.
168
     *
169
     * @param string $hash The hash to check.
170
     * @return bool Returns `true`
171
     */
172 1
    public function needsRehash($hash) {
173 1
        return $hash === '*';
174
    }
175
}
176