Test Failed
Push — main ( 96fa17...2c2b65 )
by Dimitri
03:36
created

OpenSSLHandler::encrypt()   B

Complexity

Conditions 8
Paths 35

Size

Total Lines 31
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 13
c 1
b 0
f 0
nc 35
nop 2
dl 0
loc 31
rs 8.4444
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Security\Encryption\Handlers;
13
14
use BlitzPHP\Exceptions\EncryptionException;
15
16
/**
17
 * Gestionnaire de chiffrement basé sur la librairie OpenSSL
18
 *
19
 * @credit <a href="http://www.codeigniter.com">CodeIgniter 4.4 - \CodeIgniter\Encryption\Handlers\OpenSSLHandler</a>
20
 */
21
class OpenSSLHandler extends BaseHandler
22
{
23
    /**
24
     * HMAC digest à utiliser
25
     */
26
    protected string $digest = 'SHA512';
27
28
    /**
29
     * Liste des algorithmes HMAC pris en charge
30
     *
31
     * @var array [name => digest size]
32
     */
33
    protected array $digestSize = [
34
        'SHA224' => 28,
35
        'SHA256' => 32,
36
        'SHA384' => 48,
37
        'SHA512' => 64,
38
    ];
39
40
    /**
41
     * Chiffrement à utiliser
42
     */
43
    protected string $cipher = 'AES-256-CTR';
44
45
    /**
46
     * Clé de démarrage
47
     */
48
    protected string $key = '';
49
50
    /**
51
     * Indique si le texte chiffré doit être brut. S'il est défini sur false, il sera codé en base64.
52
     */
53
    protected bool $rawData = true;
54
55
    /**
56
     * Informations sur la clé de cryptage.
57
     * Ce paramètre est uniquement utilisé par OpenSSLHandler.
58
     */
59
    public string $encryptKeyInfo = '';
60
61
    /**
62
     * Informations sur la clé d'authentification.
63
     * Ce paramètre est uniquement utilisé par OpenSSLHandler.
64
     */
65
    public string $authKeyInfo = '';
66
67
    /**
68
     * {@inheritDoc}
69
     */
70
    public function encrypt(string $data, null|array|string $params = null): string
71
    {
72
        // Autoriser le remplacement de clé
73
        if ($params) {
74
            $this->key = is_array($params) && isset($params['key']) ? $params['key'] : $params;
75
        }
76
77
        if (empty($this->key)) {
78
            throw EncryptionException::needsStarterKey();
79
        }
80
81
        // derive a secret key
82
        $encryptKey = \hash_hkdf($this->digest, $this->key, 0, $this->encryptKeyInfo);
83
84
        // cryptage de base
85
        $iv = ($ivSize = \openssl_cipher_iv_length($this->cipher)) ? \openssl_random_pseudo_bytes($ivSize) : null;
86
87
        $data = \openssl_encrypt($data, $this->cipher, $encryptKey, OPENSSL_RAW_DATA, $iv);
0 ignored issues
show
Bug introduced by
It seems like $iv can also be of type null; however, parameter $iv of openssl_encrypt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

87
        $data = \openssl_encrypt($data, $this->cipher, $encryptKey, OPENSSL_RAW_DATA, /** @scrutinizer ignore-type */ $iv);
Loading history...
88
89
        if ($data === false) {
90
            throw EncryptionException::encryptionFailed();
91
        }
92
93
        $result = $this->rawData ? $iv . $data : base64_encode($iv . $data);
94
95
        // dériver une clé secrète
96
        $authKey = \hash_hkdf($this->digest, $this->key, 0, $this->authKeyInfo);
97
98
        $hmacKey = \hash_hmac($this->digest, $result, $authKey, $this->rawData);
99
100
        return $hmacKey . $result;
101
    }
102
103
    /**
104
     * {@inheritDoc}
105
     */
106
    public function decrypt(string $data, null|array|string $params = null): string
107
    {
108
        // Autoriser le remplacement de clé
109
        if ($params) {
110
            $this->key = is_array($params) && isset($params['key']) ? $params['key'] : $params;
111
        }
112
113
        if (empty($this->key)) {
114
            throw EncryptionException::needsStarterKey();
115
        }
116
117
        // dériver une clé secrète
118
        $authKey = \hash_hkdf($this->digest, $this->key, 0, $this->authKeyInfo);
119
120
        $hmacLength = $this->rawData
121
            ? $this->digestSize[$this->digest]
122
            : $this->digestSize[$this->digest] * 2;
123
124
        $hmacKey  = self::substr($data, 0, $hmacLength);
125
        $data     = self::substr($data, $hmacLength);
126
        $hmacCalc = \hash_hmac($this->digest, $data, $authKey, $this->rawData);
127
128
        if (! hash_equals($hmacKey, $hmacCalc)) {
129
            throw EncryptionException::authenticationFailed();
130
        }
131
132
        $data = $this->rawData ? $data : base64_decode($data, true);
133
134
        if ($ivSize = \openssl_cipher_iv_length($this->cipher)) {
135
            $iv   = self::substr($data, 0, $ivSize);
136
            $data = self::substr($data, $ivSize);
137
        } else {
138
            $iv = null;
139
        }
140
141
        // dériver une clé secrète
142
        $encryptKey = \hash_hkdf($this->digest, $this->key, 0, $this->encryptKeyInfo);
143
144
        return \openssl_decrypt($data, $this->cipher, $encryptKey, OPENSSL_RAW_DATA, $iv);
0 ignored issues
show
Bug introduced by
It seems like $iv can also be of type null; however, parameter $iv of openssl_decrypt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
        return \openssl_decrypt($data, $this->cipher, $encryptKey, OPENSSL_RAW_DATA, /** @scrutinizer ignore-type */ $iv);
Loading history...
145
    }
146
}
147