wazza/laravel-db-encryption

A Laravel package that helps encrypt & decrypt certain defined table columns ensuring the data is secure in the database but can be accessed by the models.

v0.1.0-alpha 2025-06-13 17:18 UTC

This package is auto-updated.

Last update: 2025-06-13 17:34:42 UTC


README

A Laravel package for secure, transparent encryption and decryption of sensitive model attributes, storing them in a dedicated table while keeping your main tables clean and fast.

Features

  • Seamless encryption/decryption of model attributes via a simple trait
  • Encrypted data is stored in a separate encrypted_attributes table
  • Only non-table attributes can be encrypted (enforced at runtime)
  • Automatic loading and saving of encrypted attributes using Eloquent events
  • Search/filter on encrypted properties using SHA-256 hash
  • No sensitive values are ever logged
  • Easy integration: just add the trait and define $encryptedProperties in your model
  • Compatible with Laravel 9+

Requirements

  • PHP 8.1+
  • Laravel 9 or higher
  • OpenSSL PHP extension

How It Works

  1. Add the HasEncryptedAttributes trait to your Eloquent model.
  2. Define a public array property $encryptedProperties listing the attributes you want encrypted (these must NOT exist as columns in the model's table).
  3. When you load a model, encrypted attributes are automatically decrypted and available as normal properties.
  4. When you save a model, encrypted attributes are removed from the main table and securely stored in the encrypted_attributes table.
  5. You can filter/search on encrypted properties using the provided query scope.

Example Model:

use Wazza\DbEncrypt\Traits\HasEncryptedAttributes;

class User extends Model
{
    use HasEncryptedAttributes;

    protected $fillable = ['name', 'email'];

    // Only non-table attributes can be encrypted!
    public array $encryptedProperties = [
        'social_security_number',
        'private_note',
    ];
}

Usage

  • Use your model as normal:
$user = User::find(1);
$user->social_security_number = '123-45-6789';
$user->private_note = 'Sensitive info';
$user->save();

// When you retrieve the user again, encrypted attributes are automatically decrypted:
$user = User::find(1);
echo $user->social_security_number; // '123-45-6789'
  • If you try to add an attribute to $encryptedProperties that already exists as a column, an exception will be thrown.

Filtering/Search on Encrypted Properties

You can filter or search for models by encrypted property value using the built-in query scope:

// Find users with a specific social security number
$users = User::whereEncrypted('social_security_number', '123-45-6789')->get();

This uses the SHA-256 hash of the value and joins the encrypted_attributes table for efficient searching, without ever exposing the decrypted value in the query or logs.

Installation Steps

  1. Require the package in your Laravel project:
    composer require wazza/laravel-db-encryption
  2. Publish the config and migration files (if needed):
    php artisan vendor:publish --provider="Wazza\DbEncrypt\DbEncryptServiceProvider"
  3. Run the migration to create the encrypted_attributes table:
    php artisan migrate
  4. Add the trait and $encryptedProperties to your models as shown above.

Monitoring & Logs

  • All encryption/decryption operations are logged (without sensitive values).
  • To monitor package logs:
    tail -f storage/logs/laravel.log | grep db-encrypt

Testing

  • Run the test suite using Pest:
    ./vendor/bin/pest
    
    PASS  Tests\Unit\EncryptorTest
    ✓ it correctly hashes the value                                         0.40s
    ✓ it correctly encrypts and decrypts data                               0.15s
    ✓ it returns different ciphertext for same plaintext (random IV)        0.12s
    ✓ it throws on null input for encrypt                                   0.13s
    ✓ it throws on null input for decrypt                                   0.13s
    ✓ it throws on invalid base64 for decrypt                               0.14s
    ✓ it throws on missing key in config                                    0.19s
    
     PASS  Tests\Unit\ExampleTest
    ✓ that true is true                                                     0.28s
    
     PASS  Tests\Feature\ExampleTest
    ✓ it contains a successful example feature test                         0.18s
    
    Tests:    9 passed (9 assertions)
    Duration: 1.98s
  • Ensure your models and encrypted attributes behave as expected.

For more details, see the source code and comments. Contributions and issues welcome!