bentools/shh
Shh! is a lightweight PHP library for handling secrets: generate RSA key pairs, change private key passphrases, encrypt/decrypt payloads, and store encrypted secrets safely so only holders of the private key can decrypt.
Installation:
composer require bentools/shh:^1.0
Add to composer.json if using Laravel’s autoloader or ensure vendor/autoload.php is included.
First Use Case: Generate a key pair for encrypting/decrypting secrets:
use BenTools\Shh\Shh;
[$publicKey, $privateKey] = Shh::generateKeyPair();
file_put_contents(storage_path('app/public_key.pem'), $publicKey);
file_put_contents(storage_path('app/private_key.pem'), $privateKey);
Encrypt/Decrypt:
$encrypted = Shh::encrypt('my-secret', $publicKey);
$decrypted = Shh::decrypt($encrypted, $privateKey);
Usage section for core methods (generateKeyPair, encrypt, decrypt).tests/ directory for edge cases and examples.config/shh.php (if using the Symfony bundle) for default settings.Key Management:
storage/app/keys/).$publicKey = file_get_contents(env('PUBLIC_KEY_PATH'));
$privateKey = file_get_contents(env('PRIVATE_KEY_PATH'));
Encrypting Secrets:
$encryptedDbValue = Shh::encrypt($plaintextSecret, $publicKey);
// Store $encryptedDbValue in DB/config.
Decrypting Secrets:
$secret = Shh::decrypt($encryptedValue, $privateKey);
config(['services.api.token' => $secret]);
Passphrase Protection:
[$publicKey, $privateKey] = Shh::generateKeyPair('secure-passphrase');
Laravel Services: Bind the package to the container for dependency injection:
$this->app->singleton('shh', function () {
return new Shh(file_get_contents(storage_path('app/private_key.pem')));
});
Then inject via constructor:
public function __construct(private Shh $shh) {}
Database Encryption:
Use Laravel’s Attribute Casting or Accessors to auto-encrypt/decrypt fields:
use BenTools\Shh\Shh;
protected $casts = [
'encrypted_secret' => function ($value) {
return Shh::decrypt($value, $privateKey);
}
];
Environment Variables:
Encrypt secrets in .env files during deployment:
# Encrypt a value and store in .env
echo "ENCRYPTED_DB_PASSWORD=$(php artisan shh:encrypt 'my-db-password')" >> .env
API Responses: Encrypt PII (Personally Identifiable Information) before sending to clients:
return response()->json(['data' => Shh::encrypt($user->ssn, $publicKey)]);
Key Rotation:
key_version alongside encrypted data to handle rotations gracefully.Private Key Exposure:
.gitignore and environment-specific storage.env() or .env files for key paths, never hardcode them.Passphrase Handling:
Algorithm Limitations:
sha512 with 4096 bits is secure, but custom configurations (e.g., sha256 with 512 bits) may weaken security.Performance:
Invalid Keys:
Shh::decrypt() fails, verify:
\Log::debug('Key starts with:', substr($privateKey, 0, 50));
Environment Issues:
php -m | grep openssl
php artisan config:clear if config changes aren’t reflected.Base64 Encoding:
json_encode() for nested structures before encryption:
$encrypted = Shh::encrypt(json_encode(['key' => 'value']), $publicKey);
Custom Key Storage:
class CloudKeyShh extends Shh {
public function __construct() {
$privateKey = $this->fetchFromS3('private_key.pem');
parent::__construct($privateKey);
}
}
Key Validation:
use BenTools\Shh\Exceptions\InvalidKeyException;
try {
Shh::decrypt($data, $privateKey);
} catch (InvalidKeyException $e) {
// Handle invalid key (e.g., log, retry, or alert).
}
Hybrid Encryption:
$aesKey = Shh::encrypt(openssl_random_pseudo_bytes(32), $publicKey);
$iv = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $aesKey, 0, $iv);
Laravel Artisan Commands:
php artisan shh:generate-keys --passphrase="secure123"
php artisan shh:encrypt "my-secret" --output=.env
Default Algorithm:
The library defaults to sha512 with 4096 bits. Overriding this requires explicit configuration:
Shh::generateKeyPair('passphrase', [
'private_key_bits' => 2048,
'digest_alg' => 'sha256'
]);
Tip: Document custom configurations in your project’s security policy.
Key Pair Generation:
The generateKeyPair() method returns keys in PEM format. Ensure your storage system supports this format.
Tip: Use openssl_pkey_get_details() to inspect key details if needed:
$keyDetails = openssl_pkey_get_details(openssl_pkey_get_private($privateKey));
How can I help you explore Laravel packages today?