dwgebler / encryption
Encryption wrapper for PHP using libsodium — simple API for symmetric and asymmetric encryption, password hashing, digital signing, and message authentication.
Requires
- php: ^8.2
- ext-sodium: *
Requires (Dev)
- phpstan/phpstan: ^1.11
- phpunit/phpunit: ^11.0
- psalm/plugin-phpunit: ^0.19
- squizlabs/php_codesniffer: ^3.10
- vimeo/psalm: ^6.0
This package is auto-updated.
Last update: 2026-05-28 17:45:52 UTC
README
A small PHP wrapper around libsodium, providing focused classes for password hashing, symmetric encryption, asymmetric encryption, digital signing, and message authentication.
Upgrading from 1.x? See UPGRADE-2.0.md — 2.0 is a
clean break that fixes several security issues, including a critical issue
with 1.x hashPassword(). Read the security advisory at the top of
UPGRADE-2.0.md if you stored 1.x password hashes.
Requirements
- PHP 8.2 or higher
ext-sodium(bundled with PHP since 7.2)
Installation
composer require dwgebler/encryption
Quick start
use Gebler\Encryption\Encryption; $crypt = new Encryption();
The Encryption object is a facade — call accessors to reach each
primitive:
$crypt->passwords(); // PasswordHasher $crypt->symmetric(); // SymmetricCrypto $crypt->asymmetric(); // AsymmetricCrypto $crypt->signing(); // Signing $crypt->mac(); // Mac
Keys at the API boundary are raw bytes. Use the Encoding helper to
convert between raw bytes and hex / base64 when persisting or transmitting
keys.
Password hashing (for storing user passwords)
$pw = $crypt->passwords(); $hash = $pw->hash('correct horse battery staple'); // Store $hash in your database. if ($pw->verify($userInput, $hash)) { // login succeeded if ($pw->needsRehash($hash)) { $hash = $pw->hash($userInput); // update stored hash } }
Uses Argon2id with OPSLIMIT_MODERATE / MEMLIMIT_MODERATE by default.
Configure stronger or weaker parameters via the constructor:
use Gebler\Encryption\PasswordHasher; $pw = new PasswordHasher( PasswordHasher::OPSLIMIT_SENSITIVE, PasswordHasher::MEMLIMIT_SENSITIVE, );
Symmetric encryption
With a password (Argon2id-derived key)
$sym = $crypt->symmetric(); $ciphertext = $sym->encryptWithPassword('secret message', 'a strong password'); $plaintext = $sym->decryptWithPassword($ciphertext, 'a strong password');
With a 32-byte key
use Gebler\Encryption\Encoding; $sym = $crypt->symmetric(); $key = $sym->generateKey(); // 32 raw bytes $keyHex = Encoding::toHex($key); // store this // later: $key = Encoding::fromHex($keyHex); $ciphertext = $sym->encryptWithKey('secret', $key); $plaintext = $sym->decryptWithKey($ciphertext, $key);
Wrong-length keys throw InvalidKeyException. There is no silent stretching.
Asymmetric encryption
$asym = $crypt->asymmetric(); $alice = $asym->generateKeypair(); $bob = $asym->generateKeypair();
Authenticated (Alice → Bob, both identified)
$ciphertext = $asym->encryptAuthenticated( 'Hi Bob, it is Alice.', $bob->publicKey, $alice->privateKey, ); $plaintext = $asym->decryptAuthenticated( $ciphertext, $bob->privateKey, $alice->publicKey, );
Anonymous (sender hidden)
$ciphertext = $asym->encryptAnonymous('Anonymous tip.', $bob->publicKey); $plaintext = $asym->decryptAnonymous($ciphertext, $bob);
Digital signatures (Ed25519)
$signing = $crypt->signing(); $alice = $signing->generateKeypair();
Attached signature
$signed = $signing->signAttached('a public statement', $alice->privateKey); $original = $signing->openAttached($signed, $alice->publicKey);
Detached signature
$signature = $signing->signDetached('a public statement', $alice->privateKey); $valid = $signing->verifyDetached($signature, 'a public statement', $alice->publicKey);
Message authentication (shared secret)
$mac = $crypt->mac(); $key = $mac->generateKey(); $tag = $mac->sign('a message', $key); $ok = $mac->verify($tag, 'a message', $key); // true
Exceptions
The library uses two distinct exception trees:
Gebler\Encryption\Exception\EncryptionException (extends RuntimeException)
— runtime crypto failures. Catch this base type to handle any cipher /
signature failure at once.
| Subclass | Thrown when |
|---|---|
DecryptionFailedException |
Wrong key, wrong password, tampered ciphertext, signature verification failure |
SodiumOperationException |
Underlying sodium primitive raised SodiumException |
\InvalidArgumentException — input-shape errors (programmer mistakes
detectable at the call site, separate from crypto failures):
| Exception | Thrown when |
|---|---|
Gebler\Encryption\Exception\InvalidKeyException |
Key or signature has wrong length |
\InvalidArgumentException (directly) |
Plaintext / message is empty |
To handle everything, catch both EncryptionException and
\InvalidArgumentException.
License
MIT.