142 lines
4.7 KiB
Rust
142 lines
4.7 KiB
Rust
use std::env;
|
|
|
|
use clap::{Parser, Subcommand};
|
|
use ed25519_dalek::{Signature, SigningKey};
|
|
use sqlx::sqlite::SqlitePool;
|
|
|
|
use cll2v0::{db, keys};
|
|
|
|
/// 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<Command>,
|
|
}
|
|
|
|
#[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 keys_path = env::var("CLL2V0_KEYS").expect("Expect `CLL2V0_KEYS` to be set");
|
|
let keychain = keys::mk_keychain(&keys_path);
|
|
|
|
let db_url = env::var("DATABASE_URL").expect("Expect `DATABASE_URL` to be set");
|
|
let pool = SqlitePool::connect(&db_url).await?;
|
|
for vkey_bytes in keychain.keys() {
|
|
let vkey = keys::from_bytes(vkey_bytes.into())?;
|
|
let _ = db::add_persistent_key(&pool, &vkey).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)))
|
|
}
|
|
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(())
|
|
}
|