Passed
Pull Request — main (#8)
by
unknown
15:18
created

SodiumHandler   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Test Coverage

Coverage 96.15%

Importance

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