Skip to main content

Crypto Keys overview

KnoxCall’s Crypto Keys feature is encryption-as-a-service. You create a named key, then encrypt and decrypt data through KnoxCall’s API. Your applications never see the key material — they call /encrypt and /decrypt and get back ciphertext / plaintext. The Vault parallel: this is KnoxCall’s transit engine. Use it for:
  • Encrypting customer-record fields at the application layer (PII, PHI, PCI).
  • Decoupling apps from key storage — change the key, rotate it, destroy it without touching application code.
  • Cryptographic erasure — destroy a key version and every piece of ciphertext under it becomes permanently unreadable. Powerful right-to-be-forgotten primitive.
  • Centralised audit — every encrypt / decrypt call lands in the audit log.

Quick example

The ciphertext format is knoxcall:v<N>:<base64-payload> where N is the key version that produced it. Vault’s vault:v<N>:... prefix is also accepted on input — you can migrate ciphertext stored under Vault’s transit engine without re-encrypting.

Algorithms

Pick a key_type when you create a key. The right choice depends on what you’ll use it for: Cryptographic primitives:
  • AES-256-GCM. Ciphertext payload iv[12] || authTag[16] || ciphertext[n]. Format-prefix knoxcall:v<N>:<base64>.
  • HMAC: SHA-256 (32-byte tag) or SHA-512 (64-byte tag).
  • RSA: PKCS#1 v1.5 padding by default for JWT compatibility (RS256). PSS available via rsa_padding: 'pss' for raw signing, or header_overrides: { alg: 'PS256' } (/ PS384, PS512) for JWT signing.
  • ECDSA: deterministic per RFC 6979.
  • Ed25519: standard EdDSA.
Public key export: asymmetric keys expose GET /v1/crypto/keys/{name}/public-key returning both PEM (SPKI) and JWK. External services verify your signatures using the public key without ever needing the private side.

JWT signing and verification

Use a key directly to sign / verify JWTs:
The alg is derived from the key (hmac-sha256HS256, rsa-2048RS256, ecdsa-p256ES256, ed25519EdDSA). The verifier:
  • rejects alg: 'none' unconditionally,
  • rejects algorithm confusion — an HS256 token won’t verify against an RSA key,
  • binds kid so the version that issued the token is the one used to verify,
  • validates standard claims when you pass expected (issuer, audience, subject, expiry, clock skew).
External verify (the killer test): export the public key, hand it to jsonwebtoken in Node or pyjwt in Python, and verify a token KnoxCall signed. If those libraries accept it, the implementation is end-to-end correct.

Webhook signing helper

For Stripe-format webhook signatures (v1 supports the Stripe t=<unix>,v1=<hex> format; additional formats are planned), use the helper:
This is the same signing logic Webhook Signing uses for outbound subscriptions, exposed as a primitive so you can sign payloads with full control over headers and timing.

Modes

When you create a key, pick a mode: Key material stays on KnoxCall’s control plane. Every encrypt / decrypt is a network call.
  • ✅ Strongest blast-radius story — a self-hosted agent or local app process can never leak the key.
  • ⚠️ Higher latency — every operation is a round-trip to KnoxCall.
  • 👍 Use for: high-value secrets (PCI cardholder data, PHI), audit-driven encryption (every call is logged), keys you might ever want to revoke.

bundled

Key material is shipped to self-hosted agents in their session bundle (encrypted with the session key) so the agent can do encrypt / decrypt locally, without the call leaving the customer’s network.
  • ✅ Low-latency local encrypt / decrypt.
  • ✅ Same trust model as KnoxCall’s secret-injection feature today — in-memory, hour-bounded.
  • ⚠️ A compromised agent process can read the in-memory key for the duration of its session.
  • 👍 Use for: hot-path encryption inside a trusted self-hosted environment where round-trips would be too slow.
The mode is a one-shot decision per key — to switch, create a new key in the other mode and rewrap ciphertext to it.

Operations

Versioning at a glance

  • Encrypt always uses the active version.
  • Decrypt uses the version named in the ciphertext prefix.
  • Retired versions stay around so legacy ciphertext keeps working.
  • Destroyed versions are cryptographic erasure — that ciphertext is permanently unreadable. (You can’t destroy the active version; rotate first.)
deletion_allowed is a per-key safety latch. Set it false on production keys to require explicitly flipping the latch before any version can be destroyed. See Rotation & versioning for the full lifecycle.

How the keys themselves are protected

Each version is stored wrapped with your tenant master key (KCT1 envelope format). When KnoxCall needs to use a version, it unwraps it on the fly into an in-memory cache (5-minute TTL). If you cryptographically erase your tenant master key, every transit key under it becomes permanently unreadable — by construction. There’s no separate “delete all keys” step; the wrapping chain does it.

Audit trail

Every encrypt / decrypt / rotate / destroy lands in the audit log under resource_type='transit' with the key name, version, and caller. You can answer “who decrypted PII record 12345 last Tuesday?” in two log queries.

Plays well with…

  • Routes — store an encrypted secret in a route header by encrypting it with a transit key and decrypting on egress.
  • Databases — encrypt PII in your own DB schema; decrypt only on read.
  • Vaults — every vault gets its own AES-256-GCM Crypto Key. Rotate the vault → rotates the underlying transit key.
  • Webhook Signing (outbound) — sign payloads with hmacSign (HMAC formats) or sign (RSA/ECDSA/Ed25519). webhookSign returns a Stripe-shaped header in one call.
  • Inbound Webhooks — point a subscription at an HMAC key here instead of pre-sharing a secret; rotation flows through the Crypto Keys lifecycle.
  • Ephemeral Proxy{{ encrypted | json: ... }} template references encrypt small JSON blobs with a Crypto Key.

Next steps