Completed
Pull Request — master (#32)
by Michael
07:21
created

OpensslKey::messageChecksum()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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