From 7837aa06268e41bf7e01e97e57b111b146f187e7 Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 18:36:54 +0530 Subject: [PATCH 01/13] feat(encryption): Add environment variables in env file for previous keys fallback --- env | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/env b/env index f359ec20bff2..3335ec7747ed 100644 --- a/env +++ b/env @@ -55,6 +55,11 @@ # encryption.key = +# Previous keys fallback is disabled by default. +# If you want to enable it, uncomment the line below. +# encryption.previousKeysFallbackEnabled = true +# encryption.previousKeys = + #-------------------------------------------------------------------- # SESSION #-------------------------------------------------------------------- From be9300015904fc2ce97119c34c20f705751d6ecf Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 18:37:32 +0530 Subject: [PATCH 02/13] feat(encryption): Add previous keys fallback variables in encryption config file. --- app/Config/Encryption.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php index 28344134aa31..da87724d0e06 100644 --- a/app/Config/Encryption.php +++ b/app/Config/Encryption.php @@ -23,6 +23,24 @@ class Encryption extends BaseConfig */ public string $key = ''; + /** + * -------------------------------------------------------------------------- + * Previous Encryption Keys fallback enabled + * -------------------------------------------------------------------------- + * If you want to enable decryption using previous keys, set this to true. + * See the user guide for more info. + */ + public bool $previousKeysFallbackEnabled = false; + + /** + * -------------------------------------------------------------------------- + * Previous Encryption Keys + * -------------------------------------------------------------------------- + * If you want to enable decryption using previous keys, set them here. + * See the user guide for more info. + */ + public array $previousKeys = []; + /** * -------------------------------------------------------------------------- * Encryption Driver to Use From 972ad6efdf94703770f0c645155483f862a5e1bd Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 18:37:58 +0530 Subject: [PATCH 03/13] feat(encryption): Parse the previous keys fallback variables in BaseConfig.php --- system/Config/BaseConfig.php | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index ce6594d45d36..887b38bf8814 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -130,18 +130,33 @@ public function __construct() foreach ($properties as $property) { $this->initEnvValue($this->{$property}, $property, $prefix, $shortPrefix); - if ($this instanceof Encryption && $property === 'key') { - if (str_starts_with($this->{$property}, 'hex2bin:')) { - // Handle hex2bin prefix - $this->{$property} = hex2bin(substr($this->{$property}, 8)); - } elseif (str_starts_with($this->{$property}, 'base64:')) { - // Handle base64 prefix - $this->{$property} = base64_decode(substr($this->{$property}, 7), true); + if ($this instanceof Encryption) { + if ($property === 'key') { + $this->{$property} = $this->parseEncryptionKey($this->{$property}); + } else if ($property === 'previousKeysFallbackEnabled') { + // previousKeysFallbackEnabled must be boolean + $this->{$property} = (bool) $this->{$property}; + } else if ($property === 'previousKeys') { + // previousKeys must be an array + if (is_string($this->{$property})) { + $this->{$property} = array_map(fn($item) => $this->parseEncryptionKey($item), explode(',', $this->{$property})); + } } } } } + protected function parseEncryptionKey(string $key): string + { + if (str_starts_with($key, 'hex2bin:')) { + return hex2bin(substr($key, 8)); + } elseif (str_starts_with($key, 'base64:')) { + return base64_decode(substr($key, 7), true); + } + + return $key; + } + /** * Initialization an environment-specific configuration setting * From 486bf5794cd0503206cf89524c931ffaddc9aacc Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 18:38:25 +0530 Subject: [PATCH 04/13] feat(encryption): Implement the main logic of using previous keys if decryption failed --- system/Encryption/Handlers/OpenSSLHandler.php | 57 ++++++++++++++++++- system/Encryption/Handlers/SodiumHandler.php | 44 +++++++++++++- 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index 9dca5b90304c..7df0b0327c3e 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -14,7 +14,6 @@ namespace CodeIgniter\Encryption\Handlers; use CodeIgniter\Encryption\Exceptions\EncryptionException; -use SensitiveParameter; /** * Encryption handling for OpenSSL library @@ -56,6 +55,20 @@ class OpenSSLHandler extends BaseHandler */ protected $key = ''; + /** + * Whether to fall back to previous keys when decryption fails. + * + * @var bool + */ + protected bool $previousKeysFallbackEnabled = false; + + /** + * List of previous keys for fallback decryption. + * + * @var string[] + */ + protected array $previousKeys = []; + /** * Whether the cipher-text should be raw. If set to false, then it will be base64 encoded. */ @@ -127,8 +140,46 @@ public function decrypt($data, #[SensitiveParameter] $params = null) throw EncryptionException::forNeedsStarterKey(); } + try { + $result = $this->decryptWithKey($data, $this->key); + } catch (EncryptionException $e) { + $result = false; + $exception = $e; + } + + if ($result === false && $this->previousKeysFallbackEnabled && ! empty($this->previousKeys)) { + foreach ($this->previousKeys as $previousKey) { + try { + $result = $this->decryptWithKey($data, $previousKey); + if ($result !== false) { + return $result; + } + } catch (EncryptionException) { + // Try next key + } + } + } + + if (isset($exception)) { + throw $exception; + } + + return $result; + } + + /** + * Decrypt the data with the provided key + * + * @param string $data + * @param string $key + * + * @return false|string + * @throws EncryptionException + */ + protected function decryptWithKey($data, #[SensitiveParameter] $key) + { // derive a secret key - $authKey = \hash_hkdf($this->digest, $this->key, 0, $this->authKeyInfo); + $authKey = \hash_hkdf($this->digest, $key, 0, $this->authKeyInfo); $hmacLength = $this->rawData ? $this->digestSize[$this->digest] @@ -152,7 +203,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) } // derive a secret key - $encryptKey = \hash_hkdf($this->digest, $this->key, 0, $this->encryptKeyInfo); + $encryptKey = \hash_hkdf($this->digest, $key, 0, $this->encryptKeyInfo); return \openssl_decrypt($data, $this->cipher, $encryptKey, OPENSSL_RAW_DATA, $iv); } diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index 45f9ac2fa383..af9a63de2699 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -14,7 +14,6 @@ namespace CodeIgniter\Encryption\Handlers; use CodeIgniter\Encryption\Exceptions\EncryptionException; -use SensitiveParameter; /** * SodiumHandler uses libsodium in encryption. @@ -80,6 +79,46 @@ public function decrypt($data, #[SensitiveParameter] $params = null) throw EncryptionException::forNeedsStarterKey(); } + try { + $result = $this->decryptWithKey($data, $this->key); + sodium_memzero($this->key); + } catch (EncryptionException $e) { + $result = false; + $exception = $e; + sodium_memzero($this->key); + } + + if ($result === false && $this->previousKeysFallbackEnabled && ! empty($this->previousKeys)) { + foreach ($this->previousKeys as $previousKey) { + try { + $result = $this->decryptWithKey($data, $previousKey); + if (isset($result)) { + return $result; + } + } catch (EncryptionException) { + // Try next key + } + } + } + + if (isset($exception)) { + throw $exception; + } + + return $result; + } + + /** + * Decrypt the data with the provided key + * + * @param string $data + * @param string $key + * + * @return string + * @throws EncryptionException + */ + protected function decryptWithKey($data, #[SensitiveParameter] $key) + { if (mb_strlen($data, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) { // message was truncated throw EncryptionException::forAuthenticationFailed(); @@ -90,7 +129,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) $ciphertext = self::substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // decrypt data - $data = sodium_crypto_secretbox_open($ciphertext, $nonce, $this->key); + $data = sodium_crypto_secretbox_open($ciphertext, $nonce, $key); if ($data === false) { // message was tampered in transit @@ -106,7 +145,6 @@ public function decrypt($data, #[SensitiveParameter] $params = null) // cleanup buffers sodium_memzero($ciphertext); - sodium_memzero($this->key); return $data; } From 5f45c6f1ad7bf4a4b4a9c750671d19bd43893cad Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 18:59:23 +0530 Subject: [PATCH 05/13] feat(encryption): Add the key names in SodiumHandler.php --- system/Encryption/Handlers/SodiumHandler.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index af9a63de2699..d2538f838975 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -30,6 +30,18 @@ class SodiumHandler extends BaseHandler */ protected $key = ''; + /** + * Whether to fall back to previous keys when decryption fails. + */ + protected bool $previousKeysFallbackEnabled = false; + + /** + * List of previous keys for fallback decryption. + * + * @var list + */ + protected array $previousKeys = []; + /** * Block size for padding message. * @@ -115,6 +127,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) * @param string $key * * @return string + * * @throws EncryptionException */ protected function decryptWithKey($data, #[SensitiveParameter] $key) From 55ed3a76a3d7b4a70a56ec54ee421bec1902c6b2 Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 18:59:50 +0530 Subject: [PATCH 06/13] feat(encryption): Add previous key initialization in Encryption.php --- system/Encryption/Encryption.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index c233f1fdfe03..b793efa85e98 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -53,6 +53,20 @@ class Encryption */ protected $key; + /** + * Whether to fall back to previous keys when decryption fails. + * + * @var bool + */ + protected bool $previousKeysFallbackEnabled = false; + + /** + * List of previous keys for fallback decryption. + * + * @var string[] + */ + protected array $previousKeys = []; + /** * The derived HMAC key * @@ -92,6 +106,8 @@ public function __construct(?EncryptionConfig $config = null) $config ??= new EncryptionConfig(); $this->key = $config->key; + $this->previousKeysFallbackEnabled = $config->previousKeysFallbackEnabled; + $this->previousKeys = $config->previousKeys; $this->driver = $config->driver; $this->digest = $config->digest ?? 'SHA512'; @@ -117,6 +133,8 @@ public function initialize(?EncryptionConfig $config = null) { if ($config instanceof EncryptionConfig) { $this->key = $config->key; + $this->previousKeysFallbackEnabled = $config->previousKeysFallbackEnabled ?? false; + $this->previousKeys = $config->previousKeys ?? []; $this->driver = $config->driver; $this->digest = $config->digest ?? 'SHA512'; } From 5e53f06d55af71d07ef612c42f24def8026252ca Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 19:01:26 +0530 Subject: [PATCH 07/13] refactor: cs fix --- system/Config/BaseConfig.php | 9 +++++---- system/Encryption/Encryption.php | 20 +++++++++---------- system/Encryption/Handlers/OpenSSLHandler.php | 5 ++--- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 887b38bf8814..1515ab1d5097 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -133,13 +133,13 @@ public function __construct() if ($this instanceof Encryption) { if ($property === 'key') { $this->{$property} = $this->parseEncryptionKey($this->{$property}); - } else if ($property === 'previousKeysFallbackEnabled') { + } elseif ($property === 'previousKeysFallbackEnabled') { // previousKeysFallbackEnabled must be boolean $this->{$property} = (bool) $this->{$property}; - } else if ($property === 'previousKeys') { + } elseif ($property === 'previousKeys') { // previousKeys must be an array if (is_string($this->{$property})) { - $this->{$property} = array_map(fn($item) => $this->parseEncryptionKey($item), explode(',', $this->{$property})); + $this->{$property} = array_map(fn ($item) => $this->parseEncryptionKey($item), explode(',', $this->{$property})); } } } @@ -150,7 +150,8 @@ protected function parseEncryptionKey(string $key): string { if (str_starts_with($key, 'hex2bin:')) { return hex2bin(substr($key, 8)); - } elseif (str_starts_with($key, 'base64:')) { + } + if (str_starts_with($key, 'base64:')) { return base64_decode(substr($key, 7), true); } diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index b793efa85e98..8f34799b9dd4 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -55,15 +55,13 @@ class Encryption /** * Whether to fall back to previous keys when decryption fails. - * - * @var bool */ protected bool $previousKeysFallbackEnabled = false; /** * List of previous keys for fallback decryption. * - * @var string[] + * @var list */ protected array $previousKeys = []; @@ -105,11 +103,11 @@ public function __construct(?EncryptionConfig $config = null) { $config ??= new EncryptionConfig(); - $this->key = $config->key; + $this->key = $config->key; $this->previousKeysFallbackEnabled = $config->previousKeysFallbackEnabled; - $this->previousKeys = $config->previousKeys; - $this->driver = $config->driver; - $this->digest = $config->digest ?? 'SHA512'; + $this->previousKeys = $config->previousKeys; + $this->driver = $config->driver; + $this->digest = $config->digest ?? 'SHA512'; $this->handlers = [ 'OpenSSL' => extension_loaded('openssl'), @@ -132,11 +130,11 @@ public function __construct(?EncryptionConfig $config = null) public function initialize(?EncryptionConfig $config = null) { if ($config instanceof EncryptionConfig) { - $this->key = $config->key; + $this->key = $config->key; $this->previousKeysFallbackEnabled = $config->previousKeysFallbackEnabled ?? false; - $this->previousKeys = $config->previousKeys ?? []; - $this->driver = $config->driver; - $this->digest = $config->digest ?? 'SHA512'; + $this->previousKeys = $config->previousKeys ?? []; + $this->driver = $config->driver; + $this->digest = $config->digest ?? 'SHA512'; } if (empty($this->driver)) { diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index 7df0b0327c3e..481461246fc0 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -57,15 +57,13 @@ class OpenSSLHandler extends BaseHandler /** * Whether to fall back to previous keys when decryption fails. - * - * @var bool */ protected bool $previousKeysFallbackEnabled = false; /** * List of previous keys for fallback decryption. * - * @var string[] + * @var list */ protected array $previousKeys = []; @@ -174,6 +172,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) * @param string $key * * @return false|string + * * @throws EncryptionException */ protected function decryptWithKey($data, #[SensitiveParameter] $key) From 68e05ba3b6a85c53082a27271db77d6532c129fc Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 19:08:53 +0530 Subject: [PATCH 08/13] refactor: fix static analysis problems --- system/Config/BaseConfig.php | 2 +- system/Encryption/Handlers/OpenSSLHandler.php | 8 ++++---- system/Encryption/Handlers/SodiumHandler.php | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 1515ab1d5097..468ea72889fe 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -139,7 +139,7 @@ public function __construct() } elseif ($property === 'previousKeys') { // previousKeys must be an array if (is_string($this->{$property})) { - $this->{$property} = array_map(fn ($item) => $this->parseEncryptionKey($item), explode(',', $this->{$property})); + $this->{$property} = array_map(fn ($item): string => $this->parseEncryptionKey($item), explode(',', $this->{$property})); } } } diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index 481461246fc0..c252b3f835e4 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -91,7 +91,7 @@ class OpenSSLHandler extends BaseHandler /** * {@inheritDoc} */ - public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $params = null) + public function encrypt($data, $params = null) { // Allow key override if ($params !== null) { @@ -127,7 +127,7 @@ public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $para /** * {@inheritDoc} */ - public function decrypt($data, #[SensitiveParameter] $params = null) + public function decrypt($data, $params = null) { // Allow key override if ($params !== null) { @@ -145,7 +145,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) $exception = $e; } - if ($result === false && $this->previousKeysFallbackEnabled && ! empty($this->previousKeys)) { + if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== []) { foreach ($this->previousKeys as $previousKey) { try { $result = $this->decryptWithKey($data, $previousKey); @@ -175,7 +175,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) * * @throws EncryptionException */ - protected function decryptWithKey($data, #[SensitiveParameter] $key) + protected function decryptWithKey($data, $key) { // derive a secret key $authKey = \hash_hkdf($this->digest, $key, 0, $this->authKeyInfo); diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index d2538f838975..af3cb0062d85 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -52,7 +52,7 @@ class SodiumHandler extends BaseHandler /** * {@inheritDoc} */ - public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $params = null) + public function encrypt($data, $params = null) { $this->parseParams($params); @@ -83,7 +83,7 @@ public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $para /** * {@inheritDoc} */ - public function decrypt($data, #[SensitiveParameter] $params = null) + public function decrypt($data, $params = null) { $this->parseParams($params); @@ -100,7 +100,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) sodium_memzero($this->key); } - if ($result === false && $this->previousKeysFallbackEnabled && ! empty($this->previousKeys)) { + if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== []) { foreach ($this->previousKeys as $previousKey) { try { $result = $this->decryptWithKey($data, $previousKey); @@ -130,7 +130,7 @@ public function decrypt($data, #[SensitiveParameter] $params = null) * * @throws EncryptionException */ - protected function decryptWithKey($data, #[SensitiveParameter] $key) + protected function decryptWithKey($data, $key) { if (mb_strlen($data, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) { // message was truncated From 772bc29f7f90fa3fbef32c7a7215d5252dbd9092 Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 19:38:14 +0530 Subject: [PATCH 09/13] feat(encryption): Change previousKeys to a comma-separated string for fallback decryption --- app/Config/Encryption.php | 2 +- system/Config/BaseConfig.php | 8 +++++--- system/Encryption/Encryption.php | 8 ++++---- system/Encryption/Handlers/OpenSSLHandler.php | 11 ++++++----- system/Encryption/Handlers/SodiumHandler.php | 11 ++++++----- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php index da87724d0e06..4335d0bbe65b 100644 --- a/app/Config/Encryption.php +++ b/app/Config/Encryption.php @@ -39,7 +39,7 @@ class Encryption extends BaseConfig * If you want to enable decryption using previous keys, set them here. * See the user guide for more info. */ - public array $previousKeys = []; + public string $previousKeys = ''; /** * -------------------------------------------------------------------------- diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 468ea72889fe..641c916ca6fa 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -137,10 +137,12 @@ public function __construct() // previousKeysFallbackEnabled must be boolean $this->{$property} = (bool) $this->{$property}; } elseif ($property === 'previousKeys') { - // previousKeys must be an array - if (is_string($this->{$property})) { - $this->{$property} = array_map(fn ($item): string => $this->parseEncryptionKey($item), explode(',', $this->{$property})); + $keysArray = array_map('trim', explode(',', $this->{$property})); + $parsedKeys = []; + foreach ($keysArray as $key) { + $parsedKeys[] = $this->parseEncryptionKey($key); } + $this->{$property} = implode(',', $parsedKeys); } } } diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index 8f34799b9dd4..b0eb59a28e90 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -59,11 +59,11 @@ class Encryption protected bool $previousKeysFallbackEnabled = false; /** - * List of previous keys for fallback decryption. + * Comma-separated list of previous keys for fallback decryption. * - * @var list + * @var string */ - protected array $previousKeys = []; + protected string $previousKeys = ''; /** * The derived HMAC key @@ -132,7 +132,7 @@ public function initialize(?EncryptionConfig $config = null) if ($config instanceof EncryptionConfig) { $this->key = $config->key; $this->previousKeysFallbackEnabled = $config->previousKeysFallbackEnabled ?? false; - $this->previousKeys = $config->previousKeys ?? []; + $this->previousKeys = $config->previousKeys ?? ''; $this->driver = $config->driver; $this->digest = $config->digest ?? 'SHA512'; } diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index c252b3f835e4..4c17f69314f5 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -63,9 +63,9 @@ class OpenSSLHandler extends BaseHandler /** * List of previous keys for fallback decryption. * - * @var list + * @var string */ - protected array $previousKeys = []; + protected string $previousKeys = ''; /** * Whether the cipher-text should be raw. If set to false, then it will be base64 encoded. @@ -138,15 +138,16 @@ public function decrypt($data, $params = null) throw EncryptionException::forNeedsStarterKey(); } + $result = false; + try { $result = $this->decryptWithKey($data, $this->key); } catch (EncryptionException $e) { - $result = false; $exception = $e; } - if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== []) { - foreach ($this->previousKeys as $previousKey) { + if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== '') { + foreach (explode(',', $this->previousKeys) as $previousKey) { try { $result = $this->decryptWithKey($data, $previousKey); if ($result !== false) { diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index af3cb0062d85..f481dea83d5b 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -38,9 +38,9 @@ class SodiumHandler extends BaseHandler /** * List of previous keys for fallback decryption. * - * @var list + * @var string */ - protected array $previousKeys = []; + protected string $previousKeys = ''; /** * Block size for padding message. @@ -91,17 +91,18 @@ public function decrypt($data, $params = null) throw EncryptionException::forNeedsStarterKey(); } + $result = false; + try { $result = $this->decryptWithKey($data, $this->key); sodium_memzero($this->key); } catch (EncryptionException $e) { - $result = false; $exception = $e; sodium_memzero($this->key); } - if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== []) { - foreach ($this->previousKeys as $previousKey) { + if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== '') { + foreach (explode(',', $this->previousKeys) as $previousKey) { try { $result = $this->decryptWithKey($data, $previousKey); if (isset($result)) { From 2ad2e97f546d25a47cd9d731b81d59d5cb51ed94 Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 19:40:13 +0530 Subject: [PATCH 10/13] feat(encryption): Remove previousKeysFallbackEnabled property and related logic --- app/Config/Encryption.php | 9 --------- env | 4 +--- system/Config/BaseConfig.php | 3 --- system/Encryption/Encryption.php | 7 ------- system/Encryption/Handlers/OpenSSLHandler.php | 7 +------ system/Encryption/Handlers/SodiumHandler.php | 7 +------ 6 files changed, 3 insertions(+), 34 deletions(-) diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php index 4335d0bbe65b..4914c29b4a6b 100644 --- a/app/Config/Encryption.php +++ b/app/Config/Encryption.php @@ -23,15 +23,6 @@ class Encryption extends BaseConfig */ public string $key = ''; - /** - * -------------------------------------------------------------------------- - * Previous Encryption Keys fallback enabled - * -------------------------------------------------------------------------- - * If you want to enable decryption using previous keys, set this to true. - * See the user guide for more info. - */ - public bool $previousKeysFallbackEnabled = false; - /** * -------------------------------------------------------------------------- * Previous Encryption Keys diff --git a/env b/env index 3335ec7747ed..ce4f5586bd69 100644 --- a/env +++ b/env @@ -55,9 +55,7 @@ # encryption.key = -# Previous keys fallback is disabled by default. -# If you want to enable it, uncomment the line below. -# encryption.previousKeysFallbackEnabled = true +# Previous keys fallback; comma-separated list # encryption.previousKeys = #-------------------------------------------------------------------- diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 641c916ca6fa..3d4fc0606a1c 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -133,9 +133,6 @@ public function __construct() if ($this instanceof Encryption) { if ($property === 'key') { $this->{$property} = $this->parseEncryptionKey($this->{$property}); - } elseif ($property === 'previousKeysFallbackEnabled') { - // previousKeysFallbackEnabled must be boolean - $this->{$property} = (bool) $this->{$property}; } elseif ($property === 'previousKeys') { $keysArray = array_map('trim', explode(',', $this->{$property})); $parsedKeys = []; diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index b0eb59a28e90..3992a3cc43e6 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -53,11 +53,6 @@ class Encryption */ protected $key; - /** - * Whether to fall back to previous keys when decryption fails. - */ - protected bool $previousKeysFallbackEnabled = false; - /** * Comma-separated list of previous keys for fallback decryption. * @@ -104,7 +99,6 @@ public function __construct(?EncryptionConfig $config = null) $config ??= new EncryptionConfig(); $this->key = $config->key; - $this->previousKeysFallbackEnabled = $config->previousKeysFallbackEnabled; $this->previousKeys = $config->previousKeys; $this->driver = $config->driver; $this->digest = $config->digest ?? 'SHA512'; @@ -131,7 +125,6 @@ public function initialize(?EncryptionConfig $config = null) { if ($config instanceof EncryptionConfig) { $this->key = $config->key; - $this->previousKeysFallbackEnabled = $config->previousKeysFallbackEnabled ?? false; $this->previousKeys = $config->previousKeys ?? ''; $this->driver = $config->driver; $this->digest = $config->digest ?? 'SHA512'; diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index 4c17f69314f5..662564dcc077 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -55,11 +55,6 @@ class OpenSSLHandler extends BaseHandler */ protected $key = ''; - /** - * Whether to fall back to previous keys when decryption fails. - */ - protected bool $previousKeysFallbackEnabled = false; - /** * List of previous keys for fallback decryption. * @@ -146,7 +141,7 @@ public function decrypt($data, $params = null) $exception = $e; } - if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== '') { + if ($result === false && $this->previousKeys !== '') { foreach (explode(',', $this->previousKeys) as $previousKey) { try { $result = $this->decryptWithKey($data, $previousKey); diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index f481dea83d5b..9a9464dc1ebb 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -30,11 +30,6 @@ class SodiumHandler extends BaseHandler */ protected $key = ''; - /** - * Whether to fall back to previous keys when decryption fails. - */ - protected bool $previousKeysFallbackEnabled = false; - /** * List of previous keys for fallback decryption. * @@ -101,7 +96,7 @@ public function decrypt($data, $params = null) sodium_memzero($this->key); } - if ($result === false && $this->previousKeysFallbackEnabled && $this->previousKeys !== '') { + if ($result === false && $this->previousKeys !== '') { foreach (explode(',', $this->previousKeys) as $previousKey) { try { $result = $this->decryptWithKey($data, $previousKey); From c3f5bae637a45108ecee915eabf639117748afaf Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 19:46:01 +0530 Subject: [PATCH 11/13] refactor: cs fix --- system/Config/BaseConfig.php | 5 +++-- system/Encryption/Encryption.php | 18 ++++++++---------- system/Encryption/Handlers/OpenSSLHandler.php | 2 -- system/Encryption/Handlers/SodiumHandler.php | 2 -- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 3d4fc0606a1c..9d76e49c9ec2 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -134,8 +134,9 @@ public function __construct() if ($property === 'key') { $this->{$property} = $this->parseEncryptionKey($this->{$property}); } elseif ($property === 'previousKeys') { - $keysArray = array_map('trim', explode(',', $this->{$property})); - $parsedKeys = []; + $keysArray = array_map('trim', explode(',', $this->{$property})); + $parsedKeys = []; + foreach ($keysArray as $key) { $parsedKeys[] = $this->parseEncryptionKey($key); } diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index 3992a3cc43e6..eb4c37e5610d 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -55,8 +55,6 @@ class Encryption /** * Comma-separated list of previous keys for fallback decryption. - * - * @var string */ protected string $previousKeys = ''; @@ -98,10 +96,10 @@ public function __construct(?EncryptionConfig $config = null) { $config ??= new EncryptionConfig(); - $this->key = $config->key; - $this->previousKeys = $config->previousKeys; - $this->driver = $config->driver; - $this->digest = $config->digest ?? 'SHA512'; + $this->key = $config->key; + $this->previousKeys = $config->previousKeys; + $this->driver = $config->driver; + $this->digest = $config->digest ?? 'SHA512'; $this->handlers = [ 'OpenSSL' => extension_loaded('openssl'), @@ -124,10 +122,10 @@ public function __construct(?EncryptionConfig $config = null) public function initialize(?EncryptionConfig $config = null) { if ($config instanceof EncryptionConfig) { - $this->key = $config->key; - $this->previousKeys = $config->previousKeys ?? ''; - $this->driver = $config->driver; - $this->digest = $config->digest ?? 'SHA512'; + $this->key = $config->key; + $this->previousKeys = $config->previousKeys ?? ''; + $this->driver = $config->driver; + $this->digest = $config->digest ?? 'SHA512'; } if (empty($this->driver)) { diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index 662564dcc077..069a51d7d09e 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -57,8 +57,6 @@ class OpenSSLHandler extends BaseHandler /** * List of previous keys for fallback decryption. - * - * @var string */ protected string $previousKeys = ''; diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index 9a9464dc1ebb..b23757aa6d7b 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -32,8 +32,6 @@ class SodiumHandler extends BaseHandler /** * List of previous keys for fallback decryption. - * - * @var string */ protected string $previousKeys = ''; From 97e32f40afe3d5e484acca82158f7429e88750af Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Sun, 21 Dec 2025 19:47:36 +0530 Subject: [PATCH 12/13] refactor: fix FunctionFirstClassCallableRector --- system/Config/BaseConfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 9d76e49c9ec2..252f4a108e12 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -134,7 +134,7 @@ public function __construct() if ($property === 'key') { $this->{$property} = $this->parseEncryptionKey($this->{$property}); } elseif ($property === 'previousKeys') { - $keysArray = array_map('trim', explode(',', $this->{$property})); + $keysArray = array_map(trim(...), explode(',', $this->{$property})); $parsedKeys = []; foreach ($keysArray as $key) { From 6a8694fedbeb849f15d4610cc5a1df66bc8cb3fd Mon Sep 17 00:00:00 2001 From: patel-vansh Date: Tue, 23 Dec 2025 14:08:33 +0530 Subject: [PATCH 13/13] refactor: add #[SensitiveParameter] whenever necessary --- system/Encryption/Handlers/OpenSSLHandler.php | 7 ++++--- system/Encryption/Handlers/SodiumHandler.php | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index 069a51d7d09e..82f9695de5fe 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -14,6 +14,7 @@ namespace CodeIgniter\Encryption\Handlers; use CodeIgniter\Encryption\Exceptions\EncryptionException; +use SensitiveParameter; /** * Encryption handling for OpenSSL library @@ -84,7 +85,7 @@ class OpenSSLHandler extends BaseHandler /** * {@inheritDoc} */ - public function encrypt($data, $params = null) + public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $params = null) { // Allow key override if ($params !== null) { @@ -120,7 +121,7 @@ public function encrypt($data, $params = null) /** * {@inheritDoc} */ - public function decrypt($data, $params = null) + public function decrypt($data, #[SensitiveParameter] $params = null) { // Allow key override if ($params !== null) { @@ -169,7 +170,7 @@ public function decrypt($data, $params = null) * * @throws EncryptionException */ - protected function decryptWithKey($data, $key) + protected function decryptWithKey($data, #[SensitiveParameter] $key) { // derive a secret key $authKey = \hash_hkdf($this->digest, $key, 0, $this->authKeyInfo); diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index b23757aa6d7b..69d1aa3e3afc 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -14,6 +14,7 @@ namespace CodeIgniter\Encryption\Handlers; use CodeIgniter\Encryption\Exceptions\EncryptionException; +use SensitiveParameter; /** * SodiumHandler uses libsodium in encryption. @@ -45,7 +46,7 @@ class SodiumHandler extends BaseHandler /** * {@inheritDoc} */ - public function encrypt($data, $params = null) + public function encrypt(#[SensitiveParameter] $data, #[SensitiveParameter] $params = null) { $this->parseParams($params); @@ -76,7 +77,7 @@ public function encrypt($data, $params = null) /** * {@inheritDoc} */ - public function decrypt($data, $params = null) + public function decrypt($data, #[SensitiveParameter] $params = null) { $this->parseParams($params); @@ -124,7 +125,7 @@ public function decrypt($data, $params = null) * * @throws EncryptionException */ - protected function decryptWithKey($data, $key) + protected function decryptWithKey($data, #[SensitiveParameter] $key) { if (mb_strlen($data, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) { // message was truncated @@ -165,7 +166,7 @@ protected function decryptWithKey($data, $key) * * @throws EncryptionException If key is empty */ - protected function parseParams($params) + protected function parseParams(#[SensitiveParameter] $params) { if ($params === null) { return;