initial commit: added very basic symmetric key service api

This commit is contained in:
2026-05-27 22:59:18 -04:00
commit 1925deff91
4 changed files with 148 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/target
Generated
+7
View File
@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "symmetric-key-service"
version = "0.1.0"
+6
View File
@@ -0,0 +1,6 @@
[package]
name = "symmetric-key-service"
version = "0.1.0"
edition = "2024"
[dependencies]
+134
View File
@@ -0,0 +1,134 @@
// Design a Symmetric Key Distribution Service"
//
// You are building a Key Management Entity (KME)
// a service responsible for generating, storing, and distributing pre-shared
// symmetric keys to authenticated clients (e.g. network gateways, endpoints).
// Design and implement a core slice of this system in Rust.
//
// Requirements:
// Clients authenticate and request a key by providing a session_id and peer_id
// The KME returns a fresh 256-bit key, ensuring both sides of a session receive the same key
// Keys are single-use: once consumed, they cannot be re-issued
// The service must handle concurrent requests safely
// Keys not consumed within 60 seconds should expire
//
// Deliverables:
// * A Rust implementation of the core KME logic
// (not necessarily a full HTTP server — a library interface is fine)
// * A brief design doc covering: your data structures, concurrency strategy,
// and how you'd extend this to multiple KME nodes
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
enum KeyEntryState {
Active { retrieved_by: Vec<String> },
Consumed,
}
#[derive(Debug, PartialEq)]
enum KmeError {
KeyConsumed,
KeyExpired,
}
struct KeyEntry {
key: [u8; 32], // 256 bits
creation: Instant,
state: KeyEntryState,
}
#[derive(Debug, PartialEq)]
struct KeyResponse {
pub key_id: String, // stable identifier for this key
pub key: [u8; 32],
}
type SessionId = [u8; 16]; // similar to uuid
type PeerId = u32;
type Peer = (SessionId, PeerId);
struct Auth {
user_count: u32,
session_count: u8,
}
impl Auth {
pub fn login(&mut self) -> Result<(SessionId, PeerId), String>{
self.user_count+=1;
self.session_count+=1;
// give out two session ids in a row to simulate functional auth service
// where two peers who want to communicate will be given the same session id
let session_id = self.session_count/2;
Ok(([session_id;16], self.user_count))
}
}
struct Kme {
keys: Arc<Mutex<HashMap<SessionId,KeyEntry>>>,
}
impl Kme {
fn new() -> Self {
Self { keys: Arc::new(Mutex::new(HashMap::new())) }
}
// todo: service should handle concurrent requests safely
pub fn request_key(&self, peer: Peer) -> Result<KeyResponse, KmeError> {
let (session_id, _peer_id) = peer;
let mut keys = self.keys.lock().unwrap();
// keys should be single use
if let Some(entry) = keys.get_mut(&session_id) {
let diff = Instant::now() - entry.creation;
// keys will timeout
if diff > Duration::from_secs(1) { // 1 second for feasible testing
return Err(KmeError::KeyExpired);
}
if let KeyEntryState::Consumed = entry.state {
// third peer: key already consumed
return Err(KmeError::KeyConsumed);
}
// second peer: return the same key
entry.state = KeyEntryState::Consumed;
// todo: update retrieved_by as well? why needed?
Ok(KeyResponse { key_id: String::new(), key: entry.key })
} else {
// first peer: generate and store a new key
let key = [0u8; 32]; // TODO: generate real key bytes
keys.insert(session_id, KeyEntry {
key,
creation: Instant::now(),
state: KeyEntryState::Active { retrieved_by: vec![] },
});
Ok(KeyResponse { key_id: String::new(), key })
}
}
}
fn main() {
let mut auth = Auth{ user_count: 0, session_count: 1};
let first_peer = auth.login().unwrap(); // assume fine for now
let second_peer = auth.login().unwrap(); // assume fine for now
let kme = Kme::new();
let first_key = kme.request_key((first_peer.0, second_peer.1)).unwrap();
let second_key = kme.request_key((second_peer.0, first_peer.1)).unwrap();
assert_eq!(first_key, second_key);
let dupe_attempt = kme.request_key((second_peer.0, first_peer.1)).unwrap_err();
assert_eq!(dupe_attempt, KmeError::KeyConsumed);
let third_peer = auth.login().unwrap();
// third_peer somehow hijacks second peer's session_id
let third_key = kme.request_key((second_peer.0, third_peer.1)).unwrap_err();
assert_eq!(third_key, KmeError::KeyConsumed);
let forth_peer = auth.login().unwrap();
let _third_key = kme.request_key((third_peer.0, forth_peer.1)).unwrap();
std::thread::sleep(std::time::Duration::from_secs(2));
let forth_key = kme.request_key((forth_peer.0, third_peer.1)).unwrap_err();
assert_eq!(forth_key, KmeError::KeyExpired);
}