use clap::{Parser, Subcommand}; use ed25519_dalek::{Signature, SigningKey}; use cll2v0::{ db, keys::{self}, }; /// cll2v0 is a playground for rust libraries. /// This is signing service. #[derive(Parser)] #[command(arg_required_else_help(true), version, about)] struct Args { #[command(subcommand)] cmd: Option, } #[derive(Subcommand)] enum Command { /// Add new ephemeral key to an existing persistent key Add { ephemeral_key: String, persistent_key: String, expires_at: i64, }, /// Revoke an existing ephemeral key Revoke { ephemeral_key: String }, /// Check persistent keys are available and display Check, /// Gen from seed some sensible ephemeral key args to be used with `add` Gen { seed: u8 }, /// Sign a message Sign { signing_key: String, message: String, }, /// Verify a message Verify { verifying_key: String, message: String, signature: String, }, } #[tokio::main(flavor = "current_thread")] async fn main() -> anyhow::Result<()> { let args = Args::parse(); let (_, pool) = db::start_db().await?; match args.cmd { Some(Command::Add { ephemeral_key, persistent_key, expires_at, }) => { println!("Adding new ephemeral key '{ephemeral_key}'"); let e = keys::from_hex(&ephemeral_key).expect("cannot parse key"); let p = keys::from_hex(&persistent_key).expect("cannot parse key"); let res = db::add_ephemeral_key(&pool, &e, &p, expires_at).await?; println!("Added new ekey: {}", res); } Some(Command::Revoke { ephemeral_key }) => { let e = keys::from_hex(&ephemeral_key).expect("cannot parse key"); let res = db::revoke_ephemeral_key(&pool, &e).await?; println!("Revoked key: {}", res); } Some(Command::Check) => { eprintln!("!Check skipped"); let res = db::list_persistent_keys(&pool).await?; println!("Persistent keys:"); res.into_iter() .for_each(|key| println!("{}", keys::to_hex(&key))); let res = db::list_ephemeral_keys(&pool).await?; println!("ephemeral keys:"); res.into_iter() .for_each(|(e, p, t)| println!("{} {} {t}", keys::to_hex(&e), keys::to_hex(&p))) } Some(Command::Gen { seed }) => { let ekey = SigningKey::from_bytes(&[ seed, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); println!("Ephemeral signing key:"); println!("{}", keys::signing_key_to_hex(&ekey)); let res = db::list_persistent_keys(&pool).await?; let idx = (seed as usize) % res.len(); let pkey = res.get(idx); match pkey { None => eprintln!("No persistent keys found"), Some(pkey) => { let now: usize = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_millis() .try_into() .unwrap(); let twenty_mins_from_now = 20usize * 60 * 1000 + now; println!("Args"); println!( "{} {} {}", keys::to_hex(&ekey.verifying_key()), keys::to_hex(pkey), twenty_mins_from_now ) } } } Some(Command::Sign { signing_key, message, }) => { let mut skey = keys::signing_key_from_hex(&signing_key).unwrap(); let msg = hex::decode(message).unwrap(); let sig = keys::sign(&mut skey, msg); println!("{}", hex::encode(sig.to_bytes())) } Some(Command::Verify { verifying_key, message, signature, }) => { let vkey = keys::from_hex(&verifying_key).unwrap(); let msg = hex::decode(message).unwrap(); let sig = Signature::from_bytes( &TryInto::<[u8; 64]>::try_into(hex::decode(signature).unwrap()).unwrap(), ); let res = keys::verify(&vkey, &msg, &sig).unwrap(); println!("{:?}", res); } None => { println!("See help"); } } Ok(()) }