horde / secret
Secret key encryption library with authenticated encryption
v3.0.0alpha7
2026-03-07 00:00 UTC
Requires
- php: ^8.1
- ext-hash: *
- horde/crypt_blowfish: ^2 || dev-FRAMEWORK_6_0
- horde/exception: ^3 || dev-FRAMEWORK_6_0
Suggests
- ext-openssl: *
- ext-sodium: *
- horde/test: ^3 || dev-FRAMEWORK_6_0
This package is auto-updated.
Last update: 2026-03-07 21:56:10 UTC
README
Modern secret encryption library with authenticated encryption support.
Overview
Horde_Secret provides a dual-stack API for encrypting and decrypting small pieces of data:
- PSR-4 Modern API (
Horde\Secret\SecretManager) - Authenticated encryption with Libsodium/AES-GCM - PSR-0 Legacy API (
Horde_Secret) - Backward-compatible Blowfish encryption
Installation
composer require horde/secret
Quick Start
Modern API (Recommended for new projects)
use Horde\Secret\SecretManager; // Automatic cipher selection (prefers Sodium) $secret = SecretManager::create($key); // Encrypt $encrypted = $secret->encrypt('sensitive data'); // Decrypt $decrypted = $secret->decrypt($encrypted);
Legacy API (Backward compatible)
$secret = new Horde_Secret(); // Encrypt $encrypted = $secret->write($key, 'sensitive data'); // Decrypt $decrypted = $secret->read($key, $encrypted);
Features
Modern API (PSR-4)
✅ Authenticated Encryption (AEAD)
- Prevents tampering and forgery attacks
- Automatic integrity verification
✅ Multiple Cipher Support
- Libsodium XSalsa20-Poly1305 (primary, version 0x02)
- AES-256-GCM (fallback, version 0x03)
- Blowfish ECB (legacy compatibility, version 0x01)
✅ Type Safety
- PHP 8.1+ strict types
- Immutable value objects
- Full type declarations
✅ Automatic Legacy Detection
- Decrypts old PSR-0 data seamlessly
- Migration helpers included
Legacy API (PSR-0)
- 100% backward compatible with Horde_Secret 2.x
- No breaking changes
- Drop-in upgrade
- Cookie/session key management
Usage Examples
Cipher Selection
use Horde\Secret\SecretManager; // Automatic selection (recommended) $secret = SecretManager::create($key); // Explicit cipher selection $sodium = SecretManager::withSodium($key); // XSalsa20-Poly1305 $aes = SecretManager::withAesGcm($key); // AES-256-GCM $blowfish = SecretManager::withBlowfish($key); // Legacy only // Check current cipher echo $secret->getCipherName(); // "XSalsa20-Poly1305" echo $secret->getCipherVersion(); // 0x02
Working with Encrypted Data
use Horde\Secret\SecretManager; $secret = SecretManager::create($key); // Encrypt returns an EncryptedData object $encrypted = $secret->encrypt('my secret'); // Get Base64-encoded string for storage $storedValue = $encrypted->toBase64(); // Decrypt from string or object $decrypted = $secret->decrypt($storedValue);
Migration from Legacy Format
use Horde\Secret\SecretManager; $secret = SecretManager::create($key); // Decrypt legacy PSR-0 data (automatic detection) $decrypted = $secret->decrypt($oldCiphertext); // Check if needs re-encryption if ($secret->needsReEncryption($oldCiphertext)) { // Upgrade to modern format $newCiphertext = $secret->encrypt($decrypted); // Update database $db->update('table', [ 'encrypted_field' => $newCiphertext->toString() ], ['id' => $recordId]); }
Lazy Migration Pattern
use Horde\Secret\SecretManager; function getData($key, $ciphertext, $db, $recordId) { $secret = SecretManager::create($key); // Decrypt (works with any format) $data = $secret->decrypt($ciphertext); // Opportunistically upgrade if ($secret->needsReEncryption($ciphertext)) { $newCiphertext = $secret->encrypt($data); $db->update('table', ['field' => $newCiphertext->toString()], ['id' => $recordId]); } return $data; }
Error Handling
use Horde\Secret\SecretManager; use Horde\Secret\Exception\DecryptionException; use Horde\Secret\Exception\InvalidKeyException; use Horde\Secret\Exception\UnsupportedCipherException; try { $secret = SecretManager::create($key); $decrypted = $secret->decrypt($ciphertext); } catch (DecryptionException $e) { // Wrong key or corrupted/tampered data error_log("Decryption failed: " . $e->getMessage()); } catch (InvalidKeyException $e) { // Invalid key provided error_log("Invalid key: " . $e->getMessage()); } catch (UnsupportedCipherException $e) { // Required cipher not available error_log("Cipher not supported: " . $e->getMessage()); }
Checking Cipher Availability
use Horde\Secret\Cipher\SodiumCipher; use Horde\Secret\Cipher\AesGcmCipher; use Horde\Secret\Cipher\BlowfishCipher; if (SodiumCipher::isSupported()) { echo "Sodium available (recommended)\n"; } if (AesGcmCipher::isSupported()) { echo "AES-GCM available\n"; } if (BlowfishCipher::isSupported()) { echo "Blowfish available (legacy)\n"; }
System Requirements
Modern API (PSR-4)
- PHP ^8.1
- One of:
ext-sodium(recommended, bundled with PHP 7.2+)ext-opensslwith AES-GCM support
Legacy API (PSR-0)
- PHP ^8.1
horde/crypt_blowfish^2
Migration Guide
See UPGRADING.md for detailed migration instructions.
Quick Migration Summary
- No immediate action required - PSR-0 API remains fully functional
- For new code - Use PSR-4
SecretManager::create() - When ready - Migrate existing data using lazy or batch migration patterns
- PSR-4 can decrypt PSR-0 data - Seamless compatibility
Security Considerations
PSR-0 (Blowfish ECB)
- ❌ No authentication (vulnerable to tampering)
- ❌ ECB mode (pattern leakage)
- ❌ 56-byte key limit
- ⚠️ Use only for backward compatibility
PSR-4 (Sodium/AES-GCM)
- ✅ Authenticated encryption (AEAD)
- ✅ Modern stream ciphers
- ✅ 256-bit keys
- ✅ Unique nonces per message
- ✅ Constant-time operations (Sodium)
Recommendation: Use PSR-4 for all new and sensitive data.
Data Format
PSR-4 Format
[Magic: 'H']['S'][Version: 1 byte][Payload: variable]
- Magic header:
HS(0x48 0x53) for format identification - Version byte:
0x01- Blowfish ECB (legacy)0x02- Sodium XSalsa20-Poly13050x03- AES-256-GCM
- Payload: Cipher-specific encrypted data
PSR-0 Format (Legacy)
[Payload: variable]
- No header, raw Blowfish ciphertext
- Detected by absence of magic header
Testing
# Run all tests vendor/bin/phpunit # Run PSR-0 tests only vendor/bin/phpunit test/Unit/SecretTest.php # Run PSR-4 tests only vendor/bin/phpunit --testsuite psr4 # Run integration tests vendor/bin/phpunit test/Unit/Psr0Psr4IntegrationTest.php
Contributing
Contributions are welcome! Please:
- Follow PER-1 coding style
- Add tests for new features
- Use Conventional Commits format
- Ensure all tests pass on PHP 8.1+
# Check coding style vendor/bin/phpcs # Run tests vendor/bin/phpunit
Changelog
See doc/changelog.yml for version history.
License
LGPL-2.1-only - see LICENSE for details.
Links
- Homepage: https://www.horde.org/libraries/Horde_Secret
- Documentation: https://www.horde.org/libraries/Horde_Secret
- GitHub: https://github.com/horde/Secret
- Issues: https://github.com/horde/Secret/issues
- Packagist: https://packagist.org/packages/horde/secret
Support
- Mailing List: dev@lists.horde.org
- GitHub Issues: https://github.com/horde/Secret/issues
Credits
- Authors: Chuck Hagenbuch, Michael Slusarz
- Copyright: 1999-2026 Horde LLC
- License: LGPL-2.1-only