• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 20694692790

04 Jan 2026 02:55PM UTC coverage: 85.468% (-0.04%) from 85.504%
20694692790

Pull #9868

github

web-flow
Merge e7365a1b8 into 5f104f6cc
Pull Request #9868: fix: inconsistent `key` handling in encryption

33 of 34 new or added lines in 2 files covered. (97.06%)

10 existing lines in 1 file now uncovered.

21819 of 25529 relevant lines covered (85.47%)

203.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.91
/system/Encryption/Handlers/SodiumHandler.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\Encryption\Handlers;
15

16
use CodeIgniter\Encryption\Exceptions\EncryptionException;
17
use SensitiveParameter;
18

19
/**
20
 * SodiumHandler uses libsodium in encryption.
21
 *
22
 * @see https://github.com/jedisct1/libsodium/issues/392
23
 * @see \CodeIgniter\Encryption\Handlers\SodiumHandlerTest
24
 */
25
class SodiumHandler extends BaseHandler
26
{
27
    /**
28
     * Starter key
29
     *
30
     * @var string|null Null is used for buffer cleanup.
31
     */
32
    protected $key = '';
33

34
    /**
35
     * Block size for padding message.
36
     *
37
     * @var int
38
     */
39
    protected $blockSize = 16;
40

41
    /**
42
     * {@inheritDoc}
43
     */
44
    public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $params = null)
45
    {
46
        // Allow key override
47
        $key = $params !== null
7✔
48
            ? (is_array($params) && isset($params['key']) ? $params['key'] : $params)
2✔
49
            : $this->key;
6✔
50

51
        // Allow blockSize override
52
        $blockSize = (is_array($params) && isset($params['blockSize']))
7✔
NEW
53
            ? $params['blockSize']
×
54
            : $this->blockSize;
7✔
55

56
        if (empty($key)) {
7✔
57
            throw EncryptionException::forNeedsStarterKey();
1✔
58
        }
59

60
        // create a nonce for this operation
61
        $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 24 bytes
6✔
62

63
        // add padding before we encrypt the data
64
        if ($blockSize <= 0) {
6✔
65
            throw EncryptionException::forEncryptionFailed();
1✔
66
        }
67

68
        $data = sodium_pad($data, $blockSize);
5✔
69

70
        // encrypt message and combine with nonce
71
        $ciphertext = $nonce . sodium_crypto_secretbox($data, $nonce, $key);
5✔
72

73
        // cleanup buffers
74
        sodium_memzero($data);
5✔
75
        sodium_memzero($key);
5✔
76

77
        return $ciphertext;
5✔
78
    }
79

80
    /**
81
     * {@inheritDoc}
82
     */
83
    public function decrypt($data, #[SensitiveParameter] $params = null)
84
    {
85
        // Allow key override
86
        $key = $params !== null
5✔
87
            ? (is_array($params) && isset($params['key']) ? $params['key'] : $params)
4✔
88
            : $this->key;
1✔
89

90
        // Allow blockSize override
91
        $blockSize = (is_array($params) && isset($params['blockSize']))
5✔
92
            ? $params['blockSize']
2✔
93
            : $this->blockSize;
3✔
94

95
        if (empty($key)) {
5✔
UNCOV
96
            throw EncryptionException::forNeedsStarterKey();
×
97
        }
98

99
        if (mb_strlen($data, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
5✔
100
            // message was truncated
101
            throw EncryptionException::forAuthenticationFailed();
1✔
102
        }
103

104
        // Extract info from encrypted data
105
        $nonce      = self::substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
4✔
106
        $ciphertext = self::substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
4✔
107

108
        // decrypt data
109
        $data = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
4✔
110

111
        if ($data === false) {
4✔
112
            // message was tampered in transit
113
            throw EncryptionException::forAuthenticationFailed(); // @codeCoverageIgnore
×
114
        }
115

116
        // remove extra padding during encryption
117
        if ($blockSize <= 0) {
4✔
118
            throw EncryptionException::forAuthenticationFailed();
1✔
119
        }
120

121
        $data = sodium_unpad($data, $blockSize);
3✔
122

123
        // cleanup buffers
124
        sodium_memzero($ciphertext);
3✔
125
        sodium_memzero($key);
3✔
126

127
        return $data;
3✔
128
    }
129

130
    /**
131
     * Parse the $params before doing assignment.
132
     *
133
     * @param array|string|null $params
134
     *
135
     * @return void
136
     *
137
     * @throws EncryptionException If key is empty
138
     *
139
     * @deprecated 4.7.0 No longer used.
140
     */
141
    protected function parseParams($params)
142
    {
UNCOV
143
        if ($params === null) {
×
UNCOV
144
            return;
×
145
        }
146

UNCOV
147
        if (is_array($params)) {
×
UNCOV
148
            if (isset($params['key'])) {
×
UNCOV
149
                $this->key = $params['key'];
×
150
            }
151

UNCOV
152
            if (isset($params['blockSize'])) {
×
UNCOV
153
                $this->blockSize = $params['blockSize'];
×
154
            }
155

UNCOV
156
            return;
×
157
        }
158

UNCOV
159
        $this->key = (string) $params;
×
160
    }
161
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc