Completed
Push — master ( b71d83...fb74f4 )
by Michael
02:27
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
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
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\InvalidKeyEncodingException;
21
use Dcrypt\Exceptions\InvalidKeyLengthException;
22
use Exception;
23
24
/**
25
 * Provides key derivation functions.
26
 *
27
 * @category Dcrypt
28
 *
29
 * @author   Michael Meyer (mmeyer2k) <[email protected]>
30
 * @license  http://opensource.org/licenses/MIT The MIT License (MIT)
31
 *
32
 * @link     https://github.com/mmeyer2k/dcrypt
33
 */
34
final class OpensslKey
35
{
36
    /**
37
     * High entropy key.
38
     *
39
     * @var string
40
     */
41
    private $_key;
42
43
    /**
44
     * Algo string.
45
     *
46
     * @var string
47
     */
48
    private $_algo;
49
50
    /**
51
     * High entropy salt.
52
     *
53
     * @var string
54
     */
55
    private $_iv;
56
57
    /**
58
     * Name of cipher.
59
     *
60
     * @var string
61
     */
62
    private $_cipher;
63
64
    /**
65
     * OpensslKey constructor.
66
     *
67
     * @param string $key    Key to use for encryption
68
     * @param string $algo   Algo to use for HKDF
69
     * @param string $cipher Name of cipher
70
     * @param string $iv     Initialization vector
71
     *
72
     * @throws InvalidKeyLengthException
73
     * @throws InvalidKeyEncodingException
74
     */
75 48
    public function __construct(
76
        string $key,
77
        string $algo,
78
        string $cipher = '',
79
        string $iv = ''
80
    ) {
81
        // Store the key as what was supplied
82 48
        $this->_key = self::decode($key);
83
84
        // If key was not proper base64, bail out
85 39
        if ($this->_key === false) {
86
            throw new InvalidKeyEncodingException();
87
        }
88
89
        // If key was too short, bail out
90 39
        if (Str::strlen($this->_key) < 32) {
91
            throw new InvalidKeyLengthException();
92
        }
93
94
        // Store algo in object
95 39
        $this->_algo = $algo;
96
97
        // Store init vector in object
98 39
        $this->_iv = $iv;
99
100
        // Store the cipher name
101 39
        $this->_cipher = $cipher;
102 39
    }
103
104
    /**
105
     * Decode key and test validity.
106
     * 
107
     * @param string $key Encoded key to unpack
108
     * 
109
     * @throws InvalidKeyLengthException
110
     * @throws InvalidKeyEncodingException
111
     * 
112
     * @return string
113
     */
114 48
    private static function decode(string $key): string
115
    {
116
        // Store the key as what was supplied
117 48
        $key = base64_decode($key, true);
118
119
        // If key was not proper base64, bail out
120 48
        if ($key === false) {
121 9
            throw new InvalidKeyEncodingException();
122
        }
123
124
        // If key was too short, bail out
125 39
        if (Str::strlen($key) < 32) {
126
            throw new InvalidKeyLengthException();
127
        }
128
129 39
        return $key;
130
    }
131
132
    /**
133
     * Generate the authentication key.
134
     *
135
     * @return string
136
     */
137 36
    public function authenticationKey(): string
138
    {
139 36
        return $this->deriveKey(__FUNCTION__ . '|' . $this->_cipher);
140
    }
141
142
    /**
143
     * Generate the encryption key.
144
     *
145
     * @return string
146
     */
147 37
    public function encryptionKey(): string
148
    {
149 37
        return $this->deriveKey(__FUNCTION__ . '|' . $this->_cipher);
150
    }
151
152
    /**
153
     * Derive a key with differing info string parameters.
154
     *
155
     * @param string $info Info parameter to provide to hash_hkdf
156
     *
157
     * @return string
158
     */
159 39
    public function deriveKey(string $info): string
160
    {
161 39
        return hash_hkdf($this->_algo, $this->_key, 0, $info, $this->_iv);
162
    }
163
164
    /**
165
     * Calculates a given message HMAC.
166
     *
167
     * @param string $message
168
     *
169
     * @return string
170
     */
171 36
    public function messageChecksum(string $message): string
172
    {
173 36
        return hash_hmac($this->_algo, $message, $this->authenticationKey(), true);
174
    }
175
176
    /**
177
     * Allows read only access to the internal variables needed by the openssl wrapper.
178
     *
179
     * @return array
180
     */
181 37
    public function wrapperVariables(): array
182
    {
183
        return [
184 37
            $this->_iv,
185 37
            $this->encryptionKey(),
186 36
            $this->_cipher,
187
        ];
188
    }
189
190
    /**
191
     * Generate a new key.
192
     *
193
     * @param int $bytes Size of key in bytes
194
     *
195
     * @throws Exception
196
     * @throws InvalidKeyLengthException
197
     *
198
     * @return string
199
     */
200 31
    public static function create(int $bytes = 32): string
201
    {
202 31
        if ($bytes < 32) {
203 1
            throw new InvalidKeyLengthException();
204
        }
205
206 31
        return base64_encode(random_bytes($bytes));
207
    }
208
}
209