173 lines
5.7 KiB
Markdown
173 lines
5.7 KiB
Markdown
# HeroDB AGE usage: Stateless vs Key‑Managed
|
||
|
||
This document explains how to use the AGE cryptography commands exposed by HeroDB over the Redis protocol in two modes:
|
||
- Stateless (ephemeral keys; nothing stored on the server)
|
||
- Key‑managed (server‑persisted, named keys)
|
||
|
||
If you are new to the codebase, the exact tests that exercise these behaviors are:
|
||
- [rust.test_07_age_stateless_suite()](herodb/tests/usage_suite.rs:495)
|
||
- [rust.test_08_age_persistent_named_suite()](herodb/tests/usage_suite.rs:555)
|
||
|
||
Implementation entry points:
|
||
- [herodb/src/age.rs](herodb/src/age.rs)
|
||
- Dispatch from [herodb/src/cmd.rs](herodb/src/cmd.rs)
|
||
|
||
Note: Database-at-rest encryption flags in the test harness are unrelated to AGE commands; those flags control storage-level encryption of DB files. See the harness near [rust.start_test_server()](herodb/tests/usage_suite.rs:10).
|
||
|
||
## Quick start
|
||
|
||
Assuming the server is running on localhost on some PORT:
|
||
|
||
```bash
|
||
# Generate an ephemeral keypair and encrypt/decrypt a message (stateless mode)
|
||
redis-cli -p PORT AGE GENENC
|
||
# → returns an array: [recipient, identity]
|
||
|
||
redis-cli -p PORT AGE ENCRYPT <recipient> "hello world"
|
||
# → returns ciphertext (base64 in a bulk string)
|
||
|
||
redis-cli -p PORT AGE DECRYPT <identity> <ciphertext_b64>
|
||
# → returns "hello world"
|
||
```
|
||
|
||
For key‑managed mode, generate a named key once and reference it by name afterwards:
|
||
|
||
```bash
|
||
redis-cli -p PORT AGE KEYGEN app1
|
||
# → persists encryption keypair under name "app1"
|
||
|
||
redis-cli -p PORT AGE ENCRYPTNAME app1 "hello"
|
||
redis-cli -p PORT AGE DECRYPTNAME app1 <ciphertext_b64>
|
||
```
|
||
|
||
## Stateless AGE (ephemeral)
|
||
|
||
Characteristics
|
||
- No server‑side storage of keys.
|
||
- You pass the actual key material with every call.
|
||
- Not listable via AGE LIST.
|
||
|
||
Commands and examples
|
||
|
||
1) Ephemeral encryption keys
|
||
|
||
```bash
|
||
# Generate an ephemeral encryption keypair
|
||
redis-cli -p PORT AGE GENENC
|
||
# Example output (abridged):
|
||
# 1) "age1qz..." # recipient (public)
|
||
# 2) "AGE-SECRET-KEY-1..." # identity (secret)
|
||
|
||
# Encrypt with the recipient
|
||
redis-cli -p PORT AGE ENCRYPT "age1qz..." "hello world"
|
||
# → returns bulk string payload: base64 ciphertext
|
||
|
||
# Decrypt with the identity (secret)
|
||
redis-cli -p PORT AGE DECRYPT "AGE-SECRET-KEY-1..." "<ciphertext_b64>"
|
||
# → "hello world"
|
||
```
|
||
|
||
2) Ephemeral signing keys
|
||
|
||
```bash
|
||
# Generate an ephemeral signing keypair
|
||
redis-cli -p PORT AGE GENSIGN
|
||
# Example output:
|
||
# 1) "<verify_pub_b64>"
|
||
# 2) "<sign_secret_b64>"
|
||
|
||
# Sign a message with the secret
|
||
redis-cli -p PORT AGE SIGN "<sign_secret_b64>" "msg"
|
||
# → returns "<signature_b64>"
|
||
|
||
# Verify with the public key
|
||
redis-cli -p PORT AGE VERIFY "<verify_pub_b64>" "msg" "<signature_b64>"
|
||
# → 1 (valid) or 0 (invalid)
|
||
```
|
||
|
||
When to use
|
||
- You do not want the server to store private keys.
|
||
- You already manage key material on the client side.
|
||
- You need ad‑hoc operations without persistence.
|
||
|
||
Reference test: [rust.test_07_age_stateless_suite()](herodb/tests/usage_suite.rs:495)
|
||
|
||
## Key‑managed AGE (persistent, named)
|
||
|
||
Characteristics
|
||
- Server generates and persists keypairs under a chosen name.
|
||
- Clients refer to keys by name; raw secrets are not supplied on each call.
|
||
- Keys are discoverable via AGE LIST.
|
||
|
||
Commands and examples
|
||
|
||
1) Named encryption keys
|
||
|
||
```bash
|
||
# Create/persist a named encryption keypair
|
||
redis-cli -p PORT AGE KEYGEN app1
|
||
# → returns [recipient, identity] but also stores them under name "app1"
|
||
|
||
# Encrypt using the stored public key
|
||
redis-cli -p PORT AGE ENCRYPTNAME app1 "hello"
|
||
# → returns bulk string payload: base64 ciphertext
|
||
|
||
# Decrypt using the stored secret
|
||
redis-cli -p PORT AGE DECRYPTNAME app1 "<ciphertext_b64>"
|
||
# → "hello"
|
||
```
|
||
|
||
2) Named signing keys
|
||
|
||
```bash
|
||
# Create/persist a named signing keypair
|
||
redis-cli -p PORT AGE SIGNKEYGEN app1
|
||
# → returns [verify_pub_b64, sign_secret_b64] and stores under name "app1"
|
||
|
||
# Sign using the stored secret
|
||
redis-cli -p PORT AGE SIGNNAME app1 "msg"
|
||
# → returns "<signature_b64>"
|
||
|
||
# Verify using the stored public key
|
||
redis-cli -p PORT AGE VERIFYNAME app1 "msg" "<signature_b64>"
|
||
# → 1 (valid) or 0 (invalid)
|
||
```
|
||
|
||
3) List stored AGE keys
|
||
|
||
```bash
|
||
redis-cli -p PORT AGE LIST
|
||
# Example output includes labels such as "encpub" and your key names (e.g., "app1")
|
||
```
|
||
|
||
When to use
|
||
- You want centralized key storage/rotation and fewer secrets on the client.
|
||
- You need names/labels for workflows and can trust the server with secrets.
|
||
- You want discoverability (AGE LIST) and simpler client commands.
|
||
|
||
Reference test: [rust.test_08_age_persistent_named_suite()](herodb/tests/usage_suite.rs:555)
|
||
|
||
## Choosing a mode
|
||
|
||
- Prefer Stateless when:
|
||
- Minimizing server trust for secret material is the priority.
|
||
- Clients already have a secure mechanism to store/distribute keys.
|
||
- Prefer Key‑managed when:
|
||
- Centralized lifecycle, naming, and discoverability are beneficial.
|
||
- You plan to integrate rotation, ACLs, or auditability on the server side.
|
||
|
||
## Security notes
|
||
|
||
- Treat identities and signing secrets as sensitive; avoid logging them.
|
||
- For key‑managed mode, ensure server storage (and backups) are protected.
|
||
- AGE operations here are application‑level crypto and are distinct from database-at-rest encryption configured in the test harness.
|
||
|
||
## Repository pointers
|
||
|
||
- Stateless examples in tests: [rust.test_07_age_stateless_suite()](herodb/tests/usage_suite.rs:495)
|
||
- Key‑managed examples in tests: [rust.test_08_age_persistent_named_suite()](herodb/tests/usage_suite.rs:555)
|
||
- AGE implementation: [herodb/src/age.rs](herodb/src/age.rs)
|
||
- Command dispatch: [herodb/src/cmd.rs](herodb/src/cmd.rs)
|
||
- Bash demo: [herodb/examples/age_bash_demo.sh](herodb/examples/age_bash_demo.sh)
|
||
- Rust persistent demo: [herodb/examples/age_persist_demo.rs](herodb/examples/age_persist_demo.rs)
|
||
- Additional notes: [herodb/instructions/encrypt.md](herodb/instructions/encrypt.md) |