Completed
Push — master ( cf496c...a42f10 )
by Michael
17:56 queued 16:33
created

OpensslKey::authenticationKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * OpensslKey.php.
7
 *
8
 * PHP version 7
9
 *
10
 * @category Dcrypt
11
 *
12
 * @author   Michael Meyer (mmeyer2k) <[email protected]>
13
 * @license  http://opensource.org/licenses/MIT The MIT License (MIT)
14
 *
15
 * @link     https://github.com/mmeyer2k/dcrypt
16
 */
17
18
namespace Dcrypt;
19
20
use Dcrypt\Exceptions\InvalidKeyException;
21
22
/**
23
 * Provides key derivation functions.
24
 *
25
 * @category Dcrypt
26
 *
27
 * @author   Michael Meyer (mmeyer2k) <[email protected]>
28
 * @license  http://opensource.org/licenses/MIT The MIT License (MIT)
29
 *
30
 * @link     https://github.com/mmeyer2k/dcrypt
31
 */
32
final class OpensslKey
33
{
34
    /**
35
     * High entropy key.
36
     *
37
     * @var string
38
     */
39
    private $_key;
40
41
    /**
42
     * Algo string.
43
     *
44
     * @var string
45
     */
46
    private $_algo;
47
48
    /**
49
     * High entropy salt.
50
     *
51
     * @var string
52
     */
53
    private $_ivr;
54
55
    /**
56
     * OpensslKey constructor.
57
     *
58
     * @param string $algo    Algo to use for HKDF
59
     * @param string $key     Key
60
     * @param string $ivr     Initialization vector
61
     * @param bool   $testKey Validate the key
62
     *
63
     * @throws InvalidKeyException
64
     */
65 44
    public function __construct(
66
        string $algo,
67
        string $key,
68
        string $ivr = '',
69
        bool $testKey = true
70
    ) {
71
        // Store the key as what was supplied
72 44
        $this->_key = \base64_decode($key);
73
74 44
        if ($testKey) {
75
            // Make sure key was properly decoded and meets minimum required length
76 35
            if (Str::strlen($this->_key) < 2048) {
77 7
                throw new InvalidKeyException(InvalidKeyException::KEYLENGTH);
78
            }
79
80
            // Make sure key meets minimum entropy requirement
81 28
            if (self::_testKeyEntropy($this->_key) === false) {
82 1
                throw new InvalidKeyException(InvalidKeyException::KEYRANDOM);
83
            }
84
        }
85
86
        // Store algo in object
87 36
        $this->_algo = $algo;
88
89
        // Store init vector in object
90 36
        $this->_ivr = $ivr;
91 36
    }
92
93
    /**
94
     * Generate the authentication key.
95
     *
96
     * @param string $info The extra info parameter for hash_hkdf
97
     *
98
     * @return string
99
     */
100 33
    public function authenticationKey(string $info): string
101
    {
102 33
        return $this->deriveKey(__FUNCTION__.'|'.$info);
103
    }
104
105
    /**
106
     * Generate the encryption key.
107
     *
108
     * @param string $info The extra info parameter for hash_hkdf
109
     *
110
     * @return string
111
     */
112 34
    public function encryptionKey(string $info): string
113
    {
114 34
        return $this->deriveKey(__FUNCTION__.'|'.$info);
115
    }
116
117
    /**
118
     * Derive a key with differing info string parameters.
119
     *
120
     * @param string $info Info parameter to provide to hash_hkdf
121
     *
122
     * @return string
123
     */
124 36
    public function deriveKey(string $info): string
125
    {
126 36
        return \hash_hkdf($this->_algo, $this->_key, 0, $info, $this->_ivr);
127
    }
128
129
    /**
130
     * Generate a new key that meets requirements for dcrypt.
131
     *
132
     * @param int $bytes Size of key in bytes
133
     *
134
     * @throws InvalidKeyException
135
     *
136
     * @return string
137
     */
138 29
    public static function create(int $bytes = 2048): string
139
    {
140 29
        if ($bytes < 2048) {
141 1
            throw new InvalidKeyException(InvalidKeyException::KEYLENGTH);
142
        }
143
144 29
        return \base64_encode(\random_bytes($bytes));
145
    }
146
147
    /**
148
     * Returns true if key has enough entropy.
149
     *
150
     * @param string $key Key string to test
151
     *
152
     * @return bool
153
     */
154 28
    private static function _testKeyEntropy(string $key): bool
155
    {
156 28
        return \count(\array_unique(\str_split($key))) > 250;
157
    }
158
}
159