kc: ciphertext format & cryptographic spec
We publish the exact construction of thekc: ciphertext — algorithms, parameters, and key hierarchy — so that a security reviewer can evaluate it without a sales call. Specificity is the point: you should be able to verify what we built, not take our word for it.
Wire format
Akc: value is a single ASCII string. Each variable segment is base64url (no padding):
The leading
kc: and trailing :$ make detection cheap and unambiguous (POST /v1/decrypt passes non-kc: values through untouched on this basis).
Cryptographic construction (version 1)
Per-value ECIES on the NIST P-256 curve:- Generate an ephemeral P-256 keypair for this value.
-
Compute the ECDH shared secret
Zbetween the ephemeral private key and the recipient (tenant app) public key. -
Derive the content-encryption key:
-
Encrypt with AES-256-GCM (12-byte random IV, 16-byte tag). The
kc:header (version, datatype, key_ref, eph_pubkey, iv) is bound as the GCM additional authenticated data, so no header segment can be swapped without failing the tag.
Context binding (the AAD / HKDF info)
The HKDF info is a length-prefixed, canonical concatenation of a domain-separation label and the full context:
purpose is the optional data-role (pci, eu, …). Because the full context is folded into key derivation, a ciphertext is cryptographically pinned to the tenant, key, version, datatype, and data-role it was created under — decrypting under any different context simply fails the GCM tag.
How this differs from raw-ECDH designs. Some implementations feed the raw ECDH shared secret straight into AES with no KDF. KnoxCall always runs HKDF-SHA256 and binds the context into the
info parameter. This gives domain separation, defends against cross-context reuse, and means a stolen ciphertext cannot be replayed under a different tenant, key, or role.Key hierarchy & custody
- The app private key is never stored in the clear — only as a
KCT1envelope wrapped under the tenant master key. The public half is cached for encryption. - Under BYOK, the tenant master key is wrapped by your cloud KMS, so KnoxCall cannot unwrap it without a call your KMS policy authorises — and you can revoke that at any time.
- Cryptographic erasure: destroy a key version and every
kc:value produced under it becomes permanently unreadable.
Versioning & rotation
Everykc: value names its key_version in the key_ref. Rotating an ecdh-p256 key mints a new version: new values encrypt under the new version while existing values still decrypt under theirs. No bulk re-encryption is required, and a long-running re-encrypt can pin a target version to stay consistent across a concurrent rotation.
Parameter summary
Migrating from Evervault ev:
KnoxCall cannot decrypt an Evervault ev: ciphertext (only your Evervault app holds that key). Migration is a one-way re-encryption you run with scripts/migrate-ev-to-kc.ts: decrypt each ev: value via your Evervault app, then re-encrypt via POST /v1/encrypt to get a kc: value.