PHPackages                             developgravity/laravel-binary-encryption - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. developgravity/laravel-binary-encryption

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

developgravity/laravel-binary-encryption
========================================

Eloquent cast and encryption helper that gzip-compresses and encrypts into a compact versioned binary format.

03PHPCI passing

Since Apr 7Pushed 1mo agoCompare

[ Source](https://github.com/DevelopGravity/Laravel-Binary-Encryption)[ Packagist](https://packagist.org/packages/developgravity/laravel-binary-encryption)[ RSS](/packages/developgravity-laravel-binary-encryption/feed)WikiDiscussions develop Synced 1w ago

READMEChangelogDependenciesVersions (2)Used By (0)

Laravel Binary Encryption Cast
==============================

[](#laravel-binary-encryption-cast)

An Eloquent cast that gzip-compresses and encrypts model attributes into a compact versioned binary format. All cryptography is delegated to Laravel's built-in Encrypter — this package only handles compression and binary packing for efficient storage.

Requirements
------------

[](#requirements)

- PHP 8.5+
- Laravel 12 or 13

Installation
------------

[](#installation)

```
composer require developgravity/laravel-binary-encryption
```

The package auto-discovers its service provider and facade. No manual registration needed. It uses your application's existing `APP_KEY` and `app.cipher` settings.

Usage
-----

[](#usage)

Apply the cast to any Eloquent model attribute:

```
use DevelopGravity\BinaryEncryption\Casts\BinaryEncryptedCast;

class ApiCredential extends Model
{
    protected function casts(): array
    {
        return [
            'secret_key' => BinaryEncryptedCast::class,
            'webhook_secret' => BinaryEncryptedCast::class,
        ];
    }
}
```

Values are automatically encrypted on write and decrypted on read:

```
$credential = ApiCredential::create([
    'secret_key' => 'sk_live_abc123...',
    'webhook_secret' => 'whsec_xyz789...',
]);

// Stored as compact binary in the database
// Transparently decrypted when accessed
echo $credential->secret_key; // 'sk_live_abc123...'
```

### Cast Subtypes

[](#cast-subtypes)

Like Laravel's built-in `encrypted` cast, you can encrypt structured data by appending a subtype:

```
use DevelopGravity\BinaryEncryption\Casts\BinaryEncryptedCast;

class Integration extends Model
{
    protected function casts(): array
    {
        return [
            'api_key'    => BinaryEncryptedCast::class,               // string
            'settings'   => BinaryEncryptedCast::class.':array',      // array
            'config'     => BinaryEncryptedCast::class.':json',       // array (alias)
            'metadata'   => BinaryEncryptedCast::class.':object',     // stdClass
            'tags'       => BinaryEncryptedCast::class.':collection', // Collection
        ];
    }
}
```

Subtype`get()` returns`set()` accepts*(none)*`string``string``:array``array``array` or `object``:json``array` (alias for `:array`)`array` or `object``:object``stdClass``array` or `object``:collection``Illuminate\Support\Collection``array` or `object`Values are JSON-encoded before encryption and JSON-decoded after decryption.

### Using the Facade Directly

[](#using-the-facade-directly)

```
use DevelopGravity\BinaryEncryption\Facades\BinaryEncrypt;

$encrypted = BinaryEncrypt::encrypt('sensitive data');
$decrypted = BinaryEncrypt::decrypt($encrypted);
```

How It Works
------------

[](#how-it-works)

1. **Compress** — Plaintext is gzip-compressed to reduce storage size.
2. **Encrypt** — The compressed data is encrypted using Laravel's Encrypter (`encryptString`).
3. **Repack** — Laravel's base64+JSON output is decoded and repacked into a compact binary format with a versioned 3-byte header (version, cipher ID, flags), followed by the raw IV, authentication tag/MAC, and ciphertext with length prefixes.
4. **Decrypt** reverses the process: unpack binary → reconstruct Laravel's expected payload format → `decryptString` → gzip decompress.

### Supported Ciphers

[](#supported-ciphers)

CipherIDAES-256-CBC`0x01`AES-256-GCM`0x02`AES-128-CBC`0x03`AES-128-GCM`0x04`The cipher is determined by your `app.cipher` config value.

### Binary Format (v1)

[](#binary-format-v1)

```
[version: 1 byte] [cipher_id: 1 byte] [flags: 1 byte]
[iv_length: 2 bytes BE] [iv: variable]
[auth_length: 2 bytes BE] [auth: variable]
[ciphertext_length: 4 bytes BE] [ciphertext: variable]

```

Common Pitfalls
---------------

[](#common-pitfalls)

### Null Bytes and PostgreSQL `bytea` Columns

[](#null-bytes-and-postgresql-bytea-columns)

The encrypted binary output frequently contains null bytes (`\0`). This is expected and correct — it's raw binary data, not a text string.

**The problem:** PDO's default `PDO::PARAM_STR` binding truncates strings at the first null byte. If you store encrypted values in a PostgreSQL `bytea` column using the default connection, your data will be silently truncated and unrecoverable.

**The solution:** You need to ensure binary values containing null bytes are bound with `PDO::PARAM_LOB` instead of `PDO::PARAM_STR`. Here's one approach using a custom connection:

```
// app/Database/PostgresConnection.php
namespace App\Database;

use Illuminate\Database\PostgresConnection as BasePostgresConnection;
use PDO;

class PostgresConnection extends BasePostgresConnection
{
    public function prepareBindings(array $bindings): array
    {
        $grammar = $this->getQueryGrammar();

        foreach ($bindings as $key => $value) {
            if ($value instanceof \DateTimeInterface) {
                $bindings[$key] = $value->format($grammar->getDateFormat());
            } elseif (is_bool($value)) {
                $bindings[$key] = $value;
            } elseif (is_string($value) && str_contains($value, "\0")) {
                // Wrap binary strings for LOB binding
                $bindings[$key] = new BinaryValue($value);
            }
        }

        return $bindings;
    }

    public function bindValues($statement, $bindings): void
    {
        foreach ($bindings as $key => $value) {
            if ($value instanceof BinaryValue) {
                $statement->bindValue(
                    is_string($key) ? $key : $key + 1,
                    $value->bytes,
                    PDO::PARAM_LOB,
                );
                continue;
            }

            $statement->bindValue(
                is_string($key) ? $key : $key + 1,
                $value,
                match (true) {
                    is_int($value) => PDO::PARAM_INT,
                    is_bool($value) => PDO::PARAM_BOOL,
                    is_resource($value) => PDO::PARAM_LOB,
                    default => PDO::PARAM_STR,
                },
            );
        }
    }
}
```

```
// app/Database/BinaryValue.php
namespace App\Database;

use Stringable;

readonly class BinaryValue implements Stringable
{
    public function __construct(public string $bytes) {}

    public function __toString(): string
    {
        return $this->bytes;
    }
}
```

Register it in a service provider:

```
use Illuminate\Database\Connection;
use App\Database\PostgresConnection;

Connection::resolverFor('pgsql', function ($pdo, $database, $prefix, $config) {
    return new PostgresConnection($pdo, $database, $prefix, $config);
});
```

> **Note:** If you use a package that already provides a custom `pgsql` connection resolver (e.g. `tpetry/laravel-postgresql-enhanced`), you'll need to extend that connection class instead of Laravel's base, since only one resolver can be active at a time.

### MySQL and SQLite

[](#mysql-and-sqlite)

MySQL `BLOB`/`VARBINARY` and SQLite `BLOB` columns handle null bytes correctly with `PDO::PARAM_STR`. No custom connection is needed for these databases.

Testing
-------

[](#testing)

```
composer test
```

Or run Pest directly:

```
vendor/bin/pest
```

License
-------

[](#license)

MIT License. See [LICENSE.md](LICENSE.md) for details.

###  Health Score

20

—

LowBetter than 13% of packages

Maintenance59

Moderate activity, may be stable

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/82eece9b0980b310d99248c2f824c332869079f02622e56a120876c2ff028fd6?d=identicon)[DevelopGravity](/maintainers/DevelopGravity)

---

Top Contributors

[![ZacharyDuBois](https://avatars.githubusercontent.com/u/2458289?v=4)](https://github.com/ZacharyDuBois "ZacharyDuBois (14 commits)")

### Embed Badge

![Health badge](/badges/developgravity-laravel-binary-encryption/health.svg)

```
[![Health](https://phpackages.com/badges/developgravity-laravel-binary-encryption/health.svg)](https://phpackages.com/packages/developgravity-laravel-binary-encryption)
```

PHPackages © 2026

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