CipherStash Docs

Security architecture

Cryptographic primitives, key hierarchy, trust model, and data flow in CipherStash

Security architecture

This page is the single reference for CipherStash's cryptographic design. It covers the key hierarchy, encryption primitives, trust model, and data flow so security teams can evaluate CipherStash without piecing together information from multiple sources.

Cryptographic primitives

PurposeAlgorithmDetails
Data encryptionAES-GCM-SIV256-bit keys, authenticated encryption with nonce-misuse resistance
Equality search tokensHMAC-SHA-256Deterministic tokens for exact-match lookups
Range and sorting indexesBlock OREOrder-Revealing Encryption (Lewi-Wu 2016) with security enhancements from Bogatov et al 2018
Free-text search indexesEncrypted Bloom filtersTrigram-based tokenization (Nojima/Kadobayashi 2009, Chum/Zhang 2017)
Ciphertext integrityBlake3Fast cryptographic hash for CipherCell structure validation
Ciphertext encodingMessagePack + Base85Compact binary serialization stored as JSONB in PostgreSQL

All encryption happens client-side in the application process. CipherStash infrastructure never sees plaintext data.

Key hierarchy

CipherStash uses a distributed trust model with a dual-party key split. No single party — including CipherStash — can derive data encryption keys alone.

Key types

KeyWhere it livesPurpose
Authority keyZeroKMS (server-side, HSM-friendly)Server half of the key derivation input
Client keyYour application / workloadClient half of the key derivation input (CS_CLIENT_KEY env var)
Data keyEphemeral — in-memory onlyPer-value encryption key, derived from both halves, never stored

Key derivation

ZeroKMS uses an HMAC-based key derivation scheme:

  1. The SDK sends a key derivation request to ZeroKMS with the client key component.
  2. ZeroKMS combines the authority key and client key to produce a key seed.
  3. The SDK uses the key seed to derive a unique data encryption key locally.
  4. The data key encrypts the value using AES-GCM-SIV, then is immediately discarded.

Data keys are ephemeral — they are never stored, cached, or transmitted. This eliminates wrapped-key storage overhead and removes the risk of key cache compromise.

Why this matters

Traditional KMSCipherStash ZeroKMS
Wrapped data keys stored alongside dataData keys are ephemeral — never stored
Key caching required for performanceNo caching needed — HMAC derivation at 10,000+ ops/sec per node
Single point of trust (KMS provider)Distributed trust — both authority key and client key required
Compromising KMS exposes all data keysCompromising ZeroKMS alone is insufficient — attacker also needs client key

Trust model

CipherStash implements a zero-knowledge architecture:

  • CipherStash never sees plaintext data. All encryption and decryption happens in your application using the native Rust FFI module.
  • CipherStash never sees unwrapped data keys. Data keys are derived ephemerally and exist only in the client's memory.
  • Both parties are required. An attacker must compromise both the ZeroKMS authority key and the client key to derive data keys.

Shared responsibility

Your responsibilityCipherStash responsibility
Protect the client key (CS_CLIENT_KEY)Protect authority keys in ZeroKMS (HSM-backed)
Secure your application and databaseOperate ZeroKMS infrastructure with high availability
Manage access keys and keysetsEnforce access control policies on keysets
Configure identity providers for lock contextsOperate the CipherStash Token Service (CTS)
Store encrypted data in your databaseNever store, access, or log plaintext data

Blast radius

CipherStash uses keysets to scope encryption keys:

  • Each keyset provides full cryptographic isolation. Tenant A's keyset cannot decrypt Tenant B's data.
  • Compromising a single client key affects only the keysets that client has access to.
  • Revoking a client's access key immediately prevents further key derivation requests.

Data flow

Encryption (write path)

  1. Application calls client.encrypt(plaintext, { column, table }).
  2. SDK sends a key derivation request to ZeroKMS (over TLS).
  3. ZeroKMS combines authority key + client key → returns key seed.
  4. SDK derives a unique data key from the seed locally.
  5. SDK encrypts the plaintext using AES-GCM-SIV with the data key.
  6. SDK generates search index tokens (HMAC, ORE, Bloom filter) if the column has indexes configured.
  7. SDK packages ciphertext + index tokens into a CipherCell (JSON payload).
  8. Data key is discarded from memory.
  9. Application stores the CipherCell in PostgreSQL (as eql_v2_encrypted or jsonb).

Decryption (read path)

  1. Application reads the CipherCell from PostgreSQL.
  2. Application calls client.decrypt(encryptedData).
  3. SDK sends a key derivation request to ZeroKMS.
  4. ZeroKMS combines authority key + client key → returns key seed.
  5. SDK derives the data key and decrypts the ciphertext.
  6. Data key is discarded from memory.
  7. Plaintext is returned to the application.

Search (query path)

  1. Application calls client.encryptQuery(searchTerm, { column, table, queryType }).
  2. SDK generates search tokens (HMAC for equality, ORE for range, Bloom filter for free-text) using a key derived from ZeroKMS.
  3. Application sends the encrypted tokens to PostgreSQL.
  4. PostgreSQL's EQL extension compares encrypted tokens using the appropriate index — the database never sees plaintext.

Searchable encryption security properties

Searchable encryption enables queries on encrypted data but involves inherent security tradeoffs. Each index type reveals specific, bounded information to the database server.

Index typeWhat is revealed to the databaseMitigation
HMAC (equality)Whether two encrypted values are identical (frequency information)Per-column unique keys prevent cross-column correlation
ORE (range/sort)Relative ordering of encrypted valuesBlock ORE limits leakage to block-level ordering (Lewi-Wu 2016)
Bloom filter (free-text)Probabilistic token membership with configurable false positive rateParameters k and m control the tradeoff between search accuracy and information leakage

When to use searchable encryption

  • Use it when you need to query encrypted data and the leakage profile is acceptable for your threat model.
  • Don't use it when the mere ordering or frequency of values is sensitive (e.g., exact salary rankings). In those cases, encrypt without indexes and decrypt application-side.

For a deeper analysis of each index type, see Searchable encryption and Supported queries.

Network security

All communication between the SDK and CipherStash services uses TLS 1.2+ over HTTPS:

  • SDK → ZeroKMS: Key derivation requests over HTTPS
  • SDK → CTS: Token exchange requests over HTTPS (for identity-aware encryption)
  • SDK → your database: Your existing database connection (CipherStash does not proxy this)

CipherStash services are deployed across multiple AWS regions. Key material does not leave the region your workspace is configured in.

Open-source components

ComponentRepositoryLicense
EQL (Encrypt Query Language)github.com/cipherstash/encrypt-query-languageOpen source
ORE implementationgithub.com/cipherstash/ore.rsOpen source
CipherStash Proxygithub.com/cipherstash/proxyOpen source

The core cryptographic implementations (ORE, Bloom filter construction) are open source and independently auditable. ZeroKMS is a managed service operated by CipherStash.

Further reading

On this page