Laminas Doctrine Entity Encryption/Decryption Module
Doctrine Crypt is a simple data encryption/decryption module for your Doctrine entities. This module automates this process by simply listening for database select, insert and update events and reading from your configuration to determine which entities and their properties to process.
This module requires Doctrine Module and uses Doctrine ORM. I also assume that you are familiar with Doctrine ORM, Doctrine Module, Laminas / Zend Framework and using the command line interface.
This was originally an addition to my Doctrine Auth module but has been split and improved in this module. As of v0.4 of Doctrine Auth the encryption has been removed, to use encryption you will need to install this module in your application.
Doctrine Crypt uses Block Cipher AES 256bit encryption by default but you can change this to RSA key encryption if you wish. RSA encryption is restricted in the length of the data you can encrypt. I have implemented RSA encryption as my Doctrine Auth module prior to 0.4 used RSA encryption as an option. This will allow users of this encryption method to decrypt their database and encrypt with Block Cipher if they wish.
Doctrine Crypt also comes with three command line scripts to encrypt, decrypt or to change the encryption method on an existing database using your configuration settings. This will allow you to easily secure your existing database records. Encrypting an unencrypted is not a necessary step though as Doctrine Crypt will start encrypting your records once you start saving them using `\Doctrine\ORM\EntityManager::flush()`. This module can detect if your data is encrypted so it simply passes non-encrypted values through to your entity object.
Unfortunately this module can only process entities automatically as hydrating the results as an array does not go through Doctrine listeners. If you need to access the data as an array you can pass the results array to the Crypt models decryptArray() method, this is not advised for large datasets. The Crypt model also has encrypt() and decrypt() methods to process data manually. There is also a decrypt() view helper as well.
Table of contents- Installation
- Post installation
- Configuration
- Creating RSA keys
- Command line tools
- Using Doctrine array hydration
Installation Return to top
With Composer Return to top
-
In the root of your application enter:
$ composer require krytenuk/doctrine-crypt
Post installation Return to top
-
If you have the
laminas-component-installer plugin you will
be prompted to add the module to your application. If not the simply add it to your `config/modules.config.php` file.
<?php
return array(
'modules' => array(
// ...
'FwsDoctrineCrypt',
),
// ...
); - Copy `./vendor/krytenuk/doctrine-crypt/config/doctrine-crypt.local.php.dist` to `./config/autoload/doctrine-crypt.local.php`.
Configuration Return to top
This module is simply run using the configuration to determine the method of encryption and the entities and their properties to be encrypted/decrypted. Listeners setup in Doctrine will automatically encrypt and decrypt as required.
In your `config/autoload/doctrine-crypt.local.php`
Please check the configuration settings when updating Doctrine Crypt as settings may be added or removed in future releases causing errors in your application
All configuration settings are under the `doctrineCrypt` key
- Key
- Description
- encryptionMethod
- The encryption method to use, either Block Cipher or RSA. Use either one of `\FwsDoctrineCrypt\Model\Crypt::CRYPT_BLOCK_CIPHER`(default) or `\FwsDoctrineCrypt\Model\Crypt::CRYPT_RSA`
Block Cipher encryption setup
- Key
- Description
- encryptionKey
- This is the 256bit key used for AES block cipher encryption. This ideally should be a 32 character random string. You can generate one by going to, https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx, and selecting 256bit.
RSA public key cryptography setup
- Key
- Description
- rsaPrivateKeyFile
- This is your RSA private key file. Please see below for information on how to generate a key pair. The default value is `rsa/key.pem`, this path is relative to your application root.
- rsaPublicKeyFile
- This is your RSA public key file. Please see below for information on how to generate a key pair. The default value is `rsa/key.pub`, this path is relative to your application root.
- rsaKeyPassphrase
- Optional passphrase used when creating the above keys.
Entities configuration
This is where you specify which entities and their properties you wish to process. By adding them here Doctrine Crypt will automatically encrypt/decrypt the records as required. It’s as simple as that!
- Key
- Description
- entities
- A numerical array of entities to process.
Each entity configuration element is an array containing the following elements.
- Key
- Description
- class
- The fully qualified class name of your entity, e.g. `\YourModule\Entity\YourEntity::class`
- properties
- A numerical array containing the entities properties to encrypt/decrypt.
Here is an example configuration.
<?php
use YourModule\Entity\User;
use YourModule\Entity\UserAddress
use FwsDoctrineCrypt\Model\Crypt;
return [
'doctrineCrypt' => [
/**
* Use one of Crypt::CRYPT_BLOCK_CIPHER (recommended) or Crypt::RSA
* @see https://docs.laminas.dev/laminas-crypt/block-cipher/
* @see https://docs.laminas.dev/laminas-crypt/public-key/#rsa
*/
'encryptionMethod' => Crypt::CRYPT_BLOCK_CIPHER,
// for Block Cipher encryption (comment out or remove if not using Block Cipher AES encryption)
'encryptionKey' => 'your_encryption_key',
// for RSA encryption (comment out or remove if not using RSA encryption)
'rsaPrivateKeyFile' => 'rsa/key.pem',
'rsaPublicKeyFile' => 'rsa/key.pub',
'rsaKeyPassphrase' => 'YourPassphrase',
'entities' => [
[
'class' => User::class,
'properties' => [
'firstName',
'surname',
'companyName',
],
],
[
'class' => UserAddress::class,
'properties' => [
'address',
'town',
'county',
'postCode',
],
],
// ...
],
],
];
Creating your RSA encryption/decryption keys Return to top
In order to use RSA public key cryptography you need to create an RSA key pair, not required if using Block Cipher encryption. This can easily be done with openssl, to generate your keys with openssl start with the following command.

$ openssl genrsa -out key.pem 2048
This creates your private key, "key.pem" file. Also you will be asked for a passphrase, please enter this in the configuration. Please note a passphrase is optional but recommended. To extract your public key and create your "key.pub" file simply use.

$ openssl rsa -in key.pem -pubout > key.pub
Don’t forget to copy your keys to the folder you specified in the configuration. For more information please see https://en.wikibooks.org/wiki/Cryptography/Generate_a_keypair_using_OpenSSL.
Command line tools Return to top
Doctrine Crypt also has a couple of command line scripts to encrypt or decrypt your existing database records. These commands read the configuration so all you need to do once you have set you entities is to run the relevant command.
Ensure you backup your database first.
To encrypt your database records.
Doctrine Crypt will attempt to determine if any of your your records have already been encrypted, if so the record(s) are skipped. This is not guaranteed however, so it is not advised to run this command on a already encrypted database, decrypt first.
To perform a test run, no records are saved.

$ ./vendor/bin/doctrine-module doctrine-crypt:encrypt --dry-run
To encrypt and save records.

$ ./vendor/bin/doctrine-module doctrine-crypt:encrypt
To decrypt your database records.
To perform a test run, no records are saved.

$ ./vendor/bin/doctrine-module doctrine-crypt:decrypt --dry-run
To decrypt and save records.

$ ./vendor/bin/doctrine-module doctrine-crypt:encrypt
To change your database encryption method.
I added this command mainly for those who already use the encryption in my Doctrine Auth module and wish to switch from RSA to Block Cipher encryption. This command will automatically do that using your config settings. If you set the encryptionMethod key in the config to Crypt::CRYPT_BLOCK_CIPHER then this command will decrypt your specified entities using RSA and re-encrypt using Block Cipher. The reverse is also true if you set the encryptionMethod key to Crypt::CRYPT_RSA it will decrypt with Block Cipher and re-encrypt with RSA. To do this you need to ensure both encryption methods are set in your configuration.
To perform a test run, no records are saved.

$ ./vendor/bin/doctrine-module doctrine-crypt:re-encrypt --dry-run
To re-encrypt and save records.

$ ./vendor/bin/doctrine-module doctrine-crypt:re-encrypt
This command can also accept two arguments, the decrypt and encrypt methods to use. You must have the encryption/decryption settings in your configuration for this to work. To decrypt using RSA and encrypt using Block Cipher simply use.

$ ./vendor/bin/doctrine-module doctrine-crypt:re-encrypt rsa block-cipher
Using Doctrine array hydration Return to top
The Crypt model
As I have mentioned above the Doctrine listeners are not called when using Doctrine module’s array hydration, AbstractQuery::HYDRATE_ARRAY. If you really need the data as an array then you can manually decrypt using the Crypt::decryptArray() method. This method is not recommended for large datasets. The Crypt model is registered as a service and can be retrieved from the container inside your factories invoke method.
As an example, in your factory
<?php
namespace YourModule\Folder\ServiceFactoryPath;
use FwsDoctrineCrypt\Model\Crypt;
use Doctrine\ORM\EntityManager;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Psr\Container\ContainerInterface;
use YourModule\Folder\YourClass;
class IndexControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null): IndexController
{
return new YourClass(
$container->get(Crypt::class),
$container->get(EntityManager::class)
);
}
}
and in your model or controller
<?php
namespace YourModule\Folder;
use FwsDoctrineCrypt\Model\Crypt;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\AbstractQuery;
class YourClass
{
/**
* Example using PHP 8.1+
*/
public function __construct(
private readonly Crypt $crypt,
private readonly EntityManager $entityManager
): void
{}
public function yourFunction()
{
/** Fetch results from database using array hydration */
$queryBuilder = $entityManager->createQueryBuilder();
$resultsArray = $queryBuilder->select('t')
->from(YourEntity::class, 't')
->getQuery()
->getResult(AbstractQuery::HYDRATE_ARRAY);
/** Decrypt the results array */
$decrypted = $crypt->decryptArray($resultsArray);
}
}
The Crypt model also has encrypt() and decrypt() methods.

<?php
$crypt->decrypt($encryptedValue);

<?php
$crypt->encrypt($value);
The decrypt view helper
As an alternative to the above it is possible to decrypt data inside you view scripts with the decrypt() view helper. Simply use it inside of you view script or view helper with the content to decrypt.
Inside of a view script

<?= $this->decrypt($encryptedValue); ?>;
Inside of a view helper

<?php
namespace YourModule\View\Helper;
class YourViewHelper extends AbstractHelper
{
public function __invoke()
}
$html = '';
// ...
$html .= $this->view->decrypt($encryptedValue);
// ...
return $html;
}
}