caeligo/field-encryption-bundle
Install the Bundle
composer require caeligo/field-encryption-bundle
Add to config/bundles.php:
return [
// ...
Caeligo\FieldEncryptionBundle\FieldEncryptionBundle::class => ['all' => true],
];
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
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;
}
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)
String Field Encryption
password, ssn) with #[Encrypted].#[Encrypted(searchable: true)] to enable HMAC-based searches.
$users = $entityManager->createQueryBuilder()
->andWhere('u.ssn LIKE :ssn')
->setParameter('ssn', '%123%')
->getQuery()
->getResult();
Binary File Encryption
#[EncryptedFile] for file uploads (e.g., profilePicture).
#[ORM\Column(type: 'blob')]
#[EncryptedFile]
private $profilePicture;
filename, mimeType, size, and originalSize.$user->setProfilePicture($file->getContent());
$entityManager->flush();
// File is encrypted and stored as binary blob.
Key Rotation
php bin/console field-encryption:rotate-keys
FieldEncryptionKeyRotation entity to track migration status.php bin/console field-encryption:migrate-data
Compression
config/packages/field_encryption.yaml:
field_encryption:
compression:
enabled: true
algorithm: gzip
EntityType or File fields.
$builder->add('profilePicture', FileType::class, [
'mapped' => false, // Handle upload manually or use a custom form type.
]);
FieldEncryptionBundle\Tests\TestCase for encrypted field assertions:
$this->assertEncryptedField($user->getSsn(), '123-45-6789');
Key Management
FIELD_ENCRYPTION_KEY_PATH env var to customize the key storage location.Search Performance
#[Encrypted(searchable: true)]) requires HMAC hashing, which adds overhead.#[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.
Binary File Handling
#[EncryptedFile] with a string column for the file path.field_encryption:
compression:
enabled: false
Doctrine Events
ON_POST_LOAD/ON_POST_PERSIST:
#[ORM\HasLifecycleCallbacks]
class User {
#[ORM\PostLoad]
public function onPostLoad() {
// This runs after decryption.
}
}
Key Rotation Downtime
FieldEncryptionKeyRotation entity to track progress and ensure all data is migrated before removing the old key.config/packages/monolog.yaml:
handlers:
field_encryption:
type: stream
path: "%kernel.logs_dir%/field_encryption.log"
level: debug
channels: ["field_encryption"]
$connection = $entityManager->getConnection();
$sql = 'SELECT HEX(ssn) FROM user WHERE id = ?';
$stmt = $connection->prepare($sql);
$stmt->execute([$user->getId()]);
var_dump($stmt->fetch());
php bin/console field-encryption:rotate-keys --dry-run
Custom Attributes
#[EncryptedWithMetadata]):
#[Attribute(Attribute::TARGET_PROPERTY)]
class EncryptedWithMetadata extends Encrypted {
public bool $storeMetadata = true;
}
FieldEncryptionExtension.Key Providers
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);
}
}
config/packages/field_encryption.yaml:
field_encryption:
key_provider: App\Key\VaultKeyProvider
Event Listeners
FieldEncryptionEvents for custom logic (e.g., audit logging):
use Caeligo\FieldEncryptionBundle\Event\FieldEncryptionEvent;
$eventDispatcher->addListener(
FieldEncryptionEvent::PRE_ENCRYPT,
function (FieldEncryptionEvent $event) {
// Log before encryption.
}
);
Custom Cipher
Caeligo\FieldEncryptionBundle\Cipher\CipherInterface:
class ChaCha20Cipher implements CipherInterface {
public function encrypt(string $data, string $key): string { /* ... */ }
public function decrypt(string $data, string $key): string { /* ... */ }
}
services.yaml.How can I help you explore Laravel packages today?