Encryption and decryption (threshold ECIES)
TKeeper supports threshold encryption and decryption using an integrated ECIES construction (ElGamal KEM) with a symmetric payload cipher.
Key properties:
- Private key material remains distributed as shares; the full private key is not reconstructed.
- Encryption/decryption are quorum-based operations executed by the keeper cluster.
- Payload encryption uses a standard symmetric AEAD cipher.
Curve support: threshold ECIES is available only for keys on secp256k1.
Supported payload cipher
TKeeper currently supports a single payload cipher:
AES_GCM
The API exposes this as algorithm, but the only accepted value is AES_GCM.
Encrypt
- POST
/v1/keeper/ecies/encrypt - Permission:
tkeeper.key.<logicalId>.encrypt
Request
{
"keyId": "custody-key",
"algorithm": "AES_GCM",
"plaintext64": "base64(plaintext-bytes)"
}
Fields:
| Field | Type | Required | Meaning |
|---|---|---|---|
keyId |
string | yes | Key logicalId. |
algorithm |
enum | no | Payload cipher. Default: AES_GCM. |
plaintext64 |
string | yes | Base64-encoded plaintext bytes. |
Response
{
"ciphertext64": "base64(ciphertext-bytes)",
"generation": 3
}
Fields:
| Field | Meaning |
|---|---|
ciphertext64 |
Base64-encoded ciphertext bytes produced by threshold ECIES. |
generation |
Key generation used for encryption. |
Warning
Persist the returned generation alongside the ciphertext. If the key is rotated/refreshed later, decryption will require the original generation.
Decrypt
- POST
/v1/keeper/ecies/decrypt - Permission:
tkeeper.key.<logicalId>.decrypt
Request
{
"keyId": "custody-key",
"algorithm": "AES_GCM",
"ciphertext64": "base64(ciphertext-bytes)",
"generation": 3
}
Fields:
| Field | Type | Required | Meaning |
|---|---|---|---|
keyId |
string | yes | Key logicalId. |
algorithm |
enum | no | Payload cipher. Default: AES_GCM. |
ciphertext64 |
string | yes | Base64-encoded ciphertext bytes. |
generation |
int | no | Key generation to decrypt with. If omitted, the current generation is used. |
Response
{
"plaintext64": "base64(plaintext-bytes)"
}