duralumin/src/bin/duralumin-keygen.rs
2021-11-17 14:19:05 +01:00

108 lines
2.6 KiB
Rust

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 <noonebtw@nirgendwo.xyz>"
)]
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(())
}