Interfaces for extending Sealcraft with custom providers or ciphers.
KekProvider
Crumbls\Sealcraft\Contracts\KekProvider
Every KEK provider implements:
public function wrap(string $plaintextDek, EncryptionContext $context): WrappedDek;
public function unwrap(WrappedDek $wrapped, EncryptionContext $context): string;
public function name(): string;
public function capabilities(): ProviderCapabilities;
Capability marker interfaces
A provider opts into optional features by also implementing:
SupportsKeyVersioning-- exposes the KEK version that wrapped a given DEK. Required forsealcraft:rotate-kek.SupportsNativeAad-- the provider binds the context as AAD at the wrap layer. When absent, Sealcraft applies cipher-layer AAD only (or synthetic AAD on a case-by-case basis for Azure Key Vault).
Cipher
Crumbls\Sealcraft\Contracts\Cipher
public function encrypt(string $plaintext, string $key, string $aad): string;
public function decrypt(string $ciphertext, string $key, string $aad): string;
public function name(): string;
The returned ciphertext includes a self-describing header so CipherRegistry can route decryption to the right implementation even after the default cipher changes.
GeneratesDataKeys
Crumbls\Sealcraft\Contracts\GeneratesDataKeys
An optional interface for providers that can natively generate a DEK-KEK pair in a single API call (e.g. AWS KMS GenerateDataKey). If not implemented, Sealcraft generates the DEK locally with random_bytes(32) and wraps it via wrap().
DekResolver
Crumbls\Sealcraft\Contracts\DekResolver
Internal -- resolves a DEK for a context (cache-aware). Applications do not implement this; they use KeyManager instead.
Registering a custom provider
use Crumbls\Sealcraft\Services\ProviderRegistry;
app(ProviderRegistry::class)->extend('my_custom_kms', function ($app, array $config) {
return new MyCustomKmsProvider($config);
});
Then set SEALCRAFT_PROVIDER=my_custom_kms.
Registering a custom cipher
use Crumbls\Sealcraft\Services\CipherRegistry;
app(CipherRegistry::class)->extend('my-cipher', fn () => new MyCipher);
Ciphertext tagged with my-cipher decrypts through MyCipher forever, even if the default changes.
Contributors
Thank you to everyone who has contributed to this package. Every pull request, bug report, and idea makes a difference.