Hybrid Encryption with Kyber and AES --- Implementation Overview
Scope: this page explains the generic KEM + AES-GCM hybrid pattern. ANKASecure's wire format is JWE (RFC 7516) — compact for SIMPLE keys, General JSON for composite keys — not the byte layout below, and the private key is unwrapped under the tenant KEK inside the service, never handed to the caller.
📌 1. High‑Level Behavior
This implementation follows a standard hybrid encryption pattern:
-
The Kyber public key is retrieved from a keystore using a
kid(key identifier). -
A fresh, ephemeral AES‑256 key is generated for the current encryption operation.
-
The plaintext is encrypted with AES/GCM using that ephemeral AES key.
-
The AES key is wrapped (encapsulated) with the Kyber public key.
Output layout:
[wrappedKey length (2 bytes)] [wrappedKey (AES key wrapped with Kyber)]
[IV length (1 byte)] [IV (for AES-GCM)]
[ciphertext (AES-GCM encrypted data)]
📌 2. Meaning of wrappedKey
wrappedKey is the ephemeral AES key used to encrypt the data, after being encapsulated with the Kyber public key. It is not the Kyber public key itself.
During decryption, the receiver uses the Kyber private key to unwrap (unwrap) this value and recover the original AES key.
📌 3. Detailed Flow
Encryption Path
-
Retrieve Kyber public key from the keystore via
kid. -
Generate a new AES‑256 key (ephemeral, one per encryption).
-
Encrypt the payload with AES/GCM using that AES key.
-
Wrap the AES key with the Kyber public key.
-
Serialize the result as:
wrappedKeyLen + wrappedKey + ivLen + iv + ciphertext.
Decryption Path
-
Read
wrappedKeyfrom the serialized input. -
Use the Kyber private key to unwrap it and obtain the AES key.
-
Initialize AES/GCM with the recovered AES key and the IV.
-
Decrypt the ciphertext.
📌 4. Why the AES Key Is Never Sent in the Clear
-
The AES key is generated locally and then encapsulated using the Kyber public key.
-
Only the holder of the corresponding Kyber private key can recover (unwrap) that AES key.
-
As a result, the AES key never travels unprotected.
📌 5. Common Source of Confusion
A frequent misunderstanding is believing the AES key must be transmitted or stored explicitly. In this design, it is always transported wrapped with Kyber, ensuring only the intended recipient can retrieve it.
This operation is typically implemented with a call similar to:
📌 6. Reference Decryption Logic (Pseudo-code)
// 1. Retrieve Kyber private key
PrivateKey privateKyberKey = keyManagementService.retrievePrivateKeyForDecryption(kid);
// 2. Extract wrappedKey from the serialized payload
byte[] wrappedKey = readWrappedKeyFromInput(...);
// 3. Unwrap (decapsulate) the AES key
SecretKey aesEphemeral = unwrapSecretKey(privateKyberKey, wrappedKey);
// 4. Decrypt using AES/GCM
Cipher aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
aesCipher.init(Cipher.DECRYPT_MODE, aesEphemeral, ivSpec);
byte[] plaintext = aesCipher.doFinal(ciphertext);
✅ 7. End‑to‑End Summary
| Step | Operation | Description |
|---|---|---|
| 1 | Generate AES‑256 key | Fresh, ephemeral per message |
| 2 | Encrypt with AES/GCM | Data protected symmetrically |
| 3 | Wrap AES key | Encapsulated with Kyber public key |
| 4 | Serialize output | [wrappedKey + IV + ciphertext] (+ lengths) |
| 5 | Unwrap AES key | Kyber private key recovers the AES key |
| 6 | Decrypt payload | AES/GCM with recovered key |
📌 Final Notes
If issues appear during decryption, verify the sequence:
-
Read
**wrappedKey**. -
Unwrap it with the Kyber private key.
-
Decrypt with AES/GCM using the recovered key.
For further clarification (e.g., parsing/serialization helpers, specific code listings, or Markdown flavor adjustments), extend this document or provide the relevant code sections.