Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Spatie Laravel Ciphersweet
https://github.com/spatie/laravel-ciphersweet
Admin
A Laravel package that integrates CipherSweet for searchable field-level encryption, allowing
...
Tokens:
7,055
Snippets:
32
Trust Score:
8.5
Update:
5 months ago
Context
Skills
Chat
Benchmark
81
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Laravel CipherSweet Laravel CipherSweet is a Laravel package that integrates Paragon Initiative's CipherSweet library for field-level encryption with searchable capabilities. It provides a secure way to encrypt sensitive data in your database while maintaining the ability to search encrypted fields using blind indexes, ensuring unauthorized database access does not expose sensitive information. The package seamlessly integrates with Laravel's Eloquent ORM through traits and interfaces, automatically handling encryption during model saves and decryption when retrieving records. It includes Artisan commands for key generation and data encryption, validation rules for encrypted fields, and support for custom cryptographic backends and key providers. ## Model Configuration Configure Eloquent models to use field-level encryption by implementing the interface and trait. ```php use Spatie\LaravelCipherSweet\Contracts\CipherSweetEncrypted; use Spatie\LaravelCipherSweet\Concerns\UsesCipherSweet; use ParagonIE\CipherSweet\EncryptedRow; use ParagonIE\CipherSweet\BlindIndex; use Illuminate\Database\Eloquent\Model; class User extends Model implements CipherSweetEncrypted { use UsesCipherSweet; protected $fillable = ['name', 'email', 'ssn']; public static function configureCipherSweet(EncryptedRow $encryptedRow): void { $encryptedRow ->addField('email') ->addBlindIndex('email', new BlindIndex('email_index')) ->addTextField('ssn') ->addBlindIndex('ssn', new BlindIndex('ssn_index', 256)); } } // Create and save encrypted data $user = User::create([ 'name' => 'John Doe', 'email' => 'john@example.com', 'ssn' => '123-45-6789' ]); // Data is automatically encrypted on save and decrypted on retrieval echo $user->email; // 'john@example.com' (decrypted automatically) ``` ## Key Generation Generate secure encryption keys using the Artisan command. ```bash # Generate and save key to .env file php artisan ciphersweet:generate-key # Display key without saving php artisan ciphersweet:generate-key --show # Generate key in base64 format php artisan ciphersweet:generate-key --base64 # Force key generation in production php artisan ciphersweet:generate-key --force ``` ```env # Add generated key to .env CIPHERSWEET_KEY=def502001f05e5a7b8c5d9e4a3f2c1b0a9e8d7c6b5a4f3e2d1c0b9a8f7e6d5c4 CIPHERSWEET_BACKEND=nacl CIPHERSWEET_PROVIDER=string ``` ## Encrypting Existing Data Encrypt existing unencrypted database records or rotate encryption keys. ```bash # Encrypt all records for a model php artisan ciphersweet:encrypt "App\Models\User" <your-key> # Encrypt with specific sort order (useful for large tables) php artisan ciphersweet:encrypt "App\Models\User" <your-key> desc # Encrypt with custom table name php artisan ciphersweet:encrypt "App\Models\User" <your-key> asc users_archive # Key rotation example php artisan ciphersweet:encrypt "App\Models\User" <new-key> # Update .env with new key after completion ``` ```php // Command validates model implements CipherSweetEncrypted // Updates encrypted fields and blind indexes // Shows progress bar and count of updated rows // Restartable - can be re-run without re-encrypting already processed records ``` ## Searching Encrypted Fields Query encrypted fields using blind indexes with whereBlind scope. ```php use App\Models\User; // Search by encrypted email $user = User::whereBlind('email', 'email_index', 'john@example.com')->first(); // Search by encrypted SSN $users = User::whereBlind('ssn', 'ssn_index', '123-45-6789')->get(); // Chain with other query methods $user = User::whereBlind('email', 'email_index', 'john@example.com') ->where('active', true) ->first(); // Use orWhereBlind for OR conditions $users = User::whereBlind('email', 'email_index', 'john@example.com') ->orWhereBlind('email', 'email_index', 'jane@example.com') ->get(); // Parameters: column name, blind index name, raw value to search // Package automatically hashes the value for blind index lookup ``` ## Encrypted Unique Validation Validate uniqueness of encrypted fields using blind indexes. ```php use Illuminate\Validation\Rule; use Spatie\LaravelCipherSweet\Rules\EncryptedUniqueRule; use App\Models\User; // Using Rule macro (recommended) $request->validate([ 'email' => [ 'required', 'email', Rule::encryptedUnique(User::class, 'email_index') ] ]); // Using rule class directly $request->validate([ 'email' => [ 'required', 'email', new EncryptedUniqueRule(User::class, 'email_index') ] ]); // Ignore specific record (for updates) $request->validate([ 'email' => [ Rule::encryptedUnique(User::class, 'email_index') ->ignore($user->id) ] ]); // Ignore using model instance $request->validate([ 'email' => [ Rule::encryptedUnique(User::class, 'email_index') ->ignoreModel($user) ] ]); // Specify custom column name (defaults to validation attribute) $request->validate([ 'user_email' => [ Rule::encryptedUnique(User::class, 'email_index', 'email') ] ]); ``` ## Configuration Options Configure cryptographic backends and key providers. ```php // config/ciphersweet.php return [ // Cryptographic backend selection // Options: 'nacl' (default), 'boring', 'fips', 'custom' 'backend' => env('CIPHERSWEET_BACKEND', 'nacl'), 'backends' => [ // 'custom' => App\Services\CustomBackendFactory::class, ], // Key provider selection // Options: 'string' (default), 'file', 'random', 'custom' 'provider' => env('CIPHERSWEET_PROVIDER', 'string'), 'providers' => [ 'file' => [ 'path' => env('CIPHERSWEET_FILE_PATH'), ], 'string' => [ 'key' => env('CIPHERSWEET_KEY'), ], // 'custom' => App\Services\CustomKeyProviderFactory::class, ], // Allow NULL values without encryption 'permit_empty' => env('CIPHERSWEET_PERMIT_EMPTY', false) ]; ``` ## Field Type Configuration Configure different field types for optimal encryption. ```php use ParagonIE\CipherSweet\EncryptedRow; use ParagonIE\CipherSweet\BlindIndex; public static function configureCipherSweet(EncryptedRow $encryptedRow): void { $encryptedRow // Generic field (auto-detected type) ->addField('email') // Specific type fields ->addTextField('address') ->addIntegerField('age') ->addBooleanField('is_verified') ->addFloatField('salary') // Optional fields (NULL allowed without encryption) ->addOptionalTextField('middle_name') ->addOptionalIntegerField('employee_id') ->addOptionalBooleanField('newsletter_subscribed') ->addOptionalFloatField('commission_rate') // Blind indexes for searchability ->addBlindIndex('email', new BlindIndex('email_index')) ->addBlindIndex('age', new BlindIndex('age_index', 16)) // Compound blind index (multiple fields) ->addCompoundIndex( 'user_location', ['city', 'state'], 32, true // fast index ); } // Database migration - encrypted fields must be TEXT type Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->text('email'); // TEXT for encrypted data $table->text('ssn'); // TEXT for encrypted data $table->timestamps(); }); ``` ## Custom Backend Implementation Implement custom cryptographic backends for specific requirements. ```php use ParagonIE\CipherSweet\Contract\BackendInterface; use ParagonIE\CipherSweet\Backend\Key\SymmetricKey; class CustomBackendFactory { public function __invoke(): BackendInterface { return new CustomBackend(); } } class CustomBackend implements BackendInterface { public function encrypt(string $plaintext, SymmetricKey $key, string $aad = ''): string { // Custom encryption logic return sodium_crypto_secretbox( $plaintext, $this->generateNonce(), $key->getRawKey() ); } public function decrypt(string $ciphertext, SymmetricKey $key, string $aad = ''): string { // Custom decryption logic $nonce = substr($ciphertext, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); $encrypted = substr($ciphertext, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); return sodium_crypto_secretbox_open($encrypted, $nonce, $key->getRawKey()); } public function blindIndexFast(string $plaintext, SymmetricKey $key, ?int $bitLength = null): string { // Fast blind index generation return hash_hmac('sha256', $plaintext, $key->getRawKey()); } public function blindIndexSlow(string $plaintext, SymmetricKey $key, ?int $bitLength = null, array $config = []): string { // Slow (more secure) blind index using Argon2 return sodium_crypto_pwhash_str( $plaintext, SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE, SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE ); } // Additional required interface methods... public function getPrefix(): string { return 'custom:'; } } // config/ciphersweet.php return [ 'backend' => 'custom', 'backends' => [ 'custom' => App\Services\CustomBackendFactory::class, ], ]; ``` ## Custom Key Provider Implementation Implement custom key providers for different key storage strategies. ```php use ParagonIE\CipherSweet\Contract\KeyProviderInterface; use ParagonIE\CipherSweet\Backend\Key\SymmetricKey; class CustomKeyProviderFactory { public function __invoke(): KeyProviderInterface { return new CustomKeyProvider(); } } class CustomKeyProvider implements KeyProviderInterface { public function getSymmetricKey(): SymmetricKey { // Fetch key from AWS Secrets Manager $client = new SecretsManagerClient([ 'version' => 'latest', 'region' => 'us-east-1', ]); $result = $client->getSecretValue([ 'SecretId' => 'ciphersweet-encryption-key', ]); $key = $result['SecretString']; return new SymmetricKey($key); } } // Alternative: Vault-based provider class VaultKeyProvider implements KeyProviderInterface { public function getSymmetricKey(): SymmetricKey { $vault = new \Vault\Client([ 'base_uri' => env('VAULT_ADDR'), 'token' => env('VAULT_TOKEN'), ]); $secret = $vault->read('secret/data/ciphersweet'); $key = $secret['data']['data']['encryption_key']; return new SymmetricKey($key); } } // config/ciphersweet.php return [ 'provider' => 'custom', 'providers' => [ 'custom' => App\Services\CustomKeyProviderFactory::class, ], ]; ``` ## Blind Index Database Schema The package creates a polymorphic table to store blind indexes for searchability. ```php // database/migrations/create_blind_indexes_table.php Schema::create('blind_indexes', function (Blueprint $table) { $table->morphs('indexable'); // indexable_type, indexable_id $table->string('name'); // Index name (e.g., 'email_index') $table->string('value'); // Hashed index value $table->index(['name', 'value']); // For fast lookups $table->unique(['indexable_type', 'indexable_id', 'name']); // One index per field per record }); // Example records in blind_indexes table: // | indexable_type | indexable_id | name | value | // | App\Models\User | 1 | email_index | a3f5e8d9c2b1... (hash) | // | App\Models\User | 1 | ssn_index | 7c2d9a4e6f8b... (hash) | ``` ## Summary Laravel CipherSweet provides production-ready field-level encryption for Laravel applications requiring sensitive data protection. The primary use cases include encrypting personally identifiable information (PII) like social security numbers, credit card details, medical records, and personal contact information while maintaining search functionality through blind indexes. The package is particularly valuable for applications requiring GDPR, HIPAA, or PCI-DSS compliance where database encryption at rest is insufficient and field-level encryption is mandated. Integration follows standard Laravel patterns with minimal code changes required. Simply implement the interface, add the trait, configure which fields to encrypt, and run migrations. The package handles all encryption/decryption automatically through Eloquent model observers, requires no manual intervention during normal CRUD operations, and provides Artisan commands for batch encryption and key rotation. Blind indexes enable searching on encrypted data without exposing plaintext values, custom backends support specific compliance requirements, and validation rules ensure data integrity while maintaining security standards.