Compare commits
No commits in common. "76ebacacf26d04f544d9ef177598e517bf4210c9" and "6259840c43659c2322ff1da7694d5a558111c5c0" have entirely different histories.
76ebacacf2
...
6259840c43
|
@ -24,9 +24,9 @@ required-features = ["ed25519", "clap", "rpassword", "base64"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.4"
|
rand = "0.8.4"
|
||||||
clap = {version = "3.0.0-beta.5", optional = true, features = ["derive"]}
|
clap = {version = "3.0.0-beta.5", optional = true}
|
||||||
base64 = {version = "0.13.0", optional = true}
|
base64 = {version = "0.13.0", optional = true}
|
||||||
bytes = {version = "1.1.0", optional = true}
|
bytes = {version = "1.1.0", optional = true}
|
||||||
osshkeys = {git = "https://github.com/noonebtw/rust-osshkeys.git", branch = "master", optional = true}
|
osshkeys = {path = "../rust-osshkeys", optional = true}
|
||||||
sha2 = {version = "0.9.8", optional = true}
|
sha2 = {version = "0.9.8", optional = true}
|
||||||
rpassword = {version = "5.0.1", optional = true}
|
rpassword = {version = "5.0.1", optional = true}
|
|
@ -1,9 +1,8 @@
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use libduralumin::ed25519::{generate_ed25519_keypair, randomart};
|
use libduralumin::ed25519::{generate_ed25519_keypair, randomart};
|
||||||
use osshkeys::{error::OsshResult, PublicParts};
|
use osshkeys::{error::OsshResult, Key, PublicParts};
|
||||||
|
|
||||||
/// program that generates ed25519 keypairs seeded by a passphrase and an optional ID.
|
/// program that generates ed25519 keypairs seeded by a passphrase and an optional ID.
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
@ -17,23 +16,6 @@ struct Opts {
|
||||||
file: String,
|
file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_newline_ref(line: &mut String) {
|
|
||||||
if line.ends_with('\n') {
|
|
||||||
line.pop();
|
|
||||||
|
|
||||||
if line.ends_with('\r') {
|
|
||||||
line.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn fix_newline(mut line: String) -> String {
|
|
||||||
fix_newline_ref(&mut line);
|
|
||||||
|
|
||||||
line
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> OsshResult<()> {
|
fn main() -> OsshResult<()> {
|
||||||
let opts = Opts::parse();
|
let opts = Opts::parse();
|
||||||
println!("Generating ed25519 keypair:");
|
println!("Generating ed25519 keypair:");
|
||||||
|
@ -41,24 +23,12 @@ fn main() -> OsshResult<()> {
|
||||||
print!("Enter a passphrase: ");
|
print!("Enter a passphrase: ");
|
||||||
std::io::stdout().flush()?;
|
std::io::stdout().flush()?;
|
||||||
let passphrase = rpassword::read_password()?;
|
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 []: ");
|
print!("Enter an optional ID []: ");
|
||||||
std::io::stdout().flush()?;
|
std::io::stdout().flush()?;
|
||||||
let id = {
|
let id = {
|
||||||
let mut id = String::new();
|
let mut id = String::new();
|
||||||
std::io::stdin().read_line(&mut id)?;
|
std::io::stdin().read_line(&mut id)?;
|
||||||
fix_newline_ref(&mut id);
|
|
||||||
|
|
||||||
if id.is_empty() {
|
if id.is_empty() {
|
||||||
None
|
None
|
||||||
|
@ -75,48 +45,31 @@ fn main() -> OsshResult<()> {
|
||||||
let encrypt = {
|
let encrypt = {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
std::io::stdin().read_line(&mut line)?;
|
std::io::stdin().read_line(&mut line)?;
|
||||||
fix_newline_ref(&mut line);
|
|
||||||
|
|
||||||
line.to_lowercase() != "n"
|
line.to_lowercase() == "y"
|
||||||
};
|
};
|
||||||
|
|
||||||
if encrypt {
|
let fingerprint =
|
||||||
println!("Using passphrase to encrypt key..");
|
keypair.fingerprint(osshkeys::keys::FingerprintHash::SHA256)?;
|
||||||
}
|
|
||||||
|
|
||||||
let fingerprint = keypair.fingerprint(osshkeys::keys::FingerprintHash::SHA256)?;
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Your key fingerprint is: Sha256:{}",
|
"Your key fingerprint is: Sha256:{}",
|
||||||
base64::encode(&fingerprint)
|
base64::encode(&fingerprint)
|
||||||
);
|
);
|
||||||
|
|
||||||
let randomart =
|
let randomart = randomart::RandomArt::from_digest(&fingerprint)
|
||||||
randomart::RandomArt::from_digest(&fingerprint).render("ED25519 256", "SHA256")?;
|
.render("ED25519 256", "SHA256")?;
|
||||||
|
|
||||||
println!("RandomArt:\n{}", randomart);
|
println!("RandomArt:\n{}", randomart);
|
||||||
|
|
||||||
let private_path = opts.file.clone();
|
|
||||||
let public_path = opts.file.clone() + ".pub";
|
|
||||||
|
|
||||||
let private_key = keypair.serialize_openssh(
|
let private_key = keypair.serialize_openssh(
|
||||||
encrypt.then(|| passphrase.as_str()),
|
Some(&passphrase),
|
||||||
osshkeys::cipher::Cipher::Aes256_Ctr,
|
osshkeys::cipher::Cipher::Aes256_Ctr,
|
||||||
)?;
|
)?;
|
||||||
std::fs::write(&private_path, private_key)?;
|
std::fs::write(&opts.file, private_key)?;
|
||||||
|
|
||||||
let public_key = keypair.serialize_publickey()?;
|
let public_key = keypair.serialize_publickey()?;
|
||||||
std::fs::write(&public_path, public_key)?;
|
std::fs::write(opts.file + ".pub", public_key)?;
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
use std::fs::Permissions;
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
std::fs::set_permissions(private_path, Permissions::from_mode(0o0600))?;
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
std::fs::set_permissions(public_path, Permissions::from_mode(0o0600))?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#[macro_use]
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use libduralumin::passphrase_gen::{PassPhraseGenerator, Words};
|
use libduralumin::passphrase_gen::{PassPhraseGenerator, Words};
|
||||||
|
|
||||||
|
@ -70,8 +69,12 @@ fn main() {
|
||||||
.with_length(opts.words_per_passphrase());
|
.with_length(opts.words_per_passphrase());
|
||||||
|
|
||||||
let words = match opts.backend() {
|
let words = match opts.backend() {
|
||||||
Some(Backend::UseAPassPhrase) => Words::from_str(include_str!("../../useapassphrase.txt")),
|
Some(Backend::UseAPassPhrase) => {
|
||||||
Some(Backend::EnglishWords) => Words::from_str(include_str!("../../words_alpha.txt")),
|
Words::from_str(include_str!("../../useapassphrase.txt"))
|
||||||
|
}
|
||||||
|
Some(Backend::EnglishWords) => {
|
||||||
|
Words::from_str(include_str!("../../words_alpha.txt"))
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
panic!("invalid backend.")
|
panic!("invalid backend.")
|
||||||
}
|
}
|
||||||
|
|
110
src/ed25519.rs
110
src/ed25519.rs
|
@ -1,6 +1,113 @@
|
||||||
use osshkeys::{error::OsshResult, keys::ed25519::Ed25519KeyPair, KeyPair};
|
use osshkeys::{error::OsshResult, keys::ed25519::Ed25519KeyPair, KeyPair};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "base64", feature = "bytes"))]
|
||||||
|
mod asdf {
|
||||||
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
|
use bytes::Buf;
|
||||||
|
|
||||||
|
pub struct Ed25519PrivateKey {}
|
||||||
|
|
||||||
|
const OPENSSH_BEGIN: &str = "-----BEGIN OPENSSH PRIVATE KEY-----";
|
||||||
|
const OPENSSH_END: &str = "-----END OPENSSH PRIVATE KEY-----";
|
||||||
|
const OPENSSH_MAGIC: &str = "openssh-key-v1\0";
|
||||||
|
|
||||||
|
impl Ed25519PrivateKey {
|
||||||
|
pub fn parse<S>(text: S) -> Option<()>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let mut lines = text.as_ref().lines();
|
||||||
|
|
||||||
|
let data = (lines.next() == Some(OPENSSH_BEGIN))
|
||||||
|
.then(|| {
|
||||||
|
let base64_content = lines
|
||||||
|
.take_while(|&line| line != OPENSSH_END)
|
||||||
|
.fold(String::new(), |mut acc, line| {
|
||||||
|
acc.push_str(line);
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
|
||||||
|
base64::decode(&base64_content).ok()
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.map(|data| Cursor::new(data))
|
||||||
|
.and_then(|mut data| {
|
||||||
|
let mut magic = vec![0u8; OPENSSH_MAGIC.len()];
|
||||||
|
data.read_exact(&mut magic).unwrap();
|
||||||
|
|
||||||
|
// cypher name
|
||||||
|
let cypher_len = data.get_u32();
|
||||||
|
let mut cypher_name = vec![0u8; cypher_len as usize];
|
||||||
|
data.read_exact(&mut cypher_name).unwrap();
|
||||||
|
|
||||||
|
// kdf name
|
||||||
|
let kdf_name_len = data.get_u32();
|
||||||
|
let mut kdf_name = vec![0u8; kdf_name_len as usize];
|
||||||
|
data.read_exact(&mut kdf_name).unwrap();
|
||||||
|
|
||||||
|
// kdf
|
||||||
|
let kdf_len = data.get_u32();
|
||||||
|
let kdf = (kdf_len > 0).then(|| {
|
||||||
|
let mut kdf = vec![0u8; kdf_len as usize];
|
||||||
|
data.read_exact(&mut kdf).unwrap();
|
||||||
|
kdf
|
||||||
|
});
|
||||||
|
|
||||||
|
// key_count should always be `1`
|
||||||
|
let key_count = data.get_u32();
|
||||||
|
assert_eq!(key_count, 1);
|
||||||
|
|
||||||
|
// ssh public key
|
||||||
|
|
||||||
|
let pubkey_len = data.get_u32() as usize;
|
||||||
|
|
||||||
|
let keytype_len = data.get_u32() as usize;
|
||||||
|
let mut keytype = vec![0u8; keytype_len];
|
||||||
|
data.read_exact(&mut keytype).unwrap();
|
||||||
|
|
||||||
|
let pub1_len = data.get_u32() as usize;
|
||||||
|
let mut pub1 = vec![0u8; pub1_len];
|
||||||
|
data.read_exact(&mut pub1).unwrap();
|
||||||
|
|
||||||
|
let pub2_len = data.get_u32() as usize;
|
||||||
|
let mut pub2 = vec![0u8; pub2_len];
|
||||||
|
data.read_exact(&mut pub2).unwrap();
|
||||||
|
|
||||||
|
println!("magic: {}", String::from_utf8_lossy(&magic));
|
||||||
|
println!(
|
||||||
|
"cypher: {}",
|
||||||
|
String::from_utf8_lossy(&cypher_name)
|
||||||
|
);
|
||||||
|
println!("kdf: {}", String::from_utf8_lossy(&kdf_name));
|
||||||
|
|
||||||
|
println!("keytype: {}", String::from_utf8_lossy(&keytype));
|
||||||
|
println!("pub1[{}]: {:?}", pub1_len, &pub1);
|
||||||
|
println!("pub2[{}]: {:?}", pub2_len, &pub2);
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod tests {
|
||||||
|
use super::Ed25519PrivateKey;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ed25519() {
|
||||||
|
Ed25519PrivateKey::parse(include_str!("../ed25519"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ed25519_passphrased() {
|
||||||
|
Ed25519PrivateKey::parse(include_str!("../ed25519-passphrased"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_ed25519_keypair<S1, S2>(
|
pub fn generate_ed25519_keypair<S1, S2>(
|
||||||
passphrase: S1,
|
passphrase: S1,
|
||||||
id: Option<S2>,
|
id: Option<S2>,
|
||||||
|
@ -25,6 +132,8 @@ where
|
||||||
pub mod randomart {
|
pub mod randomart {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use osshkeys::error::OsshResult;
|
||||||
|
|
||||||
const WIDTH: usize = 17;
|
const WIDTH: usize = 17;
|
||||||
const HEIGHT: usize = 9;
|
const HEIGHT: usize = 9;
|
||||||
const TILES: &[char] = &[
|
const TILES: &[char] = &[
|
||||||
|
@ -120,7 +229,6 @@ pub mod randomart {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
740204
words_alpha.txt
740204
words_alpha.txt
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue