Completed
Push — master ( 42efb5...82e58a )
by Michael
03:03 queued 01:14
created

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