use std::{
fs::File,
io::{prelude::Write, BufReader},
};
use alkali::{asymmetric::kx::x25519blake2b as X25519, mem::FullAccess};
use serde::{Deserialize, Serialize};
use crate::protocol::{SetupSecret, SETUP_SECRET_LENGTH};
pub struct DebugKeys {
pub controller_keypair: X25519::Keypair,
pub breakpoint_keypair: X25519::Keypair,
pub setup_secret: SetupSecret,
}
#[derive(Debug, Serialize, Deserialize)]
struct DebugKeysFile {
controller_private: X25519::PrivateKey<FullAccess>,
controller_public: X25519::PublicKey,
breakpoint_private: X25519::PrivateKey<FullAccess>,
breakpoint_public: X25519::PublicKey,
setup_secret: [u8; SETUP_SECRET_LENGTH],
}
fn read_debug_keys(path: &str) -> Option<DebugKeys> {
let fd = File::open(path).ok()?;
let reader = BufReader::new(fd);
let raw: DebugKeysFile = serde_cbor::from_reader(reader).ok()?;
Some(DebugKeys {
controller_keypair: X25519::Keypair {
public_key: raw.controller_public,
private_key: raw.controller_private,
},
breakpoint_keypair: X25519::Keypair {
public_key: raw.breakpoint_public,
private_key: raw.breakpoint_private,
},
setup_secret: SetupSecret::from_bytes(&raw.setup_secret),
})
}
fn create_debug_keys(path: &str) -> Result<DebugKeys, ()> {
let controller_keypair = X25519::Keypair::generate().map_err(|_| ())?;
let breakpoint_keypair = X25519::Keypair::generate().map_err(|_| ())?;
let setup_secret = SetupSecret::new_random();
let for_file = serde_cbor::to_vec(&DebugKeysFile {
controller_private: controller_keypair.private_key.try_clone().map_err(|_| ())?,
controller_public: controller_keypair.public_key,
breakpoint_private: breakpoint_keypair.private_key.try_clone().map_err(|_| ())?,
breakpoint_public: breakpoint_keypair.public_key,
setup_secret: setup_secret.to_owned(),
})
.map_err(|_| ())?;
let mut fd = File::create(path).map_err(|_| ())?;
fd.write_all(&for_file).map_err(|_| ())?;
Ok(DebugKeys {
controller_keypair,
breakpoint_keypair,
setup_secret,
})
}
pub(crate) fn get_debug_keys() -> Option<DebugKeys> {
let path = std::env::var("BM_USE_DEBUG_KEYS").ok()?;
match read_debug_keys(&path) {
Some(keys) => {
eprintln!("[WARNING] Using debug keys from disk.");
Some(keys)
}
None => match create_debug_keys(&path) {
Ok(keys) => {
eprintln!("[WARNING] Using new debug keys (and saving to disk.)");
Some(keys)
}
Err(err) => {
eprintln!("[WARNING] Could not read or create new debug keys: {err:?}");
None
}
},
}
}