4.0 KiB
HeroDB AGE Cryptography
HeroDB provides AGE-based asymmetric encryption and digital signatures over the Redis protocol using X25519 for encryption and Ed25519 for signatures. Keys can be used in stateless (ephemeral) or key-managed (persistent, named) modes.
In key-managed mode, HeroDB uses a unified keypair concept: a single Ed25519 signing key is deterministically derived into X25519 keys for encryption, allowing one keypair to handle both encryption and signatures transparently.
Cryptographic Algorithms
X25519 (Encryption)
- Elliptic-curve Diffie-Hellman key exchange for symmetric key derivation.
- Used for encrypting/decrypting messages.
Ed25519 (Signatures)
- EdDSA digital signatures for message authentication.
- Used for signing/verifying messages.
Key Derivation
Ed25519 signing keys are deterministically converted to X25519 keys for encryption. This enables a single keypair to support both operations without additional keys. Derivation uses the Ed25519 secret scalar clamped for X25519.
In named keypairs, Ed25519 keys are stored, and X25519 keys are derived on-demand and cached.
Stateless Mode (Ephemeral Keys)
No server-side storage; keys are provided with each command.
Available commands:
AGE GENENC
: Generate ephemeral X25519 keypair. Returns[recipient, identity]
.AGE GENSIGN
: Generate ephemeral Ed25519 keypair. Returns[verify_pub, sign_secret]
.AGE ENCRYPT <recipient> <message>
: Encrypt message. Returns base64 ciphertext.AGE DECRYPT <identity> <ciphertext_b64>
: Decrypt ciphertext. Returns plaintext.AGE SIGN <sign_secret> <message>
: Sign message. Returns base64 signature.AGE VERIFY <verify_pub> <message> <signature_b64>
: Verify signature. Returns 1 (valid) or 0 (invalid).
Example:
redis-cli AGE GENENC
# → 1) "age1qz..." # recipient (X25519 public)
# 2) "AGE-SECRET-KEY-1..." # identity (X25519 secret)
redis-cli AGE ENCRYPT "age1qz..." "hello"
# → base64_ciphertext
redis-cli AGE DECRYPT "AGE-SECRET-KEY-1..." base64_ciphertext
# → "hello"
Key-Managed Mode (Persistent Named Keys)
Keys are stored server-side under names. Supports unified keypairs for both encryption and signatures.
Available commands:
AGE KEYGEN <name>
: Generate and store unified keypair. Returns[recipient, identity]
in age format.AGE SIGNKEYGEN <name>
: Generate and store Ed25519 signing keypair. Returns[verify_pub, sign_secret]
.AGE ENCRYPTNAME <name> <message>
: Encrypt with named key. Returns base64 ciphertext.AGE DECRYPTNAME <name> <ciphertext_b64>
: Decrypt with named key. Returns plaintext.AGE SIGNNAME <name> <message>
: Sign with named key. Returns base64 signature.AGE VERIFYNAME <name> <message> <signature_b64>
: Verify with named key. Returns 1 or 0.AGE LIST
: List all stored key names. Returns sorted array of names.
AGE LIST Output
Returns a flat, deduplicated, sorted array of key names (strings). Each name corresponds to a stored keypair, which may include encryption keys (X25519), signing keys (Ed25519), or both.
Output format: ["name1", "name2", ...]
Example:
redis-cli AGE LIST
# → 1) "<named_keypair_1>"
# 2) "<named_keypair_2>"
For unified keypairs (from AGE KEYGEN
), the name handles both encryption (derived X25519) and signatures (stored Ed25519) transparently.
Example with named keys:
redis-cli AGE KEYGEN app1
# → 1) "age1..." # recipient
# 2) "AGE-SECRET-KEY-1..." # identity
redis-cli AGE ENCRYPTNAME app1 "secret message"
# → base64_ciphertext
redis-cli AGE DECRYPTNAME app1 base64_ciphertext
# → "secret message"
redis-cli AGE SIGNNAME app1 "message"
# → base64_signature
redis-cli AGE VERIFYNAME app1 "message" base64_signature
# → 1
Choosing a Mode
- Stateless: For ad-hoc operations without persistence; client manages keys.
- Key-managed: For centralized key lifecycle; server stores keys for convenience and discoverability.
Implementation: herodb/src/age.rs
Tests: herodb/tests/usage_suite.rs