PHPackages                             lekoala/silverstripe-encrypt - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. lekoala/silverstripe-encrypt

ActiveSilverstripe-vendormodule[Security](/categories/security)

lekoala/silverstripe-encrypt
============================

Encrypted database fields and files for SilverStripe using CipherSweet

5.0.0(8mo ago)89.3k↓47.3%47MITPHPPHP ^8.3CI passing

Since Apr 9Pushed 7mo ago3 watchersCompare

[ Source](https://github.com/lekoala/silverstripe-encrypt)[ Packagist](https://packagist.org/packages/lekoala/silverstripe-encrypt)[ GitHub Sponsors](https://github.com/lekoala)[ RSS](/packages/lekoala-silverstripe-encrypt/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (9)Versions (33)Used By (7)

SilverStripe Encrypt module
===========================

[](#silverstripe-encrypt-module)

[![Build Status](https://github.com/lekoala/silverstripe-encrypt/actions/workflows/ci.yml/badge.svg)](https://github.com/lekoala/silverstripe-encrypt/actions)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/f91741c92cbd517bc85e42b9f8ceaf8b34ae4a5581d7c7b65db1a9b29925012a/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/lekoala/silverstripe-encrypt/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/786e9665d762fd839a3cd5b9a00b0192f8c266cc295f638ba1554d224c6665f2/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/lekoala/silverstripe-encrypt/?branch=master)[![Build Status](https://camo.githubusercontent.com/0e6366b6c6dc26cf9f1fabb9781b061f75800b84a943691d1cf25de16284098e/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f6261646765732f6275696c642e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/lekoala/silverstripe-encrypt/build-status/master)[![codecov.io](https://camo.githubusercontent.com/5b3adcf3c9311bf70e4d1e3b0b2de68a0b2fb3ecd18695ef4d6a443e4b2e879d/68747470733a2f2f636f6465636f762e696f2f6769746875622f6c656b6f616c612f73696c7665727374726970652d656e63727970742f636f7665726167652e7376673f6272616e63683d6d6173746572)](https://codecov.io/github/lekoala/silverstripe-encrypt?branch=master)

[![Latest Stable Version](https://camo.githubusercontent.com/4caf721cec84c04f9f33c6b479cc8e866be53e45ced8e42dada7810b548c6e20/68747470733a2f2f706f7365722e707567782e6f72672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f76657273696f6e)](https://packagist.org/packages/lekoala/silverstripe-encrypt)[![Latest Unstable Version](https://camo.githubusercontent.com/418964fbc3139cc7cef79c7c66c4f3adc67a90e2e04d6d0bd4a63b11b4ce39b8/68747470733a2f2f706f7365722e707567782e6f72672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f762f756e737461626c65)](//packagist.org/packages/lekoala/silverstripe-encrypt)[![Total Downloads](https://camo.githubusercontent.com/04731d01f4ee51fd99c4daea83afe268193932b6386f0cd060abf20be3cefd46/68747470733a2f2f706f7365722e707567782e6f72672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f646f776e6c6f616473)](https://packagist.org/packages/lekoala/silverstripe-encrypt)[![License](https://camo.githubusercontent.com/e4ff47d3bad83de172f4777204845bb4dc766fe3359a8a0847bbe730a336caa5/68747470733a2f2f706f7365722e707567782e6f72672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f6c6963656e7365)](https://packagist.org/packages/lekoala/silverstripe-encrypt)[![Monthly Downloads](https://camo.githubusercontent.com/d20a7e571dd68dc530dee3a40f2a7528e80fb7e77386f00acc2bc125ca6ca120/68747470733a2f2f706f7365722e707567782e6f72672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f642f6d6f6e74686c79)](https://packagist.org/packages/lekoala/silverstripe-encrypt)[![Daily Downloads](https://camo.githubusercontent.com/7fd2fc67a78bb42f6c33550156d4d6600c2f3f9a0ca0449bb2a378c347755932/68747470733a2f2f706f7365722e707567782e6f72672f6c656b6f616c612f73696c7665727374726970652d656e63727970742f642f6461696c79)](https://packagist.org/packages/lekoala/silverstripe-encrypt)

Easily add encryption to your DataObjects. In a time of GDPR and data leaks, this module helps you to keep your data secure.

This module use [ciphersweet](https://github.com/paragonie/ciphersweet) under the hood to encrypt field data

Thanks to CipherSweet, your encrypted data is searchable!

How to use
==========

[](#how-to-use)

First of all, you need to define an encryption key as part of your environment. This can be done like so in your `.env` file:

```
ENCRYPTION_KEY='here_is_my_key'

```

You can generate a key with `EncryptHelper::generateKey()`.

*Make sure your key stays safe and that nobody gets access to it*

Important notice
================

[](#important-notice)

*Make sure to enable fast hashes if possible* (read more below)

How this module works
=====================

[](#how-this-module-works)

You define encrypted field types. By default, everything is stored as text (varchars or texts). This is easier since our encrypted data is in text format.

```
class MySecureObject extends DataObject
{
    use HasEncryptedFields;

    private static $db = [
        "Name" => 'Varchar',
        "MyText" => EncryptedDBText::class,
        "MyHTMLText" => EncryptedDBHTMLText::class,
        "MyVarchar" => EncryptedDBVarchar::class,
        "MyNumber" => EncryptedNumberField::class,
        "MyIndexedVarchar" => EncryptedDBField::class,
    ];

    private static $indexes = [
        'MyIndexedVarcharBlindIndex' => true,
        'MyNumberBlindIndex' => true,
        'MyNumberLastFourBlindIndex' => true,
    ];

    public function getField(string $field): mixed
    {
        return $this->getEncryptedField($field);
    }

    public function setField(string $fieldName, mixed $value): static
    {
        return $this->setEncryptedField($fieldName, $value);
    }
}
```

There are two types of fields : simple and indexes (based on Composite field).

The value is encoded before `write` and is decoded when `getField` (or any \_\_get) is called. This is why we have to use the HasEncryptedFields trait, in order to transparently encode and decode data. Otherwise, we end up loading encrypted data from the database that is never decoded if you don't use dbObject calls.

You can of course not use the trait, just keep in mind that your calls to $myObject-&gt;myEncryptedField = 'my value' won't be encoded automatically. But you can most certainly do $myObject-&gt;dbObject('myEncryptedField')-&gt;setValue('my value') ... but that's really not convenient in my opinion. Maybe I'll find some way to avoid overriding the get/set field methods, but I haven't been succesful so far.

A quick note about indexes
==========================

[](#a-quick-note-about-indexes)

Please note that this module doesn't create indexes automatically for your blind indexes. Since you are probably going to use them to search your records, it's a good idea to add a database index to avoid full table scan.

NOTE: blind indexes can have false positives (two records get the same index) and therefore, you cannot be sure that a given blind index will only return one record.

The function `EncryptHelper::planIndexSizeForClass` will help you to set the right values. It returns an array that is similar to this:

```
Array
(
    [min] => 2
    [max] => 32
    [indexes] => 2
    [coincidence_count] => 8589934592
    [coincidence_ratio] => 9.3132257461548E-8
    [estimated_population] => 9223372036854775807
)
```

For each encrypted class, you can set the following config values:

- estimated\_population: the number of expected records. The higher the population, the higher is the coincidence count (which makes your blind index safe to use)
- output\_size and domain\_size: these settings are configured at field level.

```
private static $db = [
    "MyNumber" => EncryptedNumberField::class . '(["output_size" => 4, "domain_size" => 10, "index_size" => 32])',
];
```

Fast hashes
===========

[](#fast-hashes)

By default, this module doesn't enable fast hash indexes. If you expect to do a lot of queries on large table, you need to enable it. **Make sure to run this after #encrypt to override set yml configuration in the module**.

```
---
After:
  - '#encrypt'
---
LeKoala\Encrypt\EncryptHelper:
  fasthash: true
```

This is a global settings. Fast hashes are NOT the same as slow hashes so beware if you have existing data, you need to migrate it before. You can use `EncryptHelper::convertHashType` to help you along if needed.

Simple field types
==================

[](#simple-field-types)

This module provides three fields without blind indexes (if you need a blind index, see next point):

- EncryptedDBText
- EncryptedDBVarchar
- EncryptedDBHTMLText

These fields work exactly like their regular counterpart, except the data is encrypted.

JSON data type
==============

[](#json-data-type)

With EncryptedDBJson you can store json data. By default, it will encrypt the whole json representation but that will prevent using modern db engines features to access specific keys.

Instead, you can encrypt each part of the json data like so:

```
// create definition somewhere...
$map = (new JsonFieldMap())
    ->addTextField('name')
    ->addBooleanField('active')
    ->addIntegerField('age');

$definition = EncryptHelper::convertJsonMapToDefinition($map);

// in your models...
private static $db = [
    "MyEncryptedJson" => EncryptedDBJson::class . "(['map' => '7551830f{\"fields\":{\"$6e616d65\":\"string\",\"$616374697665\":\"bool\",\"$616765\":\"int\"}}'])",
];
```

The map needs to be stored in the field definition under the map option as a string representation. This can be created using `EncryptHelper::convertJsonMapToDefinition`.

NOTE: unspecified keys will be left unencrypted.

Searching for data
==================

[](#searching-for-data)

Thanks to CipherSweet, data is encrypted with a blind index. This blind index can be used to search data if you know the value or a partial value based on what kind of index you created.

To search using an index, use the EncryptedDBField instance

```
$singl = singleton(MyModel::class);
$obj = $singl->dbObject('MyEncryptedField');
$searchValue = $obj->getSearchValue($value);
$query = MyModel::get()->where(array('MyEncryptedFieldBlindIndex = ?' => $searchValue));
```

Or use shortcut

```
$singl = singleton(MyModel::class);
$obj = $singl->dbObject('MyEncryptedField');
$record = $obj->fetchRecord($value);
```

Or even better

```
$record = MyModel::getByBlindIndex("MyEncryptedField", $value);
$list = MyModel::getAllByBlindIndex("MyEncryptedField", $value);
```

We cannot use a regular search filter because of the false positive.

It is highly recommended to set indexes on your fields that use blind indexes. The convention is as follows: {Name}BlindIndex and {Name}LastFourBlindIndex

This module provides two fields with blind indexes:

- EncryptedDBField that holds a single value with a full blind index
- EncryptedNumberField that holds a single value with a full blind index and a blind index for the last 4 digits

You can extend `EncryptedDBField` to add more fields types to suit your use case. Make sure their name starts with "Encrypted".

Encrypt and decrypt other kind of data
======================================

[](#encrypt-and-decrypt-other-kind-of-data)

You can also encrypt and decrypt data using a symmetrical key with the helper

```
$someText = 'some text';
$encrypt = EncryptHelper::encrypt($someText);
$decryptedValue = EncryptHelper::decrypt($encrypt);
```

Handling encrypted files
========================

[](#handling-encrypted-files)

This module automatically adds `EncryptedDBFile` extension to your files. This is done in an extension of the base File class in order to avoid adding one more table in order to add an `Encrypted` field in your table that tracks encryption status

Please note that files are not encrypted by default, you need to call `encryptFileIfNeeded` after your uploads.

```
$myFile->encryptFileIfNeeded();
```

Or use the `EncryptedFile` class. It's better to use the `EncryptedFile` class because it will properly update the Encrypted flag if you update the file for example. Prefer checking Encrypted flag rather than using `isEncrypted` because this method is rather slow.

Also, performance wise, remember that loading a file in order to check it's state can be slow

```
$file = $this->File();
$file->encryptFileIfNeeded();
// fine for one record, not fine in a loop! Use EncryptHelper::checkIfFileIsEncrypted with ID
```

NOTE: Even if your files are encrypted, they should not be available in your public folder.

Make sure to review [SilverStripe file security](https://docs.silverstripe.org/en/4/developer_guides/files/file_security/) documentation. Keeping files .protected and served by a dedicated controller (using `sendDecryptedFile`) is necessary or through the `DecryptController`.

Key rotation
============

[](#key-rotation)

If you need to change algo or key, you will need to rotate encryption.

Rotating algorithm with the same key is easy and built into this module. It happens automatically by default and you can use the `needsToRotateEncryption` and `rotateEncryption` methods.

If you need to change key, you need to refer it first in the env:

```
OLD_ENCRYPTION_KEY='here_is_my_old_key'

```

Then call `rotateEncryption` like this

```
$oldKey = EncryptHelper::getOldKey();
$old = EncryptHelper::getEngineForEncryption("nacl", $oldKey);
$result = $model->needsToRotateEncryption($old);
if($result) {
    $result = $model->rotateEncryption($old);
}
```

Planning index sizes
====================

[](#planning-index-sizes)

If you are using blind indexes, you might need to plan their sizes.

It is highly recommended to read the following guide about blind index planning.

This modules gives you some tools and defaults that helps you to have your indexes properly configured.

By default, blind indexes will have a size of 32 chars which allow a large numbers of records in your table with a really low

Using aad
=========

[](#using-aad)

By default, this module will use AAD.

This binds the ciphertext to a specific row, thereby preventing an attacker capable of replacing ciphertexts and using legitimate app access to decrypt ciphertexts they wouldn't otherwise have access to.

This setting is controlled by `aad_source` parameter that takes by default the "ID" value. You can disable aad by setting this to an empty string.

On first write, records get their ID. Therefore, you need to make sure that the ID is set on the encrypted fields. This can be done like this. Some safety checks are also in place in case you don't do this.

```
protected function writeBaseRecord($baseTable, $now)
{
    parent::writeBaseRecord($baseTable, $now);
    // After base record is written, we have an ID and therefore AAD has changed
    $this->resetFieldValues();
}
```

Compatibility
=============

[](#compatibility)

Tested with SilverStripe 6+

For v4/5, use branch 4

Branch 1 : encryption system was different, not compatible with new versions Branch 2 : composite fields were different, rotate your values if upgrading to new versions

Maintainer
==========

[](#maintainer)

LeKoala -

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance62

Regular maintenance activity

Popularity33

Limited adoption so far

Community21

Small or concentrated contributor base

Maturity89

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 70.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~87 days

Recently: every ~100 days

Total

32

Last Release

249d ago

Major Versions

1.0.1 → 2.0.02020-12-15

2.x-dev → 3.0.02021-07-07

1.x-dev → 3.4.12023-05-31

3.5.2 → 4.0.02024-02-01

4.x-dev → 5.0.02025-09-11

PHP version history (7 changes)0.1PHP &gt;=5.6

1.0PHP ~7

2.0.0PHP &gt;7.2

3.4.0PHP ^7.4 || ^8.0

3.5.0PHP ^7.4 || ^8

4.0.0PHP ^8.1

5.0.0PHP ^8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/250762?v=4)[Thomas Portelange](/maintainers/lekoala)[@lekoala](https://github.com/lekoala)

---

Top Contributors

[![lekoala](https://avatars.githubusercontent.com/u/250762?v=4)](https://github.com/lekoala "lekoala (97 commits)")[![gordonbanderson](https://avatars.githubusercontent.com/u/7060?v=4)](https://github.com/gordonbanderson "gordonbanderson (39 commits)")[![alex-dna](https://avatars.githubusercontent.com/u/6982515?v=4)](https://github.com/alex-dna "alex-dna (1 commits)")

---

Tags

ciphersweetdecryptionencryptionsilverstripesecuritysilverstripeencryptdecryptmoduleciphersweet

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/lekoala-silverstripe-encrypt/health.svg)

```
[![Health](https://phpackages.com/badges/lekoala-silverstripe-encrypt/health.svg)](https://phpackages.com/packages/lekoala-silverstripe-encrypt)
```

###  Alternatives

[nzo/url-encryptor-bundle

The NzoUrlEncryptorBundle is a Symfony Bundle used to Encrypt and Decrypt data and variables in the Web application or passed through URL

961.0M2](/packages/nzo-url-encryptor-bundle)[xxtea/xxtea

XXTEA is a fast and secure encryption algorithm. This is a XXTEA library for PHP.

11341.7k](/packages/xxtea-xxtea)[bringyourownideas/silverstripe-composer-security-checker

Provides information if your SilverStripe application uses dependencies with known vulnerabilities.

10103.9k2](/packages/bringyourownideas-silverstripe-composer-security-checker)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
