diff --git a/Cargo.toml b/Cargo.toml index 37bd916..36d15e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,5 +36,5 @@ thiserror = "1.0" anyhow = "1.0" itertools = "0.13.0" -russh-keys = "0.44.0" +ssh-key = {version = "0.6.6", features = ["ed25519", "encryption"]} ed25519-dalek = "2.1.1" \ No newline at end of file diff --git a/src/key_gen.rs b/src/key_gen.rs index 9ec550d..e294db7 100644 --- a/src/key_gen.rs +++ b/src/key_gen.rs @@ -1,4 +1,3 @@ -use russh_keys::PublicKeyBase64; use sha2::Digest; use zeroize::Zeroizing; @@ -149,7 +148,7 @@ pub mod cli { print!("Encrypt keypair with passphrase? [Y/n]: "); let encrypt = read_line()? != "n"; if encrypt { - print!("Will encrypt keypair."); + println!("Will encrypt keypair."); } print!("Use hash algorithm (sha256, argon2) [argon2]: "); @@ -182,7 +181,7 @@ pub enum Error { #[error("Argon2 Error: {0}")] Argon2(argon2::Error), #[error(transparent)] - SshKeys(#[from] russh_keys::Error), + SshKeys(#[from] ssh_key::Error), } impl From for Error { @@ -195,13 +194,18 @@ pub type Result = core::result::Result; pub struct KeyPair { pub passphrase: Option>, - pub private_key: ed25519_dalek::SigningKey, - pub public_key: ed25519_dalek::VerifyingKey, + pub inner: ssh_key::private::Ed25519Keypair, } impl KeyPair { + fn public_key(&self) -> &[u8; 32] { + &self.inner.public.0 + } + fn private_key(&self) -> [u8; 32] { + self.inner.private.to_bytes() + } pub fn fingerprint(&self) -> Vec { - sha2::Sha256::digest(self.public_key.as_bytes()).to_vec() + sha2::Sha256::digest(self.public_key()).to_vec() } pub fn fingerprint_base64(&self) -> String { @@ -213,27 +217,20 @@ impl KeyPair { } pub fn encode_keys(&self) -> Result<(Zeroizing, String)> { - let keypair = russh_keys::key::KeyPair::Ed25519(self.private_key.clone()); - let public_key = keypair.clone_public_key()?; + let keydata = ssh_key::private::KeypairData::Ed25519(self.inner.clone()); - let mut private_key = Vec::new(); - match &self.passphrase { - Some(passphrase) => { - russh_keys::encode_pkcs8_pem_encrypted( - &keypair, - passphrase.as_bytes(), - 1, - &mut private_key, - )?; - } - None => { - russh_keys::encode_pkcs8_pem(&keypair, &mut private_key)?; - } - } + let keypair = match &self.passphrase { + Some(passphrase) => ssh_key::PrivateKey::new(keydata, "")? + .encrypt(&mut rand::rngs::OsRng, passphrase.as_bytes())?, + None => ssh_key::PrivateKey::new(keydata, "")?, + }; - let private_key = Zeroizing::new(core::str::from_utf8(&private_key).unwrap().to_string()); - let public_key = format!("{} {}", public_key.name(), public_key.public_key_base64()); - Ok((private_key, public_key)) + let public_key = keypair.public_key(); + + Ok(( + keypair.to_openssh(ssh_key::LineEnding::LF)?, + public_key.to_openssh()?, + )) } } @@ -282,10 +279,14 @@ pub fn generate_key(desc: KeygenDesc) -> Result { let private_key = ed25519_dalek::SigningKey::from_bytes(&hash); let public_key = private_key.verifying_key(); + let keypair = ssh_key::private::Ed25519Keypair { + public: ssh_key::public::Ed25519PublicKey(public_key.to_bytes()), + private: ssh_key::private::Ed25519PrivateKey::from_bytes(private_key.as_bytes()), + }; + return Ok(KeyPair { passphrase: desc.encrypt.then_some(desc.passphrase), - private_key, - public_key, + inner: keypair, }); // let keypair = russh_keys::key::KeyPair::Ed25519(private_key); // let public_key = keypair.clone_public_key().expect("pubkey");