A KEK provider wraps and unwraps Data Encryption Keys using a backing key store -- almost always a managed KMS. Sealcraft ships six providers; pick one per environment.
Production providers
| Provider | SEALCRAFT_PROVIDER value |
Backing store |
|---|---|---|
| AWS KMS | aws_kms |
AWS Key Management Service |
| GCP Cloud KMS | gcp_kms |
Google Cloud KMS |
| Azure Key Vault | azure_kv |
Azure Key Vault |
| HashiCorp Vault Transit | vault_transit |
Vault Transit secrets engine |
Non-production providers
| Provider | SEALCRAFT_PROVIDER value |
Use |
|---|---|---|
| Local | local |
Dev / test -- key is a file on disk |
| Null | null |
Unit tests -- in-memory, ephemeral |
Selecting a provider
Set SEALCRAFT_PROVIDER in .env:
SEALCRAFT_PROVIDER=aws_kms
Or in config/sealcraft.php:
'default_provider' => 'aws_kms',
What the provider does
Every provider implements Crumbls\Sealcraft\Contracts\KekProvider:
wrap(string $plaintextDek, EncryptionContext $context): WrappedDekunwrap(WrappedDek $wrapped, EncryptionContext $context): string
Some providers also implement:
SupportsKeyVersioning-- exposes the KEK version that wrapped a given DEK (required for KEK rotation)SupportsNativeAad-- the provider binds the context as AAD at the wrap layer (AWS, GCP); when absent, Sealcraft binds at the cipher layer only
Native AAD vs synthetic AAD
- AWS KMS, GCP Cloud KMS: accept arbitrary AAD on
Encrypt/DecryptAPI calls. Sealcraft passes the canonical serialized context through. - Azure Key Vault, Vault Transit:
wrapKey/unwrapKeydo not accept AAD. Sealcraft defaults to a synthetic strategy -- prepending an HMAC-SHA256 of the canonical context over the DEK and verifying on unwrap. Provides defense-in-depth equivalent to native AAD.
The canonical context is NFC-normalized UTF-8 with byte-sorted keys, escaped separators, and a 4KB size cap, so both strategies produce a stable binding.
Contributors
Thank you to everyone who has contributed to this package. Every pull request, bug report, and idea makes a difference.