From fe5245fc3112b7cbc37c1b8b4b8d99416973da99 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 30 Jul 2024 15:30:01 +0200 Subject: [PATCH] remove unneeded osshkeys dependency --- Cargo.toml | 3 +- src/bin/duralumin-keygen.rs | 160 ------------------------- src/ed25519.rs | 229 ++++++++++++------------------------ src/key_gen.rs | 2 +- src/lib.rs | 4 +- 5 files changed, 82 insertions(+), 316 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index caccc56..1519497 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ path = "src/lib.rs" [features] default = ["passphrase-gen", "password-gen", "ed25519", "clap", "rpassword", "base64"] -ed25519 = ["osshkeys", "sha2"] +ed25519 = ["sha2"] passphrase-gen = [] password-gen = [] @@ -29,7 +29,6 @@ rand_chacha = "0.3" clap = {version = "3.0.0-beta.5", optional = true, features = ["derive"]} base64 = {version = "0.13", optional = true} bytes = {version = "1.1", optional = true} -osshkeys = {git = "https://github.com/noonebtw/rust-osshkeys.git", branch = "master", optional = true} sha2 = {version = "0.9", optional = true} rpassword = {version = "5.0", optional = true} zeroize = {version = "1.5"} diff --git a/src/bin/duralumin-keygen.rs b/src/bin/duralumin-keygen.rs index 99dcb68..d76b713 100644 --- a/src/bin/duralumin-keygen.rs +++ b/src/bin/duralumin-keygen.rs @@ -12,166 +12,6 @@ struct Opts { file: String, } -pub mod keygen { - use std::str::FromStr; - - use osshkeys::{error::OsshResult, keys::ed25519::Ed25519KeyPair, KeyPair}; - use rand::{Rng, SeedableRng}; - use sha2::Digest; - use thiserror::Error; - use zeroize::Zeroizing; - - #[derive(Debug, Error)] - pub enum Error { - #[error("Failed to parse")] - ParseError, - } - - #[derive(Debug, Clone)] - pub enum KeyType { - SSH, - PGP, - } - - impl FromStr for KeyType { - type Err = Error; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "ssh" => Ok(Self::SSH), - "pgp" => Ok(Self::PGP), - _ => Err(Error::ParseError), - } - } - } - - #[derive(Debug, Clone)] - pub enum HashType { - Sha256, - Argon2, - } - - impl FromStr for HashType { - type Err = Error; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "sha256" => Ok(Self::Sha256), - "argon2" | "argon" => Ok(Self::Argon2), - _ => Err(Error::ParseError), - } - } - } - - #[derive(Debug, Clone)] - pub struct SshKeyBuilder { - hash_type: HashType, - iterations: i16, - tag: Zeroizing, - passphrase: Zeroizing, - encrypt_key: bool, - } - - impl Default for SshKeyBuilder { - fn default() -> Self { - Self { - hash_type: HashType::Argon2, - iterations: 4, - tag: Default::default(), - passphrase: Default::default(), - encrypt_key: true, - } - } - } - - impl SshKeyBuilder { - pub fn with_hash_type(mut self, hash_type: HashType) -> Self { - self.hash_type = hash_type; - self - } - - pub fn with_encrypt(mut self, encrypt: bool) -> Self { - self.encrypt_key = encrypt; - self - } - - pub fn with_hash_type_and_iterations(self, hash_type: HashType, iterations: i16) -> Self { - self.with_hash_type(hash_type).with_iterations(iterations) - } - - pub fn with_iterations(mut self, iterations: i16) -> Self { - self.iterations = iterations; - self - } - - pub fn with_maybe_tag(self, tag: Option) -> Self { - match tag { - Some(tag) => self.with_tag(tag), - None => self, - } - } - - pub fn with_tag(mut self, tag: String) -> Self { - self.tag = Zeroizing::new(tag); - self - } - - pub fn with_passphrase>>(mut self, passphrase: Z) -> Self { - self.passphrase = passphrase.into(); - self - } - - pub fn build_keypair(self) -> OsshResult<((Zeroizing, String), KeyPair)> { - let hash_seed = Zeroizing::new( - self.passphrase - .chars() - .chain(self.tag.chars()) - .collect::(), - ); - - let mut seed = [0u8; 32]; - match self.hash_type { - HashType::Sha256 => { - let mut digest = sha2::Sha256::digest(hash_seed.as_bytes()); - - assert!(self.iterations <= 1); - for _ in 0..(self.iterations - 1) { - digest = sha2::Sha256::digest(digest.as_slice()); - } - - seed.copy_from_slice(&digest[..32]); - } - HashType::Argon2 => { - // TODO: make more random salt - let salt = b"thissaltneedsupdating"; - - let argon = argon2::Argon2::new( - argon2::Algorithm::Argon2i, - argon2::Version::V0x13, - argon2::Params::new(65536, self.iterations as u32, 4, Some(32)) - .expect("argon2 params"), - ); - - argon - .hash_password_into(hash_seed.as_bytes(), salt, &mut seed) - .expect("hash passphrase"); - } - }; - - let rng = rand_chacha::ChaChaRng::from_seed(seed).gen::<[u8; 32]>(); - - let keypair = Ed25519KeyPair::from_seed(&rng).map(|key| Into::::into(key))?; - - let private_key = Zeroizing::new(keypair.serialize_openssh( - self.encrypt_key.then(|| self.passphrase.as_str()), - osshkeys::cipher::Cipher::Aes256_Ctr, - )?); - - Ok(((private_key, keypair.serialize_publickey()?), keypair)) - } - } -} - fn main() -> anyhow::Result<()> { let opts = Opts::parse(); println!("Generating ed25519 ssh keypair:"); diff --git a/src/ed25519.rs b/src/ed25519.rs index 56a312f..944b3c4 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1,176 +1,103 @@ -use osshkeys::{error::OsshResult, keys::ed25519::Ed25519KeyPair, KeyPair}; -use sha2::{Digest, Sha256}; +use std::fmt::Write; -pub fn generate_ed25519_keypair( - passphrase: S1, - id: Option, -) -> OsshResult -where - S1: AsRef, - S2: AsRef, -{ - let hash = { - let mut hasher = Sha256::new(); - hasher.update(passphrase.as_ref()); - if let Some(id) = id { - hasher.update(id.as_ref()); - } +const WIDTH: usize = 17; +const HEIGHT: usize = 9; +const TILES: &[char] = &[ + ' ', '.', 'o', '+', '=', '*', 'B', 'O', 'X', '@', '%', '&', '#', '/', '^', +]; - hasher.finalize() - }; - - Ed25519KeyPair::from_seed(&hash).map(|key| Into::::into(key)) +pub struct RandomArt { + tiles: [[i8; WIDTH]; HEIGHT], } -pub mod randomart { - use std::fmt::Write; +impl RandomArt { + pub fn render(&self, title: &str, subtitle: &str) -> Result { + let mut string = String::new(); - const WIDTH: usize = 17; - const HEIGHT: usize = 9; - const TILES: &[char] = &[ - ' ', '.', 'o', '+', '=', '*', 'B', 'O', 'X', '@', '%', '&', '#', '/', - '^', - ]; + string.write_str(&format!("+{:-^17}+\n", format!("[{}]", title)))?; - pub struct RandomArt { - tiles: [[i8; WIDTH]; HEIGHT], - } - - impl RandomArt { - pub fn render( - &self, - title: &str, - subtitle: &str, - ) -> Result { - let mut string = String::new(); - - string - .write_str(&format!("+{:-^17}+\n", format!("[{}]", title)))?; - - for row in self.tiles { - string.write_char('|')?; - for cell in row { - if cell == -1 { - string.write_char('S')?; - } else if cell == -2 { - string.write_char('E')?; - } else { - let cell = (TILES.len() - 1).min(cell as usize); - string.write_char(TILES[cell])?; - } - } - string.write_char('|')?; - string.write_char('\n')?; - } - - string.write_str(&format!( - "+{:-^17}+\n", - format!("[{}]", subtitle) - ))?; - - Ok(string) - } - - pub fn from_digest(digest: &[u8]) -> Self { - let mut tiles = [[0i8; WIDTH]; HEIGHT]; - let mut x = WIDTH / 2; - let mut y = HEIGHT / 2; - - tiles[y][x] = -1; - - for byte in digest.iter() { - for i in 0..4 { - let b = (*byte >> (i * 2)) & 3; - match b { - 0 | 1 => { - if y > 0 { - y -= 1; - } - } - 2 | 3 => { - if y < HEIGHT - 1 { - y += 1; - } - } - _ => {} - } - match b { - 0 | 2 => { - if x > 0 { - x -= 1; - } - } - 1 | 3 => { - if x < WIDTH - 1 { - x += 1; - } - } - _ => {} - } - - if tiles[y][x] >= 0 { - tiles[y][x] += 1; - } + for row in self.tiles { + string.write_char('|')?; + for cell in row { + if cell == -1 { + string.write_char('S')?; + } else if cell == -2 { + string.write_char('E')?; + } else { + let cell = (TILES.len() - 1).min(cell as usize); + string.write_char(TILES[cell])?; } } - - tiles[y][x] = -2; - - Self { tiles } + string.write_char('|')?; + string.write_char('\n')?; } + + string.write_str(&format!("+{:-^17}+\n", format!("[{}]", subtitle)))?; + + Ok(string) } - #[cfg(test)] - mod tests { - use super::*; + pub fn from_digest(digest: &[u8]) -> Self { + let mut tiles = [[0i8; WIDTH]; HEIGHT]; + let mut x = WIDTH / 2; + let mut y = HEIGHT / 2; - const FINGERPRINT: &str = - "L5N7A2PETaGegW5P3qh/Vjd8AW6Mn4B+VB2SHK+eZCY="; + tiles[y][x] = -1; - #[test] - fn render() { - let randomart = - RandomArt::from_digest(&base64::decode(FINGERPRINT).unwrap()) - .render("Title", "Subtitle") - .unwrap(); + for byte in digest.iter() { + for i in 0..4 { + let b = (*byte >> (i * 2)) & 3; + match b { + 0 | 1 => { + if y > 0 { + y -= 1; + } + } + 2 | 3 => { + if y < HEIGHT - 1 { + y += 1; + } + } + _ => {} + } + match b { + 0 | 2 => { + if x > 0 { + x -= 1; + } + } + 1 | 3 => { + if x < WIDTH - 1 { + x += 1; + } + } + _ => {} + } - println!("{}", randomart); + if tiles[y][x] >= 0 { + tiles[y][x] += 1; + } + } } + + tiles[y][x] = -2; + + Self { tiles } } } +#[cfg(test)] mod tests { - #![allow(dead_code)] - #![allow(unused_imports)] - use osshkeys::{ - keys::ed25519::Ed25519KeyPair, KeyPair, PrivateParts, PublicParts, - }; - use sha2::Digest; + use super::*; - use super::randomart::RandomArt; - - const PASSPHRASE: &str = "the spice must flow"; - - const DATA: &str = "I’d just like to interject for a moment. What you’re refering to as Linux, is in fact, GNU/Linux, or as I’ve recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX."; - - const SIGNATURE: &[u8] = &[ - 115, 18, 156, 87, 192, 149, 107, 105, 13, 87, 219, 90, 26, 146, 41, - 114, 20, 143, 253, 206, 216, 236, 222, 66, 252, 136, 38, 216, 184, 127, - 94, 255, 68, 246, 64, 228, 141, 64, 63, 64, 236, 222, 184, 214, 3, 157, - 73, 186, 73, 156, 20, 100, 76, 241, 113, 81, 38, 131, 174, 31, 103, - 181, 220, 11, - ]; + const FINGERPRINT: &str = "L5N7A2PETaGegW5P3qh/Vjd8AW6Mn4B+VB2SHK+eZCY="; #[test] - fn test() { - let mut hasher = sha2::Sha256::new(); - hasher.update(PASSPHRASE); + fn render() { + let randomart = RandomArt::from_digest(&base64::decode(FINGERPRINT).unwrap()) + .render("Title", "Subtitle") + .unwrap(); - let hash = hasher.finalize(); - - let keypair: KeyPair = Ed25519KeyPair::from_seed(&hash).unwrap().into(); - - let asdf = keypair.sign(DATA.as_bytes()).unwrap(); - assert_eq!(keypair.verify(DATA.as_bytes(), SIGNATURE).unwrap(), true); + println!("{}", randomart); } } diff --git a/src/key_gen.rs b/src/key_gen.rs index 9706c4f..0e5e041 100644 --- a/src/key_gen.rs +++ b/src/key_gen.rs @@ -2,7 +2,7 @@ use russh_keys::PublicKeyBase64; use sha2::Digest; use zeroize::Zeroizing; -use crate::ed25519::randomart; +use crate::randomart; pub mod cli { use zeroize::Zeroizing; diff --git a/src/lib.rs b/src/lib.rs index 1175ab2..2ff4547 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,8 @@ pub mod passphrase_gen; #[cfg(feature = "password-gen")] pub mod password_gen; -#[cfg(feature = "ed25519")] -pub mod ed25519; +#[path = "ed25519.rs"] +pub mod randomart; #[cfg(feature = "ed25519")] pub mod key_gen;