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

10PHPCI passing

Since Jun 26Pushed todayCompare

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

READMEChangelogDependenciesVersions (1)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

21

—

LowBetter than 18% of packages

Maintenance65

Regular maintenance activity

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

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://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)")

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

[mews/purifier

Laravel 5/6/7/8/9/10 HtmlPurifier Package

2.0k18.0M137](/packages/mews-purifier)[paragonie/ecc

PHP Elliptic Curve Cryptography library

24772.0k35](/packages/paragonie-ecc)

PHPackages © 2026

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