GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — 3.0.x ( 30be0d...35d3f6 )
by Nicolas
03:36
created

PBKDF2::hash()   C

Complexity

Conditions 7
Paths 48

Size

Total Lines 41
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 25
nc 48
nop 2
dl 0
loc 41
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package cryptography
4
 */
5
/**
6
 * PBKDF2 is a cryptography class for hashing and comparing messages
7
 * using the PBKDF2-Algorithm with salting.
8
 * This is the most advanced hashing algorithm Symphony provides.
9
 *
10
 * @since Symphony 2.3.1
11
 * @see toolkit.Cryptography
12
 */
13
class PBKDF2 extends Cryptography
14
{
15
    /**
16
     * Salt length
17
     */
18
    const SALT_LENGTH = 20;
19
20
    /**
21
     * Key length
22
     */
23
    const KEY_LENGTH = 40;
24
25
    /**
26
     * Key length
27
     */
28
    const ITERATIONS = 100000;
29
30
    /**
31
     * Algorithm to be used
32
     */
33
    const ALGORITHM = 'sha256';
34
35
    /**
36
     * Prefix to identify the algorithm used
37
     */
38
    const PREFIX = 'PBKDF2v1';
39
40
    /**
41
     * Uses `PBKDF2` and random salt generation to create a hash based on some input.
42
     * Original implementation was under public domain, taken from
43
     * http://www.itnewb.com/tutorial/Encrypting-Passwords-with-PHP-for-Storage-Using-the-RSA-PBKDF2-Standard
44
     *
45
     * @param string $input
46
     * the string to be hashed
47
     * @param string $salt
48
     * an optional salt
49
     * @param integer $iterations
50
     * an optional number of iterations to be used
51
     * @param string $keylength
52
     * an optional length the key will be cropped to fit
53
     * @return string
54
     * the hashed string
55
     */
56
    public static function hash($input, array $options = [])
57
    {
58
        if (empty($options['salt'])) {
59
            $salt = self::generateSalt(self::SALT_LENGTH);
60
        } else {
61
            $salt = $options['salt'];
62
        }
63
64
        if (empty($options['iterations'])) {
65
            $iterations = self::ITERATIONS;
66
        } else {
67
            $iterations = $options['iterations'];
68
        }
69
70
        if (empty($options['keylength'])) {
71
            $keylength = self::KEY_LENGTH;
72
        } else {
73
            $keylength = $options['keylength'];
74
        }
75
76
        if (empty($options['algorithm'])) {
77
            $algorithm = self::ALGORITHM;
78
        } else {
79
            $algorithm = $options['algorithm'];
80
        }
81
82
        $hashlength = strlen(hash($algorithm, null, true));
83
        $blocks = ceil(self::KEY_LENGTH / $hashlength);
84
        $key = '';
85
86
        for ($block = 1; $block <= $blocks; $block++) {
87
            $ib = $b = hash_hmac($algorithm, $salt . pack('N', $block), $input, true);
88
89
            for ($i = 1; $i < $iterations; $i++) {
90
                $ib ^= ($b = hash_hmac($algorithm, $b, $input, true));
91
            }
92
93
            $key .= $ib;
94
        }
95
96
        return self::PREFIX . "|$algorithm|$iterations|$salt|" . base64_encode(substr($key, 0, $keylength));
97
    }
98
99
    /**
100
     * Compares a given hash with a clean text password. Also extracts the salt
101
     * from the hash.
102
     *
103
     * @uses hash_equals()
104
     * @param string $input
105
     *  the clear text password
106
     * @param string $hash
107
     *  the hash the password should be checked against
108
     * @param bool $isHash
109
     *  if the $input is already a hash
110
     * @return boolean
111
     *  the result of the comparison
112
     */
113
    public static function compare($input, $hash, $isHash = false)
114
    {
115
        $salt = self::extractSalt($hash);
116
        $iterations = self::extractIterations($hash);
117
        $keylength = strlen(base64_decode(self::extractHash($hash)));
118
        $algorithm = self::extractAlgorithm($hash);
119
        $options = [
120
            'salt' => $salt,
121
            'iterations' => $iterations,
122
            'keylength' => $keylength,
123
            'algorithm' => $algorithm,
124
        ];
125
        if (!$algorithm) {
126
            $hash = self::PREFIX . "|sha256|$iterations|$salt|" . self::extractHash($hash);
127
        }
128
        return hash_equals(self::hash($input, $options), $hash);
129
    }
130
131
    /**
132
     * Extracts the hash from a hash/salt-combination
133
     *
134
     * @param string $input
135
     * the hashed string
136
     * @return string
137
     * the hash
138
     */
139
    public static function extractHash($input)
140
    {
141
        $data = explode('|', $input, 5);
142
143
        return empty($data[4]) ? $data[3] : $data[4];
144
    }
145
146
    /**
147
     * Extracts the salt from a hash/salt-combination
148
     *
149
     * @param string $input
150
     * the hashed string
151
     * @return string
152
     * the salt
153
     */
154
    public static function extractSalt($input)
155
    {
156
        $data = explode('|', $input, 5);
157
158
        return empty($data[4]) ? $data[2] : $data[3];
159
    }
160
161
    /**
162
     * Extracts the saltlength from a hash/salt-combination
163
     *
164
     * @param string $input
165
     * the hashed string
166
     * @return integer
167
     * the saltlength
168
     */
169
    public static function extractSaltlength($input)
170
    {
171
        return strlen(self::extractSalt($input));
172
    }
173
174
    /**
175
     * Extracts the number of iterations from a hash/salt-combination
176
     *
177
     * @param string $input
178
     * the hashed string
179
     * @return integer
180
     * the number of iterations
181
     */
182
    public static function extractIterations($input)
183
    {
184
        $data = explode('|', $input, 5);
185
186
        return (int) (empty($data[4]) ? $data[1] : $data[2]);
187
    }
188
189
    /**
190
     * Extracts the algorithm from a hash/salt-combination
191
     *
192
     * @param string $input
193
     *  the hashed string
194
     * @return string
195
     *  the algorithm
196
     */
197
    public static function extractAlgorithm($input)
198
    {
199
        $data = explode('|', $input, 5);
200
201
        return empty($data[4]) ? null : $data[1];
202
    }
203
204
    /**
205
     * Checks if provided hash has been computed by most recent algorithm
206
     * returns true if otherwise
207
     *
208
     * @param string $hash
209
     * the hash to be checked
210
     * @return boolean
211
     * whether the hash should be re-computed
212
     */
213
    public static function requiresMigration($hash)
214
    {
215
        $length = self::extractSaltlength($hash);
216
        $iterations = self::extractIterations($hash);
217
        $keylength = strlen(base64_decode(self::extractHash($hash)));
218
        $algorithm = self::extractAlgorithm($hash);
219
220
        return $length !== self::SALT_LENGTH ||
221
            $iterations !== self::ITERATIONS ||
222
            $keylength !== self::KEY_LENGTH ||
223
            $algorithm !== self::ALGORITHM;
224
    }
225
}
226