PHPackages                             ercsctt/laravel-file-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. [Security](/categories/security)
4. /
5. ercsctt/laravel-file-encryption

ActiveLibrary[Security](/categories/security)

ercsctt/laravel-file-encryption
===============================

Secure file encryption and decryption for Laravel applications

v1.1.0(1mo ago)642.6k↓40.7%1MITPHPPHP ^8.2CI passing

Since Jan 19Pushed 1mo agoCompare

[ Source](https://github.com/ercsctt/laravel-file-encryption)[ Packagist](https://packagist.org/packages/ercsctt/laravel-file-encryption)[ Docs](https://github.com/ercsctt/laravel-file-encryption)[ RSS](/packages/ercsctt-laravel-file-encryption/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (20)Versions (3)Used By (0)

Laravel File Encryption
=======================

[](#laravel-file-encryption)

A robust file encryption package for Laravel using AES-256-GCM authenticated encryption. Designed for secure, efficient encryption and decryption of files of any size with streaming support for memory-efficient processing of large files.

Features
--------

[](#features)

- **AES-256-GCM encryption** - Industry-standard authenticated encryption
- **Streaming support** - Process files of any size with minimal memory usage
- **Key rotation** - Seamlessly rotate encryption keys without downtime
- **Artisan commands** - Encrypt and decrypt files from the command line
- **Facade and helper** - Convenient ways to use the package

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

[](#requirements)

- PHP 8.2 or higher
- Laravel 11.0 or higher
- OpenSSL PHP extension

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

[](#installation)

Install the package via Composer:

```
composer require ercsctt/laravel-file-encryption
```

The package will automatically register its service provider.

Configuration
-------------

[](#configuration)

Publish the configuration file:

```
php artisan vendor:publish --tag=file-encryption-config
```

This will create a `config/file-encryption.php` file.

### Environment Variables

[](#environment-variables)

Add the following to your `.env` file:

```
FILE_ENCRYPTION_KEY=base64:your-base64-encoded-32-byte-key
```

Generate a key using:

```
php artisan tinker --execute="echo 'base64:'.base64_encode(random_bytes(32));"
```

Optional configuration:

```
# Previous keys for key rotation (comma-separated, base64-encoded)
FILE_ENCRYPTION_PREVIOUS_KEYS=base64:old-key-1,base64:old-key-2

# Chunk size for streaming (default: 65536 bytes)
FILE_ENCRYPTION_CHUNK_SIZE=65536
```

Usage
-----

[](#usage)

### Using the Facade

[](#using-the-facade)

```
use Ercsctt\FileEncryption\Facades\FileEncrypter;

// Encrypt a file
FileEncrypter::encryptFile('/path/to/source.txt', '/path/to/encrypted.enc');

// Decrypt a file
FileEncrypter::decryptFile('/path/to/encrypted.enc', '/path/to/decrypted.txt');

// Auto-generate destination path (appends .enc for encryption)
FileEncrypter::encryptFile('/path/to/source.txt'); // Creates source.txt.enc

// Auto-generate destination path (removes .enc for decryption)
FileEncrypter::decryptFile('/path/to/source.txt.enc'); // Creates source.txt

// Get decrypted contents as string
$contents = FileEncrypter::decryptedContents('/path/to/encrypted.enc');

// Check if a file is encrypted
if (FileEncrypter::isEncrypted('/path/to/file.enc')) {
    // File has encryption magic bytes
}
```

### Using the Helper Function

[](#using-the-helper-function)

```
// Decrypt and get file contents
$contents = decrypt_file('/path/to/encrypted.enc');
```

### Direct Instantiation

[](#direct-instantiation)

```
use Ercsctt\FileEncryption\FileEncrypter;

// Key must be exactly 32 bytes for AES-256
$key = random_bytes(32);
$encrypter = new FileEncrypter($key);

// With custom chunk size (minimum 1024 bytes)
$encrypter = new FileEncrypter($key, 131072); // 128KB chunks

// Encrypt and decrypt
$encrypter->encryptFile('/path/to/source.txt', '/path/to/encrypted.enc');
$encrypter->decryptFile('/path/to/encrypted.enc', '/path/to/decrypted.txt');
```

### Artisan Commands

[](#artisan-commands)

#### Encrypt Command

[](#encrypt-command)

```
php artisan file:encrypt {path} [options]
```

**Options:**

OptionDescription`--key=`Encryption key (base64-encoded). Uses configured key if not provided`-R, --recursive`Recursively encrypt all files in a directory`--force`Skip confirmation prompts`--chunk-size=65536`Chunk size in bytes for streaming`--prune`Delete original files after successful encryption**Examples:**

```
# Encrypt a single file (creates document.pdf.enc)
php artisan file:encrypt storage/app/document.pdf

# Encrypt with a specific key
php artisan file:encrypt storage/app/secret.txt --key="base64:abc123..."

# Encrypt an entire directory recursively
php artisan file:encrypt storage/app/private --recursive

# Encrypt directory and delete originals after encryption
php artisan file:encrypt storage/app/sensitive --recursive --prune

# Encrypt without confirmation prompts (useful for scripts/CI)
php artisan file:encrypt storage/app/data --recursive --force

# Encrypt with larger chunks for better performance on big files
php artisan file:encrypt storage/app/large-video.mp4 --chunk-size=1048576

# Combine options: encrypt directory, delete originals, no prompts
php artisan file:encrypt storage/app/backup --recursive --prune --force
```

#### Decrypt Command

[](#decrypt-command)

```
php artisan file:decrypt {path?} [options]
```

**Options:**

OptionDescription`--key=`Decryption key (base64-encoded)`-R, --recursive`Recursively decrypt all .enc files in a directory`--force`Skip confirmation prompts`--keep`Keep encrypted files after successful decryption`--output=`Custom output path for decrypted file`--scan`Scan entire project for encrypted (.enc) files**Examples:**

```
# Decrypt a single file (creates document.pdf from document.pdf.enc)
php artisan file:decrypt storage/app/document.pdf.enc

# Decrypt with a specific key
php artisan file:decrypt storage/app/secret.txt.enc --key="base64:abc123..."

# Decrypt to a custom output path
php artisan file:decrypt storage/app/config.json.enc --output=config/decrypted.json

# Decrypt an entire directory recursively
php artisan file:decrypt storage/app/private --recursive

# Decrypt but keep the encrypted files (useful for verification)
php artisan file:decrypt storage/app/backup --recursive --keep

# Decrypt without confirmation prompts
php artisan file:decrypt storage/app/data.enc --force

# Scan entire project for encrypted files and decrypt them
php artisan file:decrypt --scan

# Scan and decrypt all found files, keeping encrypted versions
php artisan file:decrypt --scan --keep

# Scan and decrypt without prompts (CI/scripts)
php artisan file:decrypt --scan --force

# Combine options: decrypt directory recursively, no prompts, keep originals
php artisan file:decrypt storage/app/encrypted --recursive --force --keep
```

#### Common Workflows

[](#common-workflows)

**Encrypt sensitive uploads for storage:**

```
# Encrypt all files in uploads directory, remove originals
php artisan file:encrypt storage/app/uploads --recursive --prune --force
```

**Decrypt files for processing, then re-encrypt:**

```
# Decrypt keeping encrypted versions
php artisan file:decrypt storage/app/data --recursive --keep --force

# ... process the files ...

# Re-encrypt (original .enc files still exist as backup)
php artisan file:encrypt storage/app/data --recursive --prune --force
```

**Find and decrypt all encrypted files in a project:**

```
# Scan finds all .enc files in the project and decrypts them
php artisan file:decrypt --scan --force
```

**Migrate to a new encryption key:**

```
# 1. Set new key in .env, add old key to FILE_ENCRYPTION_PREVIOUS_KEYS
# 2. Decrypt all files (will use old key automatically)
php artisan file:decrypt storage/app/encrypted --recursive --force

# 3. Re-encrypt with new key
php artisan file:encrypt storage/app/encrypted --recursive --prune --force
```

### Streaming Large Files

[](#streaming-large-files)

For large files, use `decryptedStream()` for memory-efficient processing:

```
use Ercsctt\FileEncryption\Facades\FileEncrypter;

// Stream decrypted content through a callback
FileEncrypter::decryptedStream('/path/to/large-file.enc', function ($chunk) {
    echo $chunk; // Process each chunk
});

// Stream to a file handle
$output = fopen('/path/to/output.txt', 'wb');
FileEncrypter::decryptedStream('/path/to/encrypted.enc', function ($chunk) use ($output) {
    fwrite($output, $chunk);
});
fclose($output);

// Stream for hashing
$context = hash_init('sha256');
FileEncrypter::decryptedStream('/path/to/file.enc', function ($chunk) use ($context) {
    hash_update($context, $chunk);
});
$hash = hash_final($context);
```

### Progress Callbacks

[](#progress-callbacks)

Monitor progress when processing large files:

```
use Ercsctt\FileEncryption\Facades\FileEncrypter;

// Progress callback receives current chunk and total chunks
FileEncrypter::encryptFile(
    '/path/to/large-file.zip',
    '/path/to/encrypted.enc',
    function ($currentChunk, $totalChunks) {
        $percent = round(($currentChunk / $totalChunks) * 100);
        echo "Encrypting: {$percent}%\n";
    }
);

FileEncrypter::decryptFile(
    '/path/to/encrypted.enc',
    '/path/to/decrypted.zip',
    function ($currentChunk, $totalChunks) {
        echo "Decrypting chunk {$currentChunk} of {$totalChunks}\n";
    }
);
```

### Key Rotation

[](#key-rotation)

When you need to rotate your encryption key:

1. Generate a new key:

    ```
    php artisan tinker --execute="echo 'base64:'.base64_encode(random_bytes(32));"
    ```
2. Update your `.env` file:

    ```
    FILE_ENCRYPTION_KEY=base64:your-new-key
    FILE_ENCRYPTION_PREVIOUS_KEYS=base64:your-old-key
    ```
3. The package will automatically try previous keys when decrypting files encrypted with old keys.
4. Programmatically configure previous keys:

    ```
    use Ercsctt\FileEncryption\FileEncrypter;

    $currentKey = random_bytes(32);
    $oldKey = '...'; // Your previous 32-byte key

    $encrypter = (new FileEncrypter($currentKey))->previousKeys([$oldKey]);

    // Decryption will try current key first, then fall back to old keys
    $encrypter->decryptFile('/path/to/old-encrypted.enc', '/path/to/decrypted.txt');

    // Get all configured keys
    $allKeys = $encrypter->getAllKeys(); // Returns [currentKey, oldKey]
    ```

Security Features
-----------------

[](#security-features)

- **AES-256-GCM** - Provides both confidentiality and authenticity
- **Unique nonce per chunk** - Each chunk uses a unique 12-byte nonce derived from base nonce XORed with chunk index
- **Authentication tag** - 16-byte GCM authentication tag per chunk prevents tampering
- **Chunk index in AAD** - Additional authenticated data includes chunk index to prevent reordering attacks
- **Header HMAC** - 12-byte truncated HMAC-SHA256 protects header integrity
- **Constant-time comparisons** - Uses `hash_equals()` to prevent timing attacks
- **Secure key handling** - Keys marked with `#[\SensitiveParameter]` attribute

File Format
-----------

[](#file-format)

Encrypted files use the following binary format:

```
HEADER (32 bytes):
  [4 bytes: Magic "LENC"]
  [1 byte: Version]
  [1 byte: Cipher ID (1 = AES-256-GCM)]
  [2 bytes: Reserved]
  [4 bytes: Chunk size (big-endian)]
  [8 bytes: Original file size (big-endian)]
  [12 bytes: Header HMAC]

CHUNKS (repeated):
  [12 bytes: Nonce]
  [N bytes: Ciphertext]
  [16 bytes: GCM authentication tag]

```

Error Handling
--------------

[](#error-handling)

The package throws specific exceptions for different error conditions:

```
use Ercsctt\FileEncryption\Facades\FileEncrypter;
use Illuminate\Contracts\Encryption\EncryptException;
use Illuminate\Contracts\Encryption\DecryptException;

try {
    FileEncrypter::encryptFile('/path/to/source.txt', '/path/to/encrypted.enc');
} catch (EncryptException $e) {
    // Handle encryption failure (file not found, not readable, etc.)
}

try {
    FileEncrypter::decryptFile('/path/to/encrypted.enc', '/path/to/decrypted.txt');
} catch (DecryptException $e) {
    // Handle decryption failure (wrong key, corrupted file, invalid format, etc.)
}
```

### Key Validation

[](#key-validation)

```
use Ercsctt\FileEncryption\FileEncrypter;

// Keys must be exactly 32 bytes
try {
    new FileEncrypter(str_repeat('a', 16)); // Too short!
} catch (RuntimeException $e) {
    echo $e->getMessage(); // "File encryption requires a 32-byte key for AES-256-GCM."
}

// Chunk size must be at least 1024 bytes
try {
    new FileEncrypter(random_bytes(32), 512); // Too small!
} catch (RuntimeException $e) {
    echo $e->getMessage(); // "Chunk size must be at least 1024 bytes."
}
```

Testing
-------

[](#testing)

Run the test suite:

```
composer test
```

Or with PHPUnit directly:

```
./vendor/bin/phpunit
```

API Reference
-------------

[](#api-reference)

### FileEncrypter Methods

[](#fileencrypter-methods)

MethodSignatureDescription`encryptFile``(string $source, ?string $dest = null, ?callable $progress = null): void`Encrypt a file. Destination defaults to `$source.enc``decryptFile``(string $source, ?string $dest = null, ?callable $progress = null): void`Decrypt a file. Destination defaults to source without `.enc``decryptedContents``(string $path): string`Return entire decrypted file contents as string`decryptedStream``(string $path, callable $callback): void`Stream decrypted chunks through callback`isEncrypted``(string $path): bool`Check if file has encryption magic bytes`previousKeys``(array $keys): static`Set previous keys for key rotation (fluent)`getKey``(): string`Get primary encryption key`getChunkSize``(): int`Get configured chunk size`getAllKeys``(): array`Get all keys (primary + previous)License
-------

[](#license)

This package is open-sourced software licensed under the [MIT license](LICENSE).

###  Health Score

48

—

FairBetter than 94% of packages

Maintenance89

Actively maintained with recent releases

Popularity35

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 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.

###  Release Activity

Cadence

Every ~57 days

Total

2

Last Release

54d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e29db764bf76823d6793c6c9f559582a7c37601b64f858df8623b8e22508a04f?d=identicon)[ercsctt](/maintainers/ercsctt)

---

Top Contributors

[![ercsctt](https://avatars.githubusercontent.com/u/6897798?v=4)](https://github.com/ercsctt "ercsctt (5 commits)")

---

Tags

laravelsecurityencryptionaes-256-gcmfile-encryption

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ercsctt-laravel-file-encryption/health.svg)

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

###  Alternatives

[laravel-zero/framework

The Laravel Zero Framework.

3371.4M369](/packages/laravel-zero-framework)[tzsk/otp

A secure, database-free One-Time Password (OTP) generator and verifier for PHP and Laravel.

241641.4k1](/packages/tzsk-otp)[laravel/ai

The official AI SDK for Laravel.

732506.3k60](/packages/laravel-ai)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)[cybercog/laravel-clickhouse

ClickHouse migrations for Laravel

163166.8k](/packages/cybercog-laravel-clickhouse)[dolphiq/laravel-aescrypt

AES encrypt and decrypt Eloquent attributes inspired by elocryptfive

171.7k](/packages/dolphiq-laravel-aescrypt)

PHPackages © 2026

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