use std::io::Write; use clap::Parser; use libduralumin::ed25519::{generate_ed25519_keypair, randomart}; use osshkeys::{error::OsshResult, Key, PublicParts}; /// program that generates ed25519 keypairs seeded by a passphrase and an optional ID. #[derive(Parser)] #[clap( name = "duralumin", version = "0.1.0", author = "No One " )] struct Opts { #[clap(short, long, default_value = "id_ed25519")] file: String, } fn fix_newline_ref(line: &mut String) { if line.ends_with('\n') { line.pop(); if line.ends_with('\r') { line.pop(); } } } fn fix_newline(mut line: String) -> String { fix_newline_ref(&mut line); line } fn main() -> OsshResult<()> { let opts = Opts::parse(); println!("Generating ed25519 keypair:"); print!("Enter a passphrase: "); std::io::stdout().flush()?; let passphrase = rpassword::read_password()?; print!("Re-enter the same passphrase: "); std::io::stdout().flush()?; let passphrase2 = rpassword::read_password()?; if passphrase != passphrase2 { println!("passphrases do not match."); Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, "passphrase did not match.", ))?; } print!("Enter an optional ID []: "); std::io::stdout().flush()?; let id = { let mut id = String::new(); std::io::stdin().read_line(&mut id)?; fix_newline_ref(&mut id); if id.is_empty() { None } else { Some(id) } }; let keypair = generate_ed25519_keypair(&passphrase, id.as_ref())?; print!("Encrypt keypair with passphrase? [Y/n]: "); std::io::stdout().flush()?; let encrypt = { let mut line = String::new(); std::io::stdin().read_line(&mut line)?; fix_newline_ref(&mut line); line.to_lowercase() == "y" }; if encrypt { println!("Using passphrase to encrypt key.."); } let fingerprint = keypair.fingerprint(osshkeys::keys::FingerprintHash::SHA256)?; println!( "Your key fingerprint is: Sha256:{}", base64::encode(&fingerprint) ); let randomart = randomart::RandomArt::from_digest(&fingerprint) .render("ED25519 256", "SHA256")?; println!("RandomArt:\n{}", randomart); let private_key = keypair.serialize_openssh( encrypt.then(|| passphrase.as_str()), osshkeys::cipher::Cipher::Aes256_Ctr, )?; std::fs::write(&opts.file, private_key)?; let public_key = keypair.serialize_publickey()?; std::fs::write(opts.file + ".pub", public_key)?; Ok(()) }