paragonie/doctrine-ciphersweet

v0.1.0 2025-10-02 08:19 UTC

This package is auto-updated.

Last update: 2025-10-02 08:22:14 UTC


README

Build Status Example App Static Analysis Latest Stable Version Latest Unstable Version License Downloads

Use searchable encryption with Doctrine ORM, powered by CipherSweet.

Installation

composer require paragonie/doctrine-ciphersweet

Usage

First, you need to create a ParagonIE\CipherSweet\CipherSweet object. Please refer to the CipherSweet docs.

use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\KeyProvider\StringProvider;

$keyProvider = new StringProvider(random_bytes(32));
$engine = new CipherSweet($keyProvider);

Next, create an EncryptedFieldSubscriber and register it with your EntityManager.

use ParagonIE\DoctrineCipher\Event\EncryptedFieldSubscriber;

$subscriber = new EncryptedFieldSubscriber($engine);
$entityManager->getEventManager()->addEventSubscriber($subscriber);

Now you can use the #[Encrypted] attribute on your entity properties.

use Doctrine\ORM\Mapping as ORM;
use ParagonIE\DoctrineCipher\Attribute\Encrypted;

#[ORM\Entity]
class Message
{
    #[ORM\Id]
    #[ORM\Column(type: 'integer')]
    #[ORM\GeneratedValue]
    private int $id;

    #[ORM\Column(type: 'text')]
    #[Encrypted]
    private string $text;
    
    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $textBlindIndexInsensitive;

    public function __construct(string $text)
    {
        $this->text = $text;
    }

    // ... getters and setters
}

When you persist an entity, the EncryptedFieldSubscriber will automatically encrypt the properties that have the #[Encrypted] attribute.

$message = new Message('This is a secret message.');
$entityManager->persist($message);
$entityManager->flush();

When you retrieve an entity, the encrypted properties will be automatically decrypted.

$message = $entityManager->find(Message::class, 1);
echo $message->getText(); // "This is a secret message."

Blind Indexes

You can also use blind indexes for searchable encryption. To do this, add a blindIndexes argument to the #[Encrypted] attribute.

use Doctrine\ORM\Mapping as ORM;
use ParagonIE\DoctrineCipher\Attribute\Encrypted;

#[ORM\Entity]
class Message
{
    #[ORM\Id]
    #[ORM\Column(type: 'integer')]
    #[ORM\GeneratedValue]
    private int $id;

    #[ORM\Column(type: 'text')]
    #[Encrypted(blindIndexes: ['insensitive' => 'case-insensitive'])]
    private string $text;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $textBlindIndexInsensitive;

    public function __construct(string $text)
    {
        $this->text = $text;
    }

    // ... getters and setters
}

You also need to register a transformer for the blind index.

use ParagonIE\CipherSweet\Transformation\Lowercase;

$subscriber->addTransformer('case-insensitive', Lowercase::class);

Now you can query the blind index.

To do so, you must first calculate the blind index for your search term.

use ParagonIE\CipherSweet\BlindIndex;
use ParagonIE\CipherSweet\EncryptedField;

// First, you need to get the blind index for your search term.
// Note: The EncryptedField must be configured exactly as it is for the entity.
$encryptedField = new EncryptedField($engine, 'messages', 'text');
$encryptedField->addBlindIndex(new BlindIndex('insensitive', [new Lowercase()]));

$searchTerm = 'this is a secret message.';
$blindIndex = $encryptedField->getBlindIndex($searchTerm, 'insensitive');

// Now you can use this blind index to query the database.
$repository = $entityManager->getRepository(Message::class);
$message = $repository->findOneBy(['textBlindIndexInsensitive' => $blindIndex]);

Support Contracts

If your company uses this library in their products or services, you may be interested in purchasing a support contract from Paragon Initiative Enterprises.