Weave Code
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

Field Encryption Bundle Laravel Package

caeligo/field-encryption-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require caeligo/field-encryption-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Caeligo\FieldEncryptionBundle\FieldEncryptionBundle::class => ['all' => true],
    ];
    
  2. Configure Encryption Keys Generate keys via console (run once):

    php bin/console field-encryption:generate-keys
    

    Store keys securely in .env (default paths):

    FIELD_ENCRYPTION_KEY_PATH=%kernel.project_dir%/var/encryption/keys
    FIELD_ENCRYPTION_KEY_FILE=app.key
    
  3. Annotate Your Entity Use #[Encrypted] on string fields:

    use Caeligo\FieldEncryptionBundle\Attribute\Encrypted;
    
    #[ORM\Entity]
    class User {
        #[ORM\Column(type: 'string')]
        #[Encrypted]
        private string $ssn;
    }
    
  4. First Use Case Save an entity—fields are auto-encrypted:

    $user = new User();
    $user->setSsn('123-45-6789');
    $entityManager->persist($user);
    $entityManager->flush();
    

    Retrieve it—fields are auto-decrypted:

    $user = $entityManager->find(User::class, $id);
    // $user->getSsn() returns '123-45-6789' (decrypted)
    

Implementation Patterns

Workflows

  1. String Field Encryption

    • Usage: Mark sensitive strings (e.g., password, ssn) with #[Encrypted].
    • Searching: Use #[Encrypted(searchable: true)] to enable HMAC-based searches.
      $users = $entityManager->createQueryBuilder()
          ->andWhere('u.ssn LIKE :ssn')
          ->setParameter('ssn', '%123%')
          ->getQuery()
          ->getResult();
      
    • QueryBuilder: Works seamlessly with Doctrine queries—no manual encryption/decryption.
  2. Binary File Encryption

    • Usage: Use #[EncryptedFile] for file uploads (e.g., profilePicture).
      #[ORM\Column(type: 'blob')]
      #[EncryptedFile]
      private $profilePicture;
      
    • Metadata: Automatically stores filename, mimeType, size, and originalSize.
    • Upload Handling:
      $user->setProfilePicture($file->getContent());
      $entityManager->flush();
      // File is encrypted and stored as binary blob.
      
  3. Key Rotation

    • Trigger Rotation:
      php bin/console field-encryption:rotate-keys
      
    • Progress Tracking: Uses a FieldEncryptionKeyRotation entity to track migration status.
    • Data Migration: Run the migration command to re-encrypt data with the new key:
      php bin/console field-encryption:migrate-data
      
  4. Compression

    • Enable for binary files in config/packages/field_encryption.yaml:
      field_encryption:
          compression:
              enabled: true
              algorithm: gzip
      

Integration Tips

  • Symfony Forms: Works out-of-the-box with EntityType or File fields.
    $builder->add('profilePicture', FileType::class, [
        'mapped' => false, // Handle upload manually or use a custom form type.
    ]);
    
  • APIs: Return encrypted data in responses—decryption happens automatically when accessing properties.
  • Testing: Use FieldEncryptionBundle\Tests\TestCase for encrypted field assertions:
    $this->assertEncryptedField($user->getSsn(), '123-45-6789');
    

Gotchas and Tips

Pitfalls

  1. Key Management

    • Issue: Losing the encryption key means permanent data loss.
    • Fix: Store keys in a secure vault (e.g., AWS KMS, HashiCorp Vault) and back them up offline.
    • Tip: Use the FIELD_ENCRYPTION_KEY_PATH env var to customize the key storage location.
  2. Search Performance

    • Issue: Searching encrypted fields (#[Encrypted(searchable: true)]) requires HMAC hashing, which adds overhead.
    • Fix: Index HMAC columns in the database for large datasets:
      #[ORM\Column(type: 'string', length: 64)]
      #[Encrypted(searchable: true)]
      private string $ssn;
      #[ORM\Column(type: 'string', length: 64)]
      private string $ssnHash; // Manually managed if needed.
      
  3. Binary File Handling

    • Issue: Large files (e.g., videos) may bloat the database.
    • Fix: Store encrypted files in S3/GridFS and use #[EncryptedFile] with a string column for the file path.
    • Tip: Disable compression for large files:
      field_encryption:
          compression:
              enabled: false
      
  4. Doctrine Events

    • Issue: Custom Doctrine lifecycle callbacks may interfere with encryption.
    • Fix: Ensure callbacks run after encryption/decryption by using ON_POST_LOAD/ON_POST_PERSIST:
      #[ORM\HasLifecycleCallbacks]
      class User {
          #[ORM\PostLoad]
          public function onPostLoad() {
              // This runs after decryption.
          }
      }
      
  5. Key Rotation Downtime

    • Issue: Data encrypted with the old key becomes inaccessible during rotation.
    • Fix: Use the FieldEncryptionKeyRotation entity to track progress and ensure all data is migrated before removing the old key.

Debugging

  • Enable Logging: Add to config/packages/monolog.yaml:
    handlers:
        field_encryption:
            type: stream
            path: "%kernel.logs_dir%/field_encryption.log"
            level: debug
            channels: ["field_encryption"]
    
  • Check Encrypted Data: Dump raw database values to verify encryption:
    $connection = $entityManager->getConnection();
    $sql = 'SELECT HEX(ssn) FROM user WHERE id = ?';
    $stmt = $connection->prepare($sql);
    $stmt->execute([$user->getId()]);
    var_dump($stmt->fetch());
    
  • Key Validation: Test key rotation with a backup key first:
    php bin/console field-encryption:rotate-keys --dry-run
    

Extension Points

  1. Custom Attributes

    • Extend the bundle by creating your own attributes (e.g., #[EncryptedWithMetadata]):
      #[Attribute(Attribute::TARGET_PROPERTY)]
      class EncryptedWithMetadata extends Encrypted {
          public bool $storeMetadata = true;
      }
      
    • Register the custom attribute in the bundle’s FieldEncryptionExtension.
  2. Key Providers

    • Implement Caeligo\FieldEncryptionBundle\Key\KeyProviderInterface for dynamic key fetching (e.g., from a hardware module):
      class VaultKeyProvider implements KeyProviderInterface {
          public function getKey(string $keyId): string {
              return $this->vault->read($keyId);
          }
      }
      
    • Configure in config/packages/field_encryption.yaml:
      field_encryption:
          key_provider: App\Key\VaultKeyProvider
      
  3. Event Listeners

    • Listen to FieldEncryptionEvents for custom logic (e.g., audit logging):
      use Caeligo\FieldEncryptionBundle\Event\FieldEncryptionEvent;
      
      $eventDispatcher->addListener(
          FieldEncryptionEvent::PRE_ENCRYPT,
          function (FieldEncryptionEvent $event) {
              // Log before encryption.
          }
      );
      
  4. Custom Cipher

    • Override the default AES cipher by implementing Caeligo\FieldEncryptionBundle\Cipher\CipherInterface:
      class ChaCha20Cipher implements CipherInterface {
          public function encrypt(string $data, string $key): string { /* ... */ }
          public function decrypt(string $data, string $key): string { /* ... */ }
      }
      
    • Register in the bundle’s services.yaml.
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle