X25519 ECDH key store with timed rotation, a 300-second grace window, and HKDF-SHA256 session key derivation — designed as the key exchange layer for the alterion-enc-pipeline.
What it does
Manages a live X25519 key pair that rotates automatically on a configurable interval. A 300-second grace window keeps the previous key valid after rotation so any in-flight request sent just before a rotation still completes successfully.
┌─────────────────────────────────────────────┐
│ KeyStore │
│ current ──→ active X25519 key pair │
│ previous ──→ retiring key (≤300s grace) │
└─────────────────────────────────────────────┘
On each request the client performs X25519 ECDH with the server's current public key. The resulting shared secret is passed to HKDF-SHA256 to derive separate enc_key and mac_key — both parties derive identical keys without ever transmitting them.
Quick start
1. Add the dependency
[]
= "0.1"
2. Initialise and rotate
use ;
async
3. Expose the public key to clients
use ;
use ;
use Arc;
use RwLock;
async
The public_key field is a base64-encoded 32-byte X25519 public key. The client uses it to generate an ephemeral key pair and perform ECDH.
4. Perform ECDH on an incoming request
use ecdh;
// client_pk is the 32-byte ephemeral X25519 public key sent by the client
let = ecdh.await?;
// Pass shared_secret + both public keys to HKDF to derive enc_key and mac_key
shared_secret is Zeroizing<[u8; 32]> — memory is wiped on drop.
API
| Function | Description |
|---|---|
init_key_store(interval_secs) |
Generates the initial X25519 key pair, returns Arc<RwLock<KeyStore>> |
start_rotation(store, interval_secs) |
Spawns a background task that rotates the key every interval_secs seconds |
get_current_public_key(store) |
Returns (key_id, base64_public_key) for the active key |
ecdh(store, key_id, client_pk) |
Performs X25519 ECDH, returns (Zeroizing<[u8; 32]>, [u8; 32]) — shared secret and server public key bytes |
EcdhError
| Variant | Meaning |
|---|---|
KeyExpired |
The key_id is unknown or its grace window has closed |
InvalidPublicKey |
The client's public key is not a valid 32-byte X25519 point |
Grace window
The previous key remains valid for 300 seconds after rotation. Pre-fetch a new public key on the client at rotation_interval − 300 seconds to ensure the cached key is never stale when a rotation occurs.
Contributing
See CONTRIBUTING.md. Open an issue before writing any code.
License
GNU General Public License v3.0 — see LICENSE.
Made with ❤️ by the Alterion Software team