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

SodiumHandler   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 39
c 1
b 0
f 0
dl 0
loc 109
rs 10
wmc 13

3 Methods

Rating   Name   Duplication   Size   Complexity  
A decrypt() 0 37 5
A encrypt() 0 26 3
A parseParams() 0 19 5
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 Sodium
18
 *
19
 * @see https://github.com/jedisct1/libsodium/issues/392
20
 * @credit <a href="http://www.codeigniter.com">CodeIgniter 4.4 - \CodeIgniter\Encryption\Handlers\SodiumHandler</a>
21
 */
22
class SodiumHandler extends BaseHandler
23
{
24
    /**
25
     * Clé de démarrage
26
     */
27
    protected string $key = '';
28
29
    /**
30
     * Taille du bloc pour le message de remplissage.
31
     */
32
    protected int $blockSize = 16;
33
34
    /**
35
     * {@inheritDoc}
36
     */
37
    public function encrypt(string $data, null|array|string $params = null): string
38
    {
39
        $this->parseParams($params);
40
41
        if (empty($this->key)) {
42
            throw EncryptionException::needsStarterKey();
43
        }
44
45
        // créer un occasionnel pour cette opération
46
        $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 24 bytes
47
48
        // ajouter du remplissage avant de chiffrer les données
49
        if ($this->blockSize <= 0) {
50
            throw EncryptionException::encryptionFailed();
51
        }
52
53
        $data = sodium_pad($data, $this->blockSize);
54
55
        // chiffrer le message et combiner avec occasionnel
56
        $ciphertext = $nonce . sodium_crypto_secretbox($data, $nonce, $this->key);
57
58
        // tampons de nettoyage
59
        sodium_memzero($data);
60
        sodium_memzero($this->key);
61
62
        return $ciphertext;
63
    }
64
65
    /**
66
     * {@inheritDoc}
67
     */
68
    public function decrypt(string $data, null|array|string $params = null): string
69
    {
70
        $this->parseParams($params);
71
72
        if (empty($this->key)) {
73
            throw EncryptionException::needsStarterKey();
74
        }
75
76
        if (mb_strlen($data, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
77
            // le message a été tronqué
78
            throw EncryptionException::authenticationFailed();
79
        }
80
81
        // Extraire des informations à partir de données cryptées
82
        $nonce      = self::substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
83
        $ciphertext = self::substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
84
85
        // décrypter les données
86
        $data = sodium_crypto_secretbox_open($ciphertext, $nonce, $this->key);
87
88
        if ($data === false) {
89
            // le message a été falsifié pendant le transit
90
            throw EncryptionException::authenticationFailed(); // @codeCoverageIgnore
91
        }
92
93
        // supprimer le remplissage supplémentaire pendant le cryptage
94
        if ($this->blockSize <= 0) {
95
            throw EncryptionException::authenticationFailed();
96
        }
97
98
        $data = sodium_unpad($data, $this->blockSize);
99
100
        // tampons de nettoyage
101
        sodium_memzero($ciphertext);
102
        sodium_memzero($this->key);
103
104
        return $data;
105
    }
106
107
    /**
108
     * Analysez les $params avant de faire l'affectation.
109
     *
110
     * @throws EncryptionException si la cle est vide
111
     */
112
    protected function parseParams(null|array|string $params): void
113
    {
114
        if ($params === null) {
0 ignored issues
show
introduced by
The condition $params === null is always false.
Loading history...
115
            return;
116
        }
117
118
        if (is_array($params)) {
0 ignored issues
show
introduced by
The condition is_array($params) is always true.
Loading history...
119
            if (isset($params['key'])) {
120
                $this->key = $params['key'];
121
            }
122
123
            if (isset($params['block_size'], $params['blockSize'])) {
124
                $this->blockSize = $params['block_size'] ?? $params['blockSize'];
125
            }
126
127
            return;
128
        }
129
130
        $this->key = (string) $params;
131
    }
132
}
133