PHPackages                             authcrypt/crypto-php - 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. authcrypt/crypto-php

ActiveLibrary[Security](/categories/security)

authcrypt/crypto-php
====================

Application-level symmetric encryption for PHP

1.0.0(1mo ago)10MITPHPPHP 8.2 - 8.5CI passing

Since Jun 27Pushed 1mo agoCompare

[ Source](https://github.com/authcrypt/crypto-php)[ Packagist](https://packagist.org/packages/authcrypt/crypto-php)[ Docs](https://github.com/authcrypt/crypto-php)[ RSS](/packages/authcrypt-crypto-php/feed)WikiDiscussions master Synced 2w ago

READMEChangelogDependencies (4)Versions (2)Used By (0)

Application‑Level Encryption for PHP
====================================

[](#applicationlevel-encryption-for-php)

This package provides a modern, authenticated encryption layer built on AEAD ciphers. It is designed for:

- Application‑Level Encryption (ALE) and protection of objects in storage.
- Field‑level encryption in databases.
- Client‑Side Encryption for cloud storage.
- Long‑term data storage with the ability to upgrade cryptographic algorithms.

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

[](#requirements)

- PHP 8.2 - 8.5.
- `hash` PHP extension.
- `openssl` PHP extension - optional.
- `sodium` PHP extension - optional.

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

[](#installation)

The package could be installed with [Composer](https://getcomposer.org):

```
composer require authcrypt/crypto-php
```

Quick Start
-----------

[](#quick-start)

```
use Authcrypt\Crypto\KdfCryptor;
use Authcrypt\Crypto\Cipher\SodiumAeadCipher;
use Authcrypt\Crypto\Hkdf\HkdfExtended;

$secret = hex2bin('0123456789abcdef...');
$kdf = new HkdfExtended();
$cipher = new SodiumAeadCipher();

$cryptor = new KdfCryptor(
    secret: $secret,
    kdf: $kdf,
    cipher: $cipher,
);

$context = 'application-specific-context';

$encrypted = $cryptor->encrypt('secret data', $context);
$data = $cryptor->decrypt($encrypted, $context);
```

Cryptors
--------

[](#cryptors)

All cryptors implement `CryptorInterface` and are responsible for the overall encryption flow. They differ in how the data encryption key (`DEK`) is obtained and how the ciphertext is structured.

### `KdfCryptor`

[](#kdfcryptor)

`KDF`‑based encryption (single key derived per message, no key wrapping).
A fresh Data Encryption Key (`DEK`) is derived from the secret and the provided context using the configured `KDF`. If the configured `KDF` requires a salt, a random salt is generated for each message and prepended to the ciphertext.

Output structure:

```
kdfSalt (optional) || nonce || encryptedData (with tag)

```

### `EnvelopeCryptor`

[](#envelopecryptor)

Envelope encryption (key wrapping) using a `KDF` to derive a Key Encryption Key (`KEK`) and a random Data Encryption Key (`DEK`). The `DEK` is wrapped with the `KEK` and stored alongside the ciphertext. The `DEK` is used to encrypt the actual data.

The `DEK` wrap cipher can be specified separately (e.g., `OpenSSLWrapCipher`); if omitted, the data cipher is used for wrapping as well.

Output structure:

```
kdfSalt || dekNonce || wrappedDEK (with tag) || dataNonce || encryptedData (with tag)

```

### `VersionedCryptor`

[](#versionedcryptor)

Wraps multiple cryptors and adds a fixed‑length version prefix to every ciphertext.

Output structure:

```
version (fixed length) || encrypted payload from underlying cryptor

```

Key Derivation
--------------

[](#key-derivation)

The package provides two HKDF‑based KDF implementations (RFC 5869), both suitable for high‑entropy secrets (random keys).

### `HkdfExtended`

[](#hkdfextended)

Directly applies `HKDF` to the input secret. Suitable when the secret is already a strong random key (32 bytes or more).

This implementation satisfies the **KDF Security** requirements (resistance to key extraction and key expansion attacks) as defined in the `HKDF` specification.

`HkdfExtended` supports static salt for domain separation, ensuring that keys derived for different contexts remain distinct even when the same secret is used. It also provides dynamic salt for per‑message randomness, which is enabled by default. When dynamic salt is disabled, the caller must supply a unique context for each derivation to prevent key reuse.

### `HkdfPlain`

[](#hkdfplain)

A simpler variant that applies `HKDF` without a static salt. This is suitable when you do not need additional domain separation, or when the secret itself is already adequately randomised.

When salt is disabled, the caller must supply a unique context per encryption.

Ciphers
-------

[](#ciphers)

The package provides two backends: `OpenSSL` and `Sodium` (`libsodium`).

### SodiumAeadCipher

[](#sodiumaeadcipher)

Uses `Sodium`'s high‑performance `AEAD` ciphers. Supports the following algorithms:

- `AES-256-GCM` – requires hardware `AES‑NI` support.
- `CHACHA20-POLY1305-IETF` - **default**
- `XCHACHA20-POLY1305-IETF`

Note: `AES‑256‑GCM` with `Sodium` requires CPU support for AES instructions (`AES‑NI`).

### OpenSSLAeadCipher

[](#opensslaeadcipher)

Uses `OpenSSL`'s `AEAD` ciphers. Supports the following algorithms:

- `AES-128-GCM`
- `AES-192-GCM`
- `AES-256-GCM`
- `CHACHA20-POLY1305` (`IETF` variant, 12‑byte nonce) - **default**

### OpenSSLWrapCipher

[](#opensslwrapcipher)

A dedicated cipher for key wrapping (RFC 5649 `AES‑KW`). This cipher should only be used inside `EnvelopeCryptor` for wrapping `DEKs`, not for general‑purpose encryption. Allowed algorithms:

- `AES-128-WRAP`
- `AES-192-WRAP`
- `AES-256-WRAP` - **default**

Examples
--------

[](#examples)

### User data encryption

[](#user-data-encryption)

Use this when each entity (user, record, document) has a natural unique identifier. The context includes that identifier, so no dynamic salt is needed, making the ciphertext shorter.

```
use Authcrypt\Crypto\KdfCryptor;
use Authcrypt\Crypto\Cipher\SodiumAeadCipher;
use Authcrypt\Crypto\Hkdf\HkdfExtended;

$staticSalt = hex2bin(getenv('APP_STATIC_SALT')); // must be exactly 32 bytes for SHA‑256
$kdf = new HkdfExtended(
    hashStaticSalt: $staticSalt,
    saltSize: 0, // disabled – rely on unique context
);
$cipher = new SodiumAeadCipher('AES-256-GCM');

$secret = hex2bin(getenv('MASTER_ENCRYPTION_KEY'));
$cryptor = new KdfCryptor(
    secret: $secret,
    kdf: $kdf,
    cipher: $cipher,
);

$userId = 12345;
$context = "user_data_{$userId}";

$encrypted = $cryptor->encrypt('sensitive user data', $context);
$decrypted = $cryptor->decrypt($encrypted, $context);
```

### Static context encryption

[](#static-context-encryption)

Use this when data does not have a natural unique identifier. The dynamic salt provides per‑message randomness.

```
use Authcrypt\Crypto\KdfCryptor;
use Authcrypt\Crypto\Cipher\SodiumAeadCipher;
use Authcrypt\Crypto\Hkdf\HkdfExtended;

$staticSalt = hex2bin(getenv('APP_STATIC_SALT')); // must be exactly 32 bytes for SHA‑256
$kdf = new HkdfExtended(
    hashStaticSalt: $staticSalt,
    saltSize: 32, // dynamic salt enabled (default)
);
$cipher = new SodiumAeadCipher('AES-256-GCM');

$secret = hex2bin(getenv('MASTER_ENCRYPTION_KEY'));
$cryptor = new KdfCryptor(
    secret: $secret,
    kdf: $kdf,
    cipher: $cipher,
);

$context = 'app_config_v1';

$encrypted = $cryptor->encrypt('sensitive configuration', $context);
$decrypted = $cryptor->decrypt($encrypted, $context);
```

### Envelope encryption for long‑term storage

[](#envelope-encryption-for-longterm-storage)

Use `EnvelopeCryptor` when you may need to rotate the master key without re‑encrypting all data. The `DEK` is independent of the master key – only the wrapped `DEK` needs to be re‑encrypted.

```
use Authcrypt\Crypto\EnvelopeCryptor;
use Authcrypt\Crypto\Cipher\OpenSSLAeadCipher;
use Authcrypt\Crypto\Cipher\OpenSSLWrapCipher;
use Authcrypt\Crypto\Hkdf\HkdfExtended;

$dataCipher = new OpenSSLAeadCipher('AES-256-GCM');
$wrapCipher = new OpenSSLWrapCipher('AES-256-WRAP');

$cryptor = new EnvelopeCryptor(
    secret: $secret,
    kdf: $kdf,
    cipher: $dataCipher,
    kwCipher: $wrapCipher, // if omitted, $dataCipher is used for wrapping
);

$encrypted = $cryptor->encrypt('archive data', $context);
$decrypted = $cryptor->decrypt($encrypted, $context);
```

### Algorithm Migration with VersionedCryptor

[](#algorithm-migration-with-versionedcryptor)

Gradually upgrade encryption algorithms while keeping old ciphertexts readable.

```
use Authcrypt\Crypto\KdfCryptor;
use Authcrypt\Crypto\VersionedCryptor;

$oldCryptor = new KdfCryptor($secret, $oldKdf, $oldCipher);
$newCryptor = new KdfCryptor($secret, $newKdf, $newCipher);

$versioned = new VersionedCryptor(
    cryptors: [
        'v1' => $oldCryptor,
        'v2' => $newCryptor,
    ],
    currentVersion: 'v2', // new encryptions use v2
);

// Decryption automatically detects the version from the prefix
$decrypted = $versioned->decrypt($oldCiphertext, $context);
```

Documentation
-------------

[](#documentation)

- [Internals](docs/internals.md)

License
-------

[](#license)

MIT

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance91

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

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

Unknown

Total

1

Last Release

44d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/286312399?v=4)[authcrypt](/maintainers/authcrypt)[@authcrypt](https://github.com/authcrypt)

---

Top Contributors

[![olegbaturin](https://avatars.githubusercontent.com/u/15981018?v=4)](https://github.com/olegbaturin "olegbaturin (1 commits)")

---

Tags

encryptionaeaddecryptionhkdfenvelope-encryption

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/authcrypt-crypto-php/health.svg)

```
[![Health](https://phpackages.com/badges/authcrypt-crypto-php/health.svg)](https://phpackages.com/packages/authcrypt-crypto-php)
```

###  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

951.1M2](/packages/nzo-url-encryptor-bundle)[camcima/dukpt-php

DUKPT implementation in PHP

25154.3k](/packages/camcima-dukpt-php)[legierski/aes

OpenSSL-compatible AES library

1142.4k1](/packages/legierski-aes)[mukto90/ncrypt

A simple PHP class to encrypt a string and decrypt an encrypted string

1614.4k](/packages/mukto90-ncrypt)[al-saloul/encryption

Simple number encryption and decryption package

181.5k](/packages/al-saloul-encryption)

PHPackages © 2026

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