Core Concepts
This page explains the foundational concepts you need to understand when working with Qpher. These ideas appear throughout the API, the SDKs, and the documentation.
Tenants
Qpher is a multi-tenant platform. Every organization that signs up gets its own tenant, which serves as the top-level isolation boundary for all data and operations.
- Each tenant has a unique Tenant ID (UUID)
- All PQC keys, API keys, and operations are scoped to a tenant
- Data from one tenant is never accessible to another -- this is enforced at every layer of the stack, from database queries to API routing
- The gateway injects the tenant context into every request automatically based on your API key
You never need to pass a tenant_id in your API calls. It is derived from your
API key and injected by the gateway.
API Keys
API keys authenticate your requests to Qpher. They are the primary credential for all API interactions.
Key Format
Qpher API keys follow the format qph_ followed by a random string:
qph_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
One Key Per Environment
We recommend creating separate API keys for each environment (development, staging, production). This limits blast radius if a key is compromised and makes rotation simpler.
How Keys Are Stored
Qpher never stores your API key in plaintext. When you create a key, we compute a dual HMAC-SHA256 hash:
- Simple hash -- used for fast gateway lookup
- Scoped hash -- includes the tenant ID for verification
This dual-hash design ensures that API key resolution is both fast (sub-millisecond lookup) and secure (tenant-scoped verification prevents cross-tenant collisions).
Your full API key is shown only once at creation time. Store it in a secrets manager or environment variable. If lost, you must rotate to a new key.
Key Versioning
Each API key has a version number that increments on rotation. The version is included in audit logs so you can trace which key was used for any operation.
PQC Keys
PQC keys are the cryptographic key pairs used for quantum-resistant operations. Qpher supports two types:
| Property | Kyber768 | Dilithium3 |
|---|---|---|
| NIST Name | ML-KEM-768 | ML-DSA-65 |
| NIST Standard | FIPS 203 | FIPS 204 |
| Operation | Key Encapsulation (Encrypt/Decrypt) | Digital Signatures (Sign/Verify) |
| Security Level | NIST Level 3 (~AES-192) | NIST Level 3 (~AES-192) |
| Public Key Size | 1,184 bytes | 1,952 bytes |
| Private Key Size | 2,400 bytes | 4,000 bytes |
| Ciphertext Size | 1,088 bytes | 3,293 bytes |
| Shared Secret Size | 32 bytes | N/A |
| Latency Target | < 15ms (p95) | < 30ms (p95) |
Kyber768 Keys (KEM)
Used for key encapsulation -- the mechanism that enables quantum-safe encryption. A Kyber768 key pair consists of:
- A public key (1,184 bytes) -- used during encryption to encapsulate a shared secret
- A private key (2,400 bytes) -- used during decryption to recover the shared secret
Dilithium3 Keys (Signatures)
Used for digital signatures -- creating and verifying quantum-resistant signatures. A Dilithium3 key pair consists of:
- A public key (1,952 bytes) -- used to verify signatures
- A private key (4,000 bytes) -- used to create signatures
Key Versions
Every PQC key in Qpher has an explicit version number. This is one of the most important concepts in the platform.
Why Explicit Versions?
Unlike systems that silently use the "latest" key, Qpher requires you to specify
the key_version on every operation. This design choice prevents:
- Silent key changes -- You always know exactly which key encrypted your data
- Decryption failures -- The version tells Qpher which key to use for decryption
- Audit ambiguity -- Every operation is traceable to a specific key version
Version Rules
| Operation | Allowed Key Statuses |
|---|---|
| Encrypt | active only |
| Decrypt | active or retired |
| Sign | active only |
| Verify | active or retired |
When you encrypt data or sign a message, store the key_version from the response
alongside the ciphertext or signature. You will need it for decryption or verification.
Key Lifecycle
PQC keys move through three states during their lifetime:
Active
A newly generated key starts in the active state. Active keys can perform all operations: encrypt, decrypt, sign, and verify. Each tenant can have one active key per algorithm at a time.
Retired
When you rotate a key, the previously active key moves to retired status. Retired keys can still decrypt and verify (backward compatibility), but they cannot encrypt or sign new data. This ensures you can always access data encrypted with older keys.
Archived
When a retired key is no longer needed for any decryption or verification, you can archive it. Archived keys cannot perform any operations. This is a terminal state intended for compliance and record-keeping.
Rotation Flow
Hybrid KEM-DEM Encryption
Qpher does not use Kyber768 alone for encryption. Instead, it implements a hybrid KEM-DEM (Key Encapsulation Mechanism -- Data Encapsulation Mechanism) scheme that combines post-quantum key exchange with proven symmetric encryption.
How It Works
- KEM (Kyber768) -- The Kyber768 public key encapsulates a 32-byte shared secret. This step is quantum-resistant.
- KDF (HKDF-SHA256) -- The shared secret is fed through HKDF-SHA256 to derive a 256-bit AES key. This adds cryptographic domain separation.
- DEM (AES-256-GCM) -- The derived key encrypts your plaintext using AES-256-GCM, which provides both confidentiality and integrity (authenticated encryption).
Ciphertext Structure
The ciphertext returned by the /kem/encrypt endpoint is a single base64-encoded
blob containing all four components:
You do not need to parse or manage these components. Pass the entire ciphertext
value to the /kem/decrypt endpoint along with the correct key_version, and Qpher
handles the rest.
The shared secret produced by KEM encapsulation is used only to derive the AES key. It is never stored, logged, or returned in any API response. A fresh shared secret is generated for every encrypt operation.
Why Hybrid?
- Kyber768 provides quantum resistance -- protecting the key exchange against quantum attacks
- AES-256-GCM provides efficient authenticated encryption for arbitrary-length data -- Kyber768 alone can only encapsulate a fixed 32-byte secret
- HKDF-SHA256 provides proper key derivation with domain separation -- preventing key reuse across different contexts
This combination gives you the best of both worlds: quantum-safe key exchange and battle-tested symmetric encryption.
Non-Exportable Private Keys
Qpher follows a strict non-exportable key policy. This is a fundamental security guarantee of the platform.
What This Means
- Private keys are generated inside the KMS Orchestrator and never leave it
- No API endpoint exists to retrieve, download, or export private key material
- The database stores only a
private_key_handle(a reference to the encrypted key file), never the key bytes themselves - Private keys are encrypted at rest using AES-256-GCM with a Key Encryption Key (KEK)
Why It Matters
If private keys could be exported, any breach of your application could compromise all your encrypted data. By keeping private keys non-exportable:
- A compromised API key cannot extract private key material
- Your data remains protected even if your application is breached
- Key operations (decrypt, sign) require going through Qpher's authenticated API, which enforces rate limits, policy checks, and audit logging
Qpher does not currently support importing externally generated private keys. All key generation happens within the platform to ensure the non-exportable guarantee. If you have specific requirements, contact us about Enterprise plans.
Standard Response Format
All Qpher API responses follow a consistent structure:
{
"data": {
// Operation-specific payload
},
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"timestamp": "2026-01-15T10:30:00Z"
}
data-- Contains the operation result (ciphertext, signature, key details, etc.)request_id-- A unique UUID for tracing and debugging. Include this when contacting support.timestamp-- UTC timestamp of when the response was generated
Next Steps
- Authentication -- Learn how the auth pipeline works and how to secure your API keys
- Quickstart Guide -- Make your first API call in 5 minutes
- Key Management Guide -- Deep dive into generating, rotating, and managing keys
- API Reference -- Full endpoint documentation