tuzelko/yii2-key-storage

Named cryptographic key storage with format validation for Yii2 framework

Maintainers

Package info

github.com/TuzelKO/yii2-key-storage

Type:yii2-extension

pkg:composer/tuzelko/yii2-key-storage

Statistics

Installs: 20

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-10 03:53 UTC

This package is auto-updated.

Last update: 2026-06-10 03:58:30 UTC


README

Project Status: Active Tests Latest Version PHP Version Total Downloads License

Named cryptographic key storage for the Yii2 framework.

Solves one recurring problem: "give me the raw bytes of key X, taken from env, decoded and validated — and fail loudly at the first use if the key is missing or malformed". Encryption keys, signing keys, HMAC secrets, TOTP seeds — all behind one named registry instead of ad-hoc base64_decode(getenv(...)) calls scattered around the codebase.

Features

  • Named keys — one registry, keys referenced by name
  • Text sourcesbase64 (standard and url-safe alphabets) or hex, typically from env
  • Modular key types — each format is a small class validating the decoded bytes; ship your own by implementing one interface
  • Fail-fast validation — wrong length, bad encoding, missing value → InvalidKeyException with the key name in the message
  • Interface-first — consumers depend on KeyProviderInterface, not on the concrete storage
  • Memoization — decode and validation happen once per key per instance
  • No ext requirements — key-type byte lengths are hardcoded, so describing sodium keys does not require ext-sodium

Requirements

  • PHP >= 8.0
  • yiisoft/yii2 ~2.0

Installation

composer require tuzelko/yii2-key-storage

Quick start

Register the storage in the DI container under the interface, so consumers never know the concrete class:

// config/main.php
use tuzelko\yii\keystorage\KeyProviderInterface;
use tuzelko\yii\keystorage\KeyStorage;
use tuzelko\yii\keystorage\types\SodiumSecretboxKey;

'container' => [
    'singletons' => [
        KeyProviderInterface::class => static fn () => new KeyStorage([
            'keys' => [
                'appCrypto' => [
                    'base64' => getenv('APP_CRYPTO_KEY'),
                    'type'   => SodiumSecretboxKey::class,
                ],
            ],
        ]),
    ],
],
$rawKey = Yii::$container->get(KeyProviderInterface::class)->getRaw('appCrypto');

getRaw() returns raw binary bytes, ready for sodium_* / hash_hmac / openssl_* calls.

Key configuration

Each entry under keys is name => descriptor. A descriptor has exactly one source encoding and a mandatory type:

Field Description
base64 Base64-encoded key value (standard and url-safe alphabets accepted)
hex Hex-encoded key value
type KeyTypeInterface class name or instance — validates the decoded bytes
'keys' => [
    'appCrypto'  => ['base64' => getenv('CRYPTO_KEY'),       'type' => SodiumSecretboxKey::class],
    'requestSigning' => ['hex'    => getenv('SIGNING_KEY_HEX'),  'type' => Ed25519SecretKey::class],
    'legacyAes'      => ['base64' => getenv('LEGACY_KEY'),       'type' => new CustomLengthKey(16)],
],

Bundled key types

Type Valid length For
SodiumSecretboxKey 32 bytes sodium_crypto_secretbox (XSalsa20-Poly1305)
Ed25519PublicKey 32 bytes sodium_crypto_sign verification
Ed25519SecretKey 64 bytes sodium_crypto_sign signing
CustomLengthKey(n) n bytes any fixed-length format not shipped with the package

Custom key types

A key type is any class implementing KeyTypeInterface — one method, full control over what "valid" means:

use tuzelko\yii\keystorage\InvalidKeyException;
use tuzelko\yii\keystorage\types\KeyTypeInterface;

class PemRsaPrivateKey implements KeyTypeInterface
{
    public function validate(string $raw): void
    {
        if (openssl_pkey_get_private($raw) === false) {
            throw new InvalidKeyException('not a valid PEM RSA private key.');
        }
    }
}

For plain length checks extend FixedLengthKey instead and implement only length(): int.

Docker secrets

Keys are always supplied as text via env. If you use Docker secrets, deliver them to env in your entrypoint (the common *_FILE pattern) — the storage intentionally does not read files, so there is exactly one secret-loading mechanism and no binary-vs-text file pitfalls.

Error handling

Every failure throws tuzelko\yii\keystorage\InvalidKeyException (extends RuntimeException) with the key name in the message:

Condition Message
Unknown key name Key "x" is not configured.
Empty / unset env value Key "x": base64 value is empty or not set.
Bad encoding Key "x": invalid base64 string. / invalid hex string.
Missing source Key "x" must specify one of: base64, hex.
Missing / wrong type Key "x" has unknown or missing type; ...
Failed type validation Key "x": wrong length: expected 32 bytes, got 16.

Running tests

make test

Tests run inside Docker (PHP 8.3) with no local setup required.

License

MIT — see LICENSE.