Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Encryption Bundle Laravel Package

sidus/encryption-bundle

Sidus Encryption Bundle is a Symfony/Doctrine integration for transparent field-level encryption, automatically encrypting and decrypting sensitive entity fields so data is protected at rest while application code keeps using normal entity properties.

View on GitHub
Deep Wiki
Context7

Getting Started

First, confirm the architectural premise: this is a Symfony Bundle built on Doctrine ORM lifecycle events, not a Laravel package. There is no Eloquent analogue for postLoad/prePersist interception. As a Laravel developer you have two paths:

  • Doctrine already in the stack. Vendor the bundle (never require from Packagist unguarded — see Gotchas), register it, and use it as designed.
  • Eloquent (default Laravel). Do not install it. Read the source as a pattern reference — the value is the annotation-driven Doctrine type + key-per-entity model, not the cryptography. Reimplement in ~200–400 lines as an Eloquent cast backed by sodium_crypto_secretbox and a KMS master key.

If you do proceed on Symfony/Doctrine:

  1. Pin a fork via a VCS or path repository in composer.json — the repo is dormant (2 stars, 0 dependents), so treat upstream as frozen.
  2. Register SidusEncryptionBundle in config/bundles.php and configure the encryptor + key provider under config/packages/sidus_encryption.yaml.
  3. Run the bundle migrations to create the EncryptionKey entity table. Note the default key storage is the same database as the ciphertext — weak against the most common threat (DB dump). Plan to override the key provider with KMS/Vault before rollout.
  4. Apply the encrypted field attribute/type to one high-sensitivity, low-query column.
  5. Persist and read normally — encryption is transparent through the Doctrine custom type and an event subscriber.

First use case: a single low-risk PII field (national ID, DOB, free-text health note) on one entity in a non-production environment. Measure hydration overhead before expanding. Avoid starting with email, username, or anything you filter/sort/LIKE on — encrypted columns are non-deterministic and unqueryable.

For the Laravel-native equivalent, mirror the seam: EncryptedCast for columns, a Flysystem decorator for files, per-record data keys wrapped by a KMS master key cached per request.

Implementation Patterns

Field-level via Doctrine custom type. Mark the property with the bundle's encrypted attribute and the custom type. Writes encrypt in prePersist/preUpdate; reads decrypt on hydration. Code keeps reading plaintext; the DB holds ciphertext. This is the seam to replicate — in Eloquent, it's a CastsAttributes implementation.

Encrypted files alongside entities. The bundle stores an encrypted file path on the entity and encrypts the blob on write. The interesting design element is the hybrid RSA+AES approach for file payloads — asymmetric wrap of a symmetric key. Do not encrypt large files with RSA directly; it is prohibitively slow per row/object. If you need this pattern in Laravel, encrypt on the storage-driver boundary (a Flysystem decorator) so S3/local behave identically and streaming is preserved.

Pluggable encryptors and key providers via Symfony DI. This is the extension point you would actually use — swap the default file-based key provider for a KMS/Vault-backed service so key material lives outside the database. In Laravel, the equivalent is a KeyProvider contract bound in a service provider.

Key rotation via multiple key versions. The bundle supports versioned keys; rotation is O(rows) and requires a resumable, idempotent background re-encryption job. Never attempt a synchronous table rewrite. In Laravel, model it as encryption_key_id on the row + a queued job that re-wraps/re-encrypts per chunk.

Testing against the seam. Because encryption is transparent at the persistence layer, unit tests using in-memory repositories won't exercise it. Write integration tests against a real DB and verify the raw column is ciphertext before asserting the hydrated value is plaintext. For Laravel, add a test asserting the DB driver sees ciphertext (not the cast's plaintext).

Searchability via blind index. Where you genuinely need WHERE/ORDER BY on a sensitive field, add a separate column holding an HMAC of the normalized value (a deterministic blind index) — never attempt to query ciphertext. Document this constraint with product before promising filters.

Gotchas and Tips

  • License gate. GPL-2.0 is viral on distribution. Internal/self-hosted SaaS is generally fine; on-prem appliances, SDKs, or any redistributable artifact compel GPL on surrounding work. Copying source creates derivative-work ambiguity; copying patterns and writing fresh code does not. Confirm with legal before any code is copied.
  • Effective abandonment. No maintainer, no security advisories, no CVE watch, no Stack Overflow corpus. If adopted you own the fork permanently — PHP upgrades, Doctrine API deprecations, crypto fixes.
  • Version drift is a certainty, not a risk. Expect breakage on PHP 8.2+, Symfony 6+, and Doctrine 3.x. Budget a compatibility patch set (return types, deprecated APIs, compiler pass signatures) before first deploy.
  • Key-in-database default. The bundled EncryptionKey persistence puts key material next to ciphertext. Against a backup/dump adversary this is weak protection. Override the key provider with KMS/Vault before any production use.
  • Lost key = unrecoverable data. Not degraded — gone. Require KMS backup, key escrow, and a tested restore drill before rollout.
  • Plaintext leaks past the hydration boundary. Decryption at hydration means plaintext exists in every model instance, in toArray()/JSON responses, in logs, in queue payloads, and in cache. Redact explicitly where serialization, logging, or job dispatch occurs — the bundle gives you nothing here.
  • Ciphertext inflates ~33–40% (base64 + nonce + tag). Plan column sizes, storage budget, and index width accordingly; VARCHAR(255) on an encrypted field will silently truncate.
  • N+1 key lookups. The EncryptionKey association will be fetched per row on list endpoints unless you cache per request. Profile list pages specifically.
  • Per-row CPU on read paths. Every hydration pays decrypt cost. Benchmark at realistic row counts; if you have high write throughput or wide result sets, this is measurable latency.
  • Files must stream. If the implementation buffers whole files in memory, large uploads hit memory limits. Wrap the storage driver rather than file contents.
  • Hydration exceptions are load failures. One corrupted ciphertext or missing key throws on postLoad and can fail an entire query — including unrelated rows. Consider a nullable/tryDecrypt variant in your own fork that returns a sentinel and alerts rather than 500ing a page.
  • Debugging tip: when a decrypt fails, log the key version and the first/last bytes of the ciphertext — never the plaintext or the full key. This is usually enough to distinguish a rotation mismatch from a corruption.
  • For Laravel developers: everything above translates 1:1 to an Eloquent cast + KMS-backed key provider + blind index. The bundle's genuine contribution is the Doctrine lifecycle hook; that integration is what you are choosing to own or re-implement. Given zero adoption and GPL-2.0, the default recommendation is re-implement the pattern natively — roughly a week of engineering, fully under your license and control, with no bus factor.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package