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.
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?