Repository navigation
Conversation
[security] encryption_key now also accepts a list of keys. The first entry is the current key and is used for all encryption; later entries are decrypt-only previous keys, tried in order when the current key fails. A plain string or a single-entry list builds the same single-key Encrypter as before. Empty later entries are ignored. An empty first entry throws rather than promoting a previous key, so an unset env var cannot cause new data to be encrypted with a retired key. Every key is validated at construction. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Replace RotatingEncrypter with Cubex\Encryption\Encrypter, which extends Illuminate's Encrypter and accepts either a key or a list of keys. The first key encrypts and is tried first on decrypt; later keys are decrypt-only fallbacks. EncryptionService always binds it, so string and list config share one class and instanceof Illuminate's Encrypter holds. Co-Authored-By: Claude Opus 5.5 <[email protected]>
encryption_cipher defaults to AES-128-CBC. It is either one cipher for every key or a list aligned by index with encryption_key, so a rotation can move to AES-256-CBC while the previous key stays AES-128-CBC. A list must have one entry per key entry, including empty ones; a list with a single string key throws; an empty cipher entry is the default. decrypt() now keeps the first failure while trying each key, so no catch variable goes unused. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Cubex\Encryption\Encrypter is now standalone and implements Illuminate\Contracts\Encryption\Encrypter, reading and writing the same payload format as illuminate/encryption 5.x and throwing the contracts' DecryptException/EncryptException. illuminate/contracts is now a direct requirement; illuminate/encryption is require-dev only, for compatibility tests in both directions. Remove security.encryption_cipher: a 16 byte key uses AES-128-CBC and a 32 byte key AES-256-CBC, anything else throws. 16 byte keys behave as before, and 32 byte keys previously threw under the default cipher. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Contributor
Author
|
Superseded by #73, which rebuilds this on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
encrypteraccepts only one AES-128 key, so replacing[security] encryption_keymakes everything encrypted under the old key (e.g. cookies) undecryptable at once.EncryptionServicenow bindsCubex\Encryption\Encrypter, a standalone implementation ofIlluminate\Contracts\Encryption\Encrypter. It reads and writes exactly the illuminate/encryption 5.x payload:base64(json({iv, value, mac})), openssl AES-CBC, HMAC-SHA256 MAC checked with the same double-HMAC comparison. It throws the contracts'DecryptException/EncryptException, soIlluminate\Cookie\Middleware\EncryptCookiesworks unchanged and existing cookies keep decrypting.illuminate/encryptionmoves torequire-dev(tests only), andilluminate/contractsbecomes a direct requirement (it was already pulled in by container/support/cookie). The bound object is no longer an instance ofIlluminate\Encryption\Encrypter; code that type-hints the contract is unaffected.encryption_keycan be a key or a list. The first key is current: it encrypts, is returned bygetKey(), and is tried first on decrypt. Later keys are only used to decrypt, in order, and the first failure is rethrown if none match. Each key's cipher follows its length: 16 bytes is AES-128-CBC, 32 bytes is AES-256-CBC, anything else throws at boot. There is no cipher setting.A single 16-byte string key behaves as before. Empty later entries are ignored. An empty first entry throws instead of promoting an old key, so an unset env var can't cause new data to be encrypted with a retired key. A missing item or
[]uses the existing default key.Fallback keys are usually being retired because they're compromised, so anything that decrypts with one may be forged. Keep the window short and don't base security decisions on cookie contents during it; consumers can re-issue cookies to move them onto the current key.
decrypt()still calls plainunserialize()like Illuminate's; untrusted input should use$unserialize = falsewithallowed_classes => false.Test plan
EncrypterTestchecks compatibility against the real illuminate/encryption 5.5.44 in both directions for AES-128-CBC and AES-256-CBC, covering serialized values,$unserialize = falseand the*Stringmethods. It also covers:EncryptionServiceTestcovers string, list, 32-byte, missing and[]config.Results on PHP 7.4 with this branch's own dependencies (PHPUnit 6.5):
ReflectionType::__toString()deprecations inCubexTest, which fail the same way on2.6.8.--no-devinstall leaves out illuminate/encryption, and the encrypter still works there.Rollout
2.0withgh release create.cubex/frameworkand setsencryption_key[]to the new 32-char env key first and the old 16-char key second.🤖 Generated with Claude Code