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

Ciphersweet Laravel Package

paragonie/ciphersweet

CipherSweet is a PHP library for fast, secure field-level encryption with searchable encrypted indexes. Designed for applications that need to protect sensitive data at rest while still supporting equality and range queries, with strong cryptography and clean integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require paragonie/ciphersweet
    

    Add to composer.json if using a custom repository.

  2. First Use Case: Encrypt a sensitive field (e.g., email) in a Laravel model:

    use ParagonIE\CipherSweet\CipherSweet;
    use ParagonIE\CipherSweet\KeyProvider\FileKeyProvider;
    
    // Initialize in a service provider (e.g., AppServiceProvider)
    $keyProvider = new FileKeyProvider(storage_path('app/ciphersweet-keys'));
    $cipherSweet = new CipherSweet($keyProvider);
    
    // Encrypt a value
    $encryptedEmail = $cipherSweet->encrypt('user@example.com', 'email');
    
    // Decrypt later
    $decryptedEmail = $cipherSweet->decrypt($encryptedEmail, 'email');
    
  3. Key Management: Generate keys via CLI:

    php vendor/bin/ciphersweet generate-keys storage/app/ciphersweet-keys
    

    Store keys securely (e.g., encrypted in .env or a secrets manager).


Implementation Patterns

Field-Level Encryption in Eloquent

  1. Model Integration: Use accessors/mutators for automatic encryption/decryption:

    class User extends Model {
        protected $casts = [
            'email' => EncryptedAttribute::class,
        ];
    
        // Or manually:
        public function setEmailAttribute($value) {
            $this->attributes['email'] = $cipherSweet->encrypt($value, 'email');
        }
    
        public function getEmailAttribute($value) {
            return $cipherSweet->decrypt($value, 'email');
        }
    }
    
  2. Query Filtering: Leverage CipherSweet’s searchable encryption for filtered queries:

    // Encrypt with a searchable token
    $encryptedEmail = $cipherSweet->encrypt('user@example.com', 'email', ['searchable' => true]);
    
    // Query encrypted fields (requires a search index)
    $users = User::whereEncrypted('email', 'user@example.com')->get();
    
  3. Batch Operations: Use CipherSweet::encryptBatch() for bulk data:

    $encryptedData = $cipherSweet->encryptBatch([
        'email' => 'user@example.com',
        'phone' => '123-456-7890',
    ], ['email', 'phone']);
    

Workflows

  • Data Migration: Encrypt existing data in a migration:

    public function up() {
        User::chunk(100, function ($users) {
            foreach ($users as $user) {
                $user->email = $this->cipherSweet->encrypt($user->email, 'email');
                $user->save();
            }
        });
    }
    
  • API Responses: Decrypt data before sending to clients:

    return User::find($id)->load(['posts' => function ($query) {
        $query->select('id', 'title', 'encrypted_content');
    }])->map(function ($user) {
        $user->posts->each(function ($post) {
            $post->content = $this->cipherSweet->decrypt($post->encrypted_content, 'content');
        });
        return $user;
    });
    

Gotchas and Tips

Pitfalls

  1. Key Rotation:

    • Rotate keys periodically (use KeyProvider::rotateKeys()).
    • Gotcha: Decrypted data may fail if old keys are purged before rotation completes.
    • Fix: Use a key transition period (keep old keys available temporarily).
  2. Searchability:

    • Gotcha: Searchable encryption requires a search index (e.g., PostgreSQL pgcrypto or Elasticsearch).
    • Fix: Configure CipherSweet with a search provider:
      $cipherSweet = new CipherSweet($keyProvider, [
          'search_provider' => new ParagonIE\CipherSweet\SearchProvider\PostgresSearchProvider(
              config('database.connections.pgsql')
          ),
      ]);
      
  3. Performance:

    • Gotcha: Encryption/decryption adds latency (~1-5ms per field).
    • Fix: Cache decrypted values in memory (e.g., LaravelCache) for frequently accessed data.
  4. Plaintext Exposure:

    • Gotcha: Accidentally logging or dumping encrypted data may reveal plaintext if misconfigured.
    • Fix: Use CipherSweet::isEncrypted() to verify data before processing:
      if ($cipherSweet->isEncrypted($value, 'email')) {
          $decrypted = $cipherSweet->decrypt($value, 'email');
      }
      

Debugging

  • Invalid Keys:

    • Error: Key not found for context 'email'.
    • Fix: Verify keys exist in FileKeyProvider storage and permissions are correct (chmod 600).
  • Corrupted Data:

    • Error: Decryption failed.
    • Fix: Check for truncated data or incorrect context labels. Use CipherSweet::validate():
      if (!$cipherSweet->validate($encryptedData, 'email')) {
          throw new \RuntimeException('Invalid encrypted data');
      }
      

Extension Points

  1. Custom Key Providers: Extend KeyProviderInterface for cloud storage (e.g., AWS KMS):

    class AwsKmsKeyProvider implements KeyProviderInterface {
        // Implement getKey(), rotateKeys(), etc.
    }
    
  2. Context-Specific Logic: Override CipherSweet to add field-specific rules:

    $cipherSweet = new class($keyProvider) extends CipherSweet {
        public function encrypt($plaintext, $context, $options = []) {
            if ($context === 'ssn') {
                $options['searchable'] = false; // Never search SSNs
            }
            return parent::encrypt($plaintext, $context, $options);
        }
    };
    
  3. Laravel Integration: Publish config and create a facade for cleaner usage:

    // config/ciphersweet.php
    return [
        'key_path' => storage_path('app/ciphersweet-keys'),
        'search_provider' => env('CIPHERSWEET_SEARCH_PROVIDER', null),
    ];
    
    // Facade
    Facades\CipherSweet::encrypt($value, 'context');
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky