Encrypter::generateKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Magister\Services\Encryption;
4
5
use Magister\Services\Contracts\Encryption\DecryptException;
6
use Magister\Services\Contracts\Encryption\Encrypter as EncrypterContract;
7
8
/**
9
 * Class Encrypter.
10
 */
11
class Encrypter implements EncrypterContract
12
{
13
    /**
14
     * The encryption key.
15
     *
16
     * @var string
17
     */
18
    protected $key;
19
20
    /**
21
     * The algorithm used for encryption.
22
     *
23
     * @var string
24
     */
25
    protected $cipher = 'AES-128-CBC';
26
27
    /**
28
     * The mode used for encryption.
29
     *
30
     * @var string
31
     */
32
    protected $mode = 'cbc';
33
34
    /**
35
     * The block size of the cipher.
36
     *
37
     * @var int
38
     */
39
    protected $block = 32;
40
41
    /**
42
     * Create a new encrypter instance.
43
     *
44
     * @param string $key
45
     */
46
    public function __construct($key)
47
    {
48
        $this->key = $key;
49
    }
50
51
    /**
52
     * Encrypt the given value.
53
     *
54
     * @param string $value
55
     *
56
     * @return string
57
     */
58
    public function encrypt($value)
59
    {
60
        $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
61
62
        $value = openssl_encrypt($value, $this->cipher, $this->key, 0, $iv);
63
64
        $mac = $this->hash($iv = base64_encode($iv), $value);
65
66
        return base64_encode(json_encode(compact('iv', 'value', 'mac')));
67
    }
68
69
    /**
70
     * Decrypt the given value.
71
     *
72
     * @param string $payload
73
     *
74
     * @return string
75
     */
76
    public function decrypt($payload)
77
    {
78
        $payload = $this->getJsonPayload($payload);
79
80
        $value = base64_decode($payload['value']);
81
82
        $iv = base64_decode($payload['iv']);
83
84
        $decryptedValue = openssl_decrypt($value, $this->cipher, $this->key, 0, $iv);
85
86
        return unserialize($decryptedValue);
87
    }
88
89
    /**
90
     * Generate a new key.
91
     *
92
     * @return string
93
     */
94
    public function generateKey()
95
    {
96
        return random_bytes(16);
97
    }
98
99
    /**
100
     * Get the JSON array from the given payload.
101
     *
102
     * @param string $payload
103
     *
104
     * @throws \Magister\Services\Contracts\Encryption\DecryptException
105
     *
106
     * @return array
107
     */
108
    protected function getJsonPayload($payload)
109
    {
110
        $payload = json_decode(base64_decode($payload), true);
111
112
        if (!$payload || $this->invalidPayload($payload)) {
113
            throw new DecryptException('Invalid data.');
114
        }
115
116
        if (!$this->validMac($payload)) {
117
            throw new DecryptException('MAC is invalid.');
118
        }
119
120
        return $payload;
121
    }
122
123
    /**
124
     * Determine if the MAC for the given payload is valid.
125
     *
126
     * @param array $payload
127
     *
128
     * @return bool
129
     */
130
    protected function validMac(array $payload)
131
    {
132
        return $payload['mac'] === $this->hash($payload['iv'], $payload['value']);
133
    }
134
135
    /**
136
     * Create a MAC for the given value.
137
     *
138
     * @param string $iv
139
     * @param string $value
140
     *
141
     * @return string
142
     */
143
    protected function hash($iv, $value)
144
    {
145
        return hash_hmac('sha256', $iv.$value, $this->key);
146
    }
147
148
    /**
149
     * Verify that the encryption payload is valid.
150
     *
151
     * @param array|mixed $data
152
     *
153
     * @return bool
154
     */
155
    protected function invalidPayload($data)
156
    {
157
        return !is_array($data) || !isset($data['iv']) || !isset($data['value']) || !isset($data['mac']);
158
    }
159
160
    /**
161
     * Set the encryption key.
162
     *
163
     * @param string $key
164
     *
165
     * @return void
166
     */
167
    public function setKey($key)
168
    {
169
        $this->key = $key;
170
    }
171
172
    /**
173
     * Set the encryption cipher.
174
     *
175
     * @param string $cipher
176
     *
177
     * @return void
178
     */
179
    public function setCipher($cipher)
180
    {
181
        $this->cipher = $cipher;
182
    }
183
184
    /**
185
     * Set the encryption mode.
186
     *
187
     * @param string $mode
188
     *
189
     * @return void
190
     */
191
    public function setMode($mode)
192
    {
193
        $this->mode = $mode;
194
    }
195
}
196