paragonie/ciphersweet
CipherSweet is a PHP library for field-level encryption with searchable encrypted data. It helps you securely encrypt database columns while still supporting safe, blind-index-based search and sorting, with modern cryptography and key management support.
Installation:
composer require paragonie/ciphersweet
Add to composer.json if using a custom repository.
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');
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).
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');
}
}
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();
Batch Operations:
Use CipherSweet::encryptBatch() for bulk data:
$encryptedData = $cipherSweet->encryptBatch([
'email' => 'user@example.com',
'phone' => '123-456-7890',
], ['email', 'phone']);
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;
});
Key Rotation:
KeyProvider::rotateKeys()).Searchability:
pgcrypto or Elasticsearch).CipherSweet with a search provider:
$cipherSweet = new CipherSweet($keyProvider, [
'search_provider' => new ParagonIE\CipherSweet\SearchProvider\PostgresSearchProvider(
config('database.connections.pgsql')
),
]);
Performance:
LaravelCache) for frequently accessed data.Plaintext Exposure:
CipherSweet::isEncrypted() to verify data before processing:
if ($cipherSweet->isEncrypted($value, 'email')) {
$decrypted = $cipherSweet->decrypt($value, 'email');
}
Invalid Keys:
Key not found for context 'email'.FileKeyProvider storage and permissions are correct (chmod 600).Corrupted Data:
Decryption failed.CipherSweet::validate():
if (!$cipherSweet->validate($encryptedData, 'email')) {
throw new \RuntimeException('Invalid encrypted data');
}
Custom Key Providers:
Extend KeyProviderInterface for cloud storage (e.g., AWS KMS):
class AwsKmsKeyProvider implements KeyProviderInterface {
// Implement getKey(), rotateKeys(), etc.
}
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);
}
};
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');
How can I help you explore Laravel packages today?