Encrypt Data with KEM
This guide walks you through encrypting data using Qpher hybrid KEM-DEM encryption, which combines Kyber768 post-quantum key encapsulation with AES-256-GCM symmetric encryption.
Prerequisites
- A Qpher account with an active API key
- At least one active Kyber768 key pair (see Key Management)
- The
key_versionof the active key you want to use
How Qpher KEM Encryption Works
Qpher uses a hybrid KEM-DEM (Key Encapsulation Mechanism - Data Encapsulation Mechanism) scheme:
- KEM step: Kyber768 encapsulates a shared secret using your public key
- KDF step: HKDF-SHA256 derives a 256-bit symmetric key from the shared secret
- DEM step: AES-256-GCM encrypts your plaintext with the derived key
The shared secret is never stored or returned. Your private key never leaves the Qpher secure enclave.
Step 1: Prepare Your Plaintext
Your plaintext must be base64-encoded before sending it to the API.
All plaintext data must be base64-encoded in the request body. The API will reject raw binary or unencoded strings. Maximum plaintext size is 1 MB (1,048,576 bytes) before encoding.
Step 2: Send the Encrypt Request
curl -X POST https://api.qpher.ai/api/v1/kem/encrypt \
-H "Content-Type: application/json" \
-H "x-api-key: qph_your_key_here" \
-d '{
"plaintext": "SGVsbG8sIFdvcmxkIQ==",
"key_version": 1
}'Step 3: Understand the Response
/api/v1/kem/encryptContent-Type: application/json
x-api-key: qph_your_key_here{
"plaintext": "SGVsbG8sIFdvcmxkIQ==",
"key_version": 1
}{
"data": {
"ciphertext": "base64-encoded-ciphertext...",
"key_version": 1,
"algorithm": "Kyber768"
},
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-02-15T10:30:00Z"
}| Field | Description |
|---|---|
ciphertext | Base64-encoded ciphertext containing the KEM ciphertext, IV, AES ciphertext, and auth tag |
key_version | The key version used for encryption — store this alongside the ciphertext |
algorithm | The KEM algorithm used (Kyber768) |
request_id | Unique request identifier for tracing and support |
Always store the key_version alongside the ciphertext. You will need the exact same key_version to decrypt the data later. There is no implicit "latest" key — Qpher requires explicit versioning on every operation.
Error Handling
| HTTP Status | Error Code | Cause | Resolution |
|---|---|---|---|
| 400 | ERR_INVALID_001 | Missing or invalid plaintext or key_version | Ensure plaintext is valid base64 and key_version is a positive integer |
| 400 | ERR_KEM_001 | Plaintext exceeds 1 MB limit | Split data into smaller chunks |
| 401 | ERR_AUTH_001 | Invalid or missing API key | Check your x-api-key header |
| 404 | ERR_KEM_003 | Key version not found | Verify the key_version exists for your tenant |
| 409 | ERR_KEM_004 | Key is not in active status | Only active keys can encrypt — generate or rotate to get a new active key |
| 429 | ERR_RATE_001 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
Related Guides
- Decrypt Data — Decrypt ciphertext produced by this endpoint
- Key Management — Generate and manage your KEM keys
- Key Versioning — Understand why explicit key versions matter
- Deterministic Encryption — Opt-in deterministic mode for special use cases