TL;DR
Bring Your Own Key (BYOK) for the Marturia Audit tier lets an enterprise keep a 32-byte KEK entirely under its control. Marturia receives only a wrapped form of that KEK and uses HKDF to derive tenant-specific and session-specific Ed25519 signing keys; the KEK itself is never stored or seen by Marturia. The result is that a fully compromised Marturia deployment still cannot produce signatures that verify under the customer’s published public key.

Threat model

A BYOK customer buys a simple guarantee: even if every Marturia server, operator, and database is under attacker control, the attacker cannot mint receipts that appear to come from that tenant.

Because the root KEK never leaves the customer’s hardware token or HSM, the only way an attacker can produce a valid Ed25519 signature for the tenant is to obtain that KEK. All downstream keys are derived with HKDF using tenant-specific labels and per-session nonces; compromise of any derived key therefore yields nothing about the KEK or other tenants.

HKDF derivation tree

Marturia uses a two-level HKDF tree:

Customer KEK (32 bytes, offline)

HKDF(KEK, label='tenant:') → 32-byte tenant key

HKDF(tenant, label='session:') → Ed25519 seed

Ed25519 signature over receipt hash

The public key published to the verifier is derived from the session seed; the verifier never needs the KEK or any private material.

Step-by-step setup

1. Generate the KEK offline

Create a 32-byte secret on a machine or hardware token that never touches the network:

# On an air-gapped workstation or HSM
openssl rand -out kek.bin 32
sha256sum kek.bin   # record the fingerprint

Store kek.bin in your organization’s key-management system (HSM, Vault, or equivalent). This file is the only long-term secret you must protect.

2. Wrap the KEK for transport (future API, current pattern)

At Audit-tier launch the provisioning endpoint will accept an RSA-OAEP-wrapped KEK or an HPKE ciphertext. Until that endpoint exists, Marturia supplies a short-lived transport key via the session-bound pattern documented in the closed-beta SDK. The same wrapping code will work unchanged once the production endpoint is available:

# Pseudocode that will be identical at launch
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes

transport_pub = get_marturia_transport_key()   # ephemeral, session-scoped
wrapped = transport_pub.encrypt(
    kek.bin,
    padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                 algorithm=hashes.SHA256(),
                 label=None)
)

3. Bootstrap derivation parameters

POST the wrapped KEK together with a tenant UUID and an HKDF salt:

POST /v1/byok/bootstrap
Content-Type: application/json

{
  "tenant_id": "123e4567-e89b-12d3-a456-426614174000",
  "wrapped_kek": "<base64>",
  "salt": "<32-byte random>"
}

Marturia stores only the wrapped blob and the salt; the plaintext KEK is decrypted inside an enclave, used for a single HKDF expansion, and immediately discarded.

4. Verify the first signed receipt

After bootstrap, request any audit operation. The returned receipt contains the Ed25519 public key and signature. Verify with the public marturia-verify tool:

pip install marturia-verify
marturia-verify receipt.json \
  --tenant 123e4567-e89b-12d3-a456-426614174000

A successful verification proves the receipt was signed under a key ultimately derived from your KEK.

Trade-offs

BYOK removes Marturia from the trust boundary for signature authenticity, but it shifts operational responsibility to you. You must:

Most organizations therefore keep the KEK in an HSM with strict access controls and maintain a sealed escrow copy for disaster recovery.

Compatibility with marturia-verify

The public verifier package never changes. It only requires the Ed25519 public key embedded in each receipt and the tenant’s published root public key. Whether that key was generated from a platform-managed seed or from your own KEK is invisible to the verifier.

Roadmap note

The Audit tier and its BYOK capability are scheduled for Phase 2. During the current closed beta all tenants use platform-managed keys. The steps above are provided now so that security teams can prepare policies, HSM integrations, and runbooks ahead of launch.

Related Marturia resources - /docs/api.html - /learn/lesson_05_how_marturia_signs_a_receipt.html