PBKDF2   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 108
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 11
Bugs 3 Features 1
Metric Value
wmc 14
c 11
b 3
f 1
lcom 1
cbo 0
dl 0
loc 108
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A deriveKey() 0 12 4
A customPBKDF2() 0 20 4
A checkArguments() 0 9 4
A nativePBKDF2() 0 8 2
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2015 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace PBKDF2;
13
14
/**
15
 * Class representing a JSON Web Token Manager.
16
 */
17
final class PBKDF2
18
{
19
    /**
20
     * PBKDF2 key derivation function as defined by RSA's PKCS #5: RFC 2898
21
     * Test vectors can be found in the RFC 6070
22
     * This implementation of PBKDF2 was originally created by defuse.ca
23
     * With improvements by variations-of-shadow.com.
24
     *
25
     * @param string $algorithm          The hash algorithm to use. For supported hash algorithms, see hash_algos().
26
     * @param string $password           The password.
27
     * @param string $salt               A salt that is unique to the password.
28
     * @param int    $count              Iteration count. Higher is better, but slower.
29
     * @param int    $key_length         The length of the derived key in bytes. Default is 0 (means the length is 1-block).
30
     * @param bool   $raw_output         If true, the result is in binary format, else in hex. Default is false.
31
     * @param bool   $native_php_enabled If true and PHP >= 5.5, this function will use the native PHP function, else, this implementation.
32
     *
33
     * @return string A $key_length-byte key derived from the password and salt.
34
     *
35
     * @see https://www.ietf.org/rfc/rfc2898.txt
36
     * @see https://www.ietf.org/rfc/rfc6070.txt
37
     * @see http://php.net/manual/en/function.hash-hmac.php
38
     * @see http://php.net/manual/en/function.hash-pbkdf2.php
39
     */
40
    public static function deriveKey($algorithm, $password, $salt, $count, $key_length = 0, $raw_output = false, $native_php_enabled = true)
41
    {
42
        if (function_exists('hash_pbkdf2') && $native_php_enabled) {
43
            return self::nativePBKDF2($algorithm, $password, $salt, $count, $key_length, $raw_output);
44
        }
45
46
        self::checkArguments($algorithm, $count, $key_length);
47
48
        $raw = self::customPBKDF2($algorithm, $password, $salt, $count, $key_length);
49
50
        return true === $raw_output ? $raw : bin2hex($raw);
51
    }
52
53
    /**
54
     * Pure PHP PBKDF2 key derivation function.
55
     *
56
     * @param string $algorithm  The hash algorithm to use. For supported hash algorithms, see hash_algos().
57
     * @param string $password   The password.
58
     * @param string $salt       A salt that is unique to the password.
59
     * @param int    $count      Iteration count. Higher is better, but slower.
60
     * @param int    $key_length The length of the derived key in bytes.
61
     *
62
     * @return string A $key_length-byte key derived from the password and salt.
63
     */
64
    private static function customPBKDF2($algorithm, $password, $salt, $count, $key_length)
65
    {
66
        $hash_length = strlen(hash($algorithm, '', true));
67
        if (0 === $key_length) {
68
            $key_length = $hash_length;
69
        }
70
        $block_count = ceil($key_length / $hash_length);
71
72
        $output = '';
73
        for ($i = 1; $i <= $block_count; ++$i) {
74
            $last = $salt.pack('N', $i);
75
            $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
76
            for ($j = 1; $j < $count; ++$j) {
77
                $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
78
            }
79
            $output .= $xorsum;
80
        }
81
82
        return substr($output, 0, $key_length);
83
    }
84
85
    /**
86
     * Native PHP PBKDF2 key derivation function.
87
     *
88
     * @param string $algorithm  The hash algorithm to use. For supported hash algorithms, see hash_algos().
89
     * @param string $password   The password.
90
     * @param string $salt       A salt that is unique to the password.
91
     * @param int    $count      Iteration count. Higher is better, but slower.
92
     * @param int    $key_length The length of the derived key in bytes.
93
     * @param bool   $raw_output If true, the result is in binary format, else in hex. Default is false
94
     *
95
     * @return string A $key_length-byte key derived from the password and salt.
96
     */
97
    private static function nativePBKDF2($algorithm, $password, $salt, $count, $key_length, $raw_output)
98
    {
99
        if (!$raw_output) {
100
            $key_length = $key_length * 2;
101
        }
102
103
        return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
104
    }
105
106
    /**
107
     * Native PHP PBKDF2 key derivation function.
108
     *
109
     * @param string $algorithm  The hash algorithm to use. For supported hash algorithms, see hash_algos().
110
     * @param int    $count      Iteration count. Higher is better, but slower.
111
     * @param int    $key_length The length of the derived key in bytes.
112
     *
113
     * @throws \InvalidArgumentException If algorithm is not supported or if count/key_length parameter are not valid.
114
     */
115
    private static function checkArguments($algorithm, $count, $key_length)
116
    {
117
        if (!in_array($algorithm, hash_algos(), true)) {
118
            throw new \InvalidArgumentException('PBKDF2 ERROR: Invalid hash algorithm.');
119
        }
120
        if ($count <= 0 || $key_length < 0) {
121
            throw new \InvalidArgumentException('PBKDF2 ERROR: Invalid key length parameters.');
122
        }
123
    }
124
}
125