Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions system/Encryption/EncrypterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ interface EncrypterInterface
/**
* Encrypt - convert plaintext into ciphertext
*
* @param string $data Input data
* @param array|string|null $params Overridden parameters, specifically the key
* @param string $data Input data
* @param array<string, mixed>|string|null $params Overridden parameters, specifically the key
*
* @return string
*
Expand All @@ -38,8 +38,8 @@ public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $para
/**
* Decrypt - convert ciphertext into plaintext
*
* @param string $data Encrypted data
* @param array|string|null $params Overridden parameters, specifically the key
* @param string $data Encrypted data
* @param array<string, mixed>|string|null $params Overridden parameters, specifically the key
*
* @return string
*
Expand Down
14 changes: 10 additions & 4 deletions system/Encryption/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class Encryption
/**
* Map of drivers to handler classes, in preference order
*
* @var array
* @var list<string>
*/
protected $drivers = [
'OpenSSL',
Expand Down Expand Up @@ -138,8 +138,14 @@ public function initialize(?EncryptionConfig $config = null)
$handlerName = 'CodeIgniter\\Encryption\\Handlers\\' . $this->driver . 'Handler';
$this->encrypter = new $handlerName($config);

if (($config->previousKeys ?? []) !== []) {
$this->encrypter = new KeyRotationDecorator($this->encrypter, $config->previousKeys);
// (array) '' is [''], not [], so the unset default must be filtered out here.
$previousKeys = array_values(array_filter(
(array) ($config->previousKeys ?? []),
static fn ($key): bool => $key !== '',
));

if ($previousKeys !== []) {
$this->encrypter = new KeyRotationDecorator($this->encrypter, $previousKeys);
}

return $this->encrypter;
Expand All @@ -162,7 +168,7 @@ public static function createKey($length = 32)
*
* @param string $key Property name
*
* @return array|string|null
* @return list<string>|string|null
*/
public function __get($key)
{
Expand Down
5 changes: 4 additions & 1 deletion system/Encryption/Handlers/OpenSSLHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
/**
* Encryption handling for OpenSSL library
*
* @property-read string $cipher
* @property-read string $key
*
* @see \CodeIgniter\Encryption\Handlers\OpenSSLHandlerTest
*/
class OpenSSLHandler extends BaseHandler
Expand All @@ -33,7 +36,7 @@ class OpenSSLHandler extends BaseHandler
/**
* List of supported HMAC algorithms
*
* @var array [name => digest size]
* @var array<string, int> [name => digest size]
*/
protected array $digestSize = [
'SHA224' => 28,
Expand Down
5 changes: 4 additions & 1 deletion system/Encryption/Handlers/SodiumHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
/**
* SodiumHandler uses libsodium in encryption.
*
* @property-read int $blockSize
* @property-read string|null $key
*
* @see https://github.com/jedisct1/libsodium/issues/392
* @see \CodeIgniter\Encryption\Handlers\SodiumHandlerTest
*/
Expand Down Expand Up @@ -124,7 +127,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null)
/**
* Parse the $params before doing assignment.
*
* @param array|string|null $params
* @param array<string, mixed>|string|null $params
*
* @return void
*
Expand Down
3 changes: 3 additions & 0 deletions system/Encryption/KeyRotationDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
* Wraps any EncrypterInterface implementation to provide automatic
* fallback to previous encryption keys during decryption. This enables
* seamless key rotation without requiring re-encryption of existing data.
*
* @property-read string|null $cipher
* @property-read string|null $key
*/
class KeyRotationDecorator implements EncrypterInterface
{
Expand Down
6 changes: 4 additions & 2 deletions tests/system/Encryption/EncryptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use CodeIgniter\Config\Services as CodeIgniterServices;
use CodeIgniter\Encryption\Exceptions\EncryptionException;
use CodeIgniter\Encryption\Handlers\OpenSSLHandler;
use CodeIgniter\Superglobals;
use CodeIgniter\Test\CIUnitTestCase;
use Config\Encryption as EncryptionConfig;
Expand Down Expand Up @@ -156,6 +157,7 @@ public function testServiceShared(): void

$config->key = 'Abracadabra';
$encrypter = Services::encrypter($config, true);
$this->assertInstanceOf(OpenSSLHandler::class, $encrypter);
$this->assertSame('anything', $encrypter->key);
}

Expand All @@ -166,7 +168,7 @@ public function testMagicIssetTrue(): void

public function testMagicIssetFalse(): void
{
$this->assertFalse(isset($this->encryption->bogus));
$this->assertFalse(isset($this->encryption->bogus)); // @phpstan-ignore property.notFound
}

public function testMagicGet(): void
Expand All @@ -176,7 +178,7 @@ public function testMagicGet(): void

public function testMagicGetMissing(): void
{
$this->assertNull($this->encryption->bogus);
$this->assertNull($this->encryption->bogus); // @phpstan-ignore property.notFound
}

public function testDecryptEncryptedDataByCI3AES128CBC(): void
Expand Down
3 changes: 3 additions & 0 deletions tests/system/Encryption/Handlers/OpenSSLHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function testSanity(): void
$params->key = 'Something other than an empty string';

$encrypter = $this->encryption->initialize($params);
$this->assertInstanceOf(OpenSSLHandler::class, $encrypter);

$this->assertSame('AES-256-CTR', $encrypter->cipher);
$this->assertSame('Something other than an empty string', $encrypter->key);
Expand All @@ -64,6 +65,7 @@ public function testSimple(): void
$params->key = '\xd0\xc9\x08\xc4\xde\x52\x12\x6e\xf8\xcc\xdb\x03\xea\xa0\x3a\x5c';
// Default state (AES-256/Rijndael-256 in CTR mode)
$encrypter = $this->encryption->initialize($params);
$this->assertInstanceOf(OpenSSLHandler::class, $encrypter);

// Was the key properly set?
$this->assertSame($params->key, $encrypter->key);
Expand Down Expand Up @@ -145,6 +147,7 @@ public function testInternalKeyNotModifiedByParams(): void
$params->key = 'original-key-value';

$encrypter = $this->encryption->initialize($params);
$this->assertInstanceOf(OpenSSLHandler::class, $encrypter);

$this->assertSame('original-key-value', $encrypter->key);

Expand Down
4 changes: 3 additions & 1 deletion tests/system/Encryption/Handlers/SodiumHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ public function testPropertiesGetter(): void
$this->config->key = sodium_crypto_secretbox_keygen();
$this->config->blockSize = 256;
$encrypter = $this->encryption->initialize($this->config);
$this->assertInstanceOf(SodiumHandler::class, $encrypter);

$this->assertSame($this->config->key, $encrypter->key);
$this->assertSame($this->config->blockSize, $encrypter->blockSize);
$this->assertNull($encrypter->driver);
$this->assertNull($encrypter->driver); // @phpstan-ignore property.notFound
}

public function testEmptyKeyThrowsErrorOnInitialize(): void
Expand Down Expand Up @@ -136,6 +137,7 @@ public function testInternalKeyNotModifiedByParams(): void

$this->config->key = $originalKey;
$encrypter = $this->encryption->initialize($this->config);
$this->assertInstanceOf(SodiumHandler::class, $encrypter);

$this->assertSame($originalKey, $encrypter->key);

Expand Down
1 change: 1 addition & 0 deletions tests/system/Encryption/KeyRotationDecoratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ public function testPropertyAccessDelegation(): void
$params->previousKeys = ['old-key'];

$encrypter = $this->encryption->initialize($params);
$this->assertInstanceOf(KeyRotationDecorator::class, $encrypter);

$this->assertSame('AES-128-CBC', $encrypter->cipher);
$this->assertSame('test-key-very-long', $encrypter->key);
Expand Down
2 changes: 1 addition & 1 deletion utils/phpstan-baseline/loader.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# total 419 errors
# total 394 errors

includes:
- argument.type.neon
Expand Down
62 changes: 1 addition & 61 deletions utils/phpstan-baseline/missingType.iterableValue.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# total 282 errors
# total 270 errors

parameters:
ignoreErrors:
Expand Down Expand Up @@ -397,66 +397,6 @@ parameters:
count: 1
path: ../../system/Email/Email.php

-
message: '#^Method CodeIgniter\\Encryption\\EncrypterInterface\:\:decrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/EncrypterInterface.php

-
message: '#^Method CodeIgniter\\Encryption\\EncrypterInterface\:\:encrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/EncrypterInterface.php

-
message: '#^Method CodeIgniter\\Encryption\\Encryption\:\:__get\(\) return type has no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Encryption.php

-
message: '#^Property CodeIgniter\\Encryption\\Encryption\:\:\$drivers type has no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Encryption.php

-
message: '#^Method CodeIgniter\\Encryption\\Handlers\\OpenSSLHandler\:\:decrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Handlers/OpenSSLHandler.php

-
message: '#^Method CodeIgniter\\Encryption\\Handlers\\OpenSSLHandler\:\:encrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Handlers/OpenSSLHandler.php

-
message: '#^Property CodeIgniter\\Encryption\\Handlers\\OpenSSLHandler\:\:\$digestSize type has no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Handlers/OpenSSLHandler.php

-
message: '#^Method CodeIgniter\\Encryption\\Handlers\\SodiumHandler\:\:decrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Handlers/SodiumHandler.php

-
message: '#^Method CodeIgniter\\Encryption\\Handlers\\SodiumHandler\:\:encrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Handlers/SodiumHandler.php

-
message: '#^Method CodeIgniter\\Encryption\\Handlers\\SodiumHandler\:\:parseParams\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/Handlers/SodiumHandler.php

-
message: '#^Method CodeIgniter\\Encryption\\KeyRotationDecorator\:\:decrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/KeyRotationDecorator.php

-
message: '#^Method CodeIgniter\\Encryption\\KeyRotationDecorator\:\:encrypt\(\) has parameter \$params with no value type specified in iterable type array\.$#'
count: 1
path: ../../system/Encryption/KeyRotationDecorator.php

-
message: '#^Method CodeIgniter\\Exceptions\\PageNotFoundException\:\:lang\(\) has parameter \$args with no value type specified in iterable type array\.$#'
count: 1
Expand Down
47 changes: 1 addition & 46 deletions utils/phpstan-baseline/property.notFound.neon
Original file line number Diff line number Diff line change
@@ -1,52 +1,7 @@
# total 19 errors
# total 6 errors

parameters:
ignoreErrors:
-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$key\.$#'
count: 1
path: ../../tests/system/Encryption/EncryptionTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\Encryption\:\:\$bogus\.$#'
count: 2
path: ../../tests/system/Encryption/EncryptionTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$cipher\.$#'
count: 1
path: ../../tests/system/Encryption/Handlers/OpenSSLHandlerTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$key\.$#'
count: 3
path: ../../tests/system/Encryption/Handlers/OpenSSLHandlerTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$blockSize\.$#'
count: 1
path: ../../tests/system/Encryption/Handlers/SodiumHandlerTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$driver\.$#'
count: 1
path: ../../tests/system/Encryption/Handlers/SodiumHandlerTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$key\.$#'
count: 2
path: ../../tests/system/Encryption/Handlers/SodiumHandlerTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$cipher\.$#'
count: 1
path: ../../tests/system/Encryption/KeyRotationDecoratorTest.php

-
message: '#^Access to an undefined property CodeIgniter\\Encryption\\EncrypterInterface\:\:\$key\.$#'
count: 1
path: ../../tests/system/Encryption/KeyRotationDecoratorTest.php

-
message: '#^Access to an undefined property CodeIgniter\\I18n\\TimeLegacy\:\:\$foobar\.$#'
count: 1
Expand Down
Loading