use getopts::Options;
use pwhash::*;
use pwtool::*;
use sha1::{Digest, Sha1};
use std::env;
const VERSION: &str = env!("CARGO_PKG_VERSION");
fn print_usage(program: &str, opts: Options) {
let brief = format!("Usage: {} [options]", program);
print!("{}", opts.usage(&brief));
}
fn set_config_options(
matches: &getopts::Matches,
c: &mut Config,
args: Vec<String>,
opts: Options,
) {
if matches.opt_present("version") {
println!("pwtool {VERSION}");
std::process::exit(0);
}
if matches.opt_present("words") {
c.word_list = Some("/usr/share/dict/words".to_string());
}
if matches.opt_present("wordsfile") {
let words = matches.opt_str("wordsfile").unwrap();
c.word_list = Some(words);
}
let mut found = false;
for opt in [
"onlynumeric",
"onlyalpha",
"onlyuppercase",
"onlyuppercase",
"onlylowercase",
"onlyextended",
] {
if matches.opt_present(opt) {
if found {
eprintln!("cannot have multiple --only* options");
std::process::exit(1);
}
found = true;
}
}
if matches.opt_present("onlynumeric") {
c.pw_type = Some(PwClass::Num as u32);
}
if matches.opt_present("onlyalpha") {
c.pw_type = Some(PwClass::Alpha as u32);
}
if matches.opt_present("onlyuppercase") {
c.pw_type = Some(PwClass::Upper as u32);
}
if matches.opt_present("onlylowercase") {
c.pw_type = Some(PwClass::Lower as u32);
}
if matches.opt_present("onlyextended") {
c.pw_type = Some(PwClass::Ext as u32);
}
if matches.opt_present("onlyextended") {
c.pw_type = Some(PwClass::Ext as u32);
}
if matches.opt_present("help") {
print_usage(&args[0], opts);
std::process::exit(0);
}
if matches.opt_present("username") {
c.username = matches.opt_str("username");
}
if matches.opt_present("database") {
c.database = matches.opt_str("database");
}
c.len = if matches.opt_present("length") {
let n = matches.opt_str("length").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else if c.word_list.is_some() {
3
} else {
10
};
c.number = if matches.opt_present("number") {
let n = matches.opt_str("number").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else {
20
};
if matches.opt_present("numeric") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Num as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("alpha") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Alpha as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("extended") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Ext as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
| PwClass::Ext as u32
}
});
}
if matches.opt_present("uppercase") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Upper as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("lowercase") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Lower as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("help") {
print_usage(&args[0], opts);
std::process::exit(0);
}
c.len = if matches.opt_present("length") {
let n = matches.opt_str("length").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else if c.word_list.is_some() {
3
} else {
10
};
c.number = if matches.opt_present("number") {
let n = matches.opt_str("number").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else {
20
};
}
#[allow(deprecated)]
fn main() {
let mut c = Config::new();
let args: Vec<String> = env::args().collect();
let mut opts = Options::new();
opts.optflag("h", "help", "display help");
opts.optflag("", "alpha", "use alpha characters (default)");
opts.optflag("", "numeric", "use numeric characters (default)");
opts.optflag("", "extended", "use extended characters");
opts.optflag("", "lowercase", "use lowercase characters (default)");
opts.optflag("", "uppercase", "use uppercase characters (default)");
opts.optflag("", "onlyuppercase", "use uppercase characters");
opts.optflag("", "onlylowercase", "use lowercase characters");
opts.optflag("", "onlynumeric", "use numeric characters");
opts.optflag("", "onlyextended", "use extended characters");
opts.optflag("", "onlyalpha", "use alpha characters");
opts.optflag("", "md5", "use MD5");
opts.optflag("", "bcrypt", "use bcrypt");
opts.optflag("", "des", "use traditional unix crypt");
opts.optflag("", "sha1", "use SHA1");
opts.optflag("", "sha256", "use SHA256");
opts.optflag("", "sha512", "use SHA512");
opts.optopt("", "username", "for %{username} formatter", "STRING");
opts.optopt("", "database", "for %{database} formatter", "STRING");
opts.optflag("v", "version", "display version");
opts.optopt("n", "number", "number of passwords", "NUMBER");
opts.optopt(
"l",
"length",
"length of passwords (default is three with a wordlist)",
"NUMBER",
);
opts.optflag("w", "words", "use default wordlist");
opts.optopt("", "wordsfile", "use wordsfile", "FILE");
opts.optopt(
"",
"format",
"output using a string: %{VAL} where VAL is md5, bcrypt, des, sha1, sha256, sha512, mysql, postgres, database, password or username",
"FORMAT",
);
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
eprintln!("{}", f);
std::process::exit(1);
}
};
set_config_options(&matches, &mut c, args, opts);
for _ in 0..c.number {
if matches.opt_present("md5") {
let pw = prng_string(&mut c);
println!("{} {}", pw, md5_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha1") {
let pw = prng_string(&mut c);
println!("{} {}", pw, sha1_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha256") {
let pw = prng_string(&mut c);
println!("{} {}", pw, sha256_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha512") {
let pw = prng_string(&mut c);
println!("{} {}", pw, sha512_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("bcrypt") {
let pw = prng_string(&mut c);
println!("{} {}", pw, bcrypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("des") {
let pw = prng_string(&mut c);
println!("{} {}", pw, unix_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("format") {
let pw = prng_string(&mut c);
let mut format_string = matches.opt_str("format").unwrap().to_string();
if format_string.contains("%{md5}") {
format_string =
format_string.replace("%{md5}", &md5_crypt::hash(&pw).unwrap().to_string());
}
if format_string.contains("%{bcrypt}") {
format_string =
format_string.replace("%{bcrypt}", &bcrypt::hash(&pw).unwrap().to_string());
}
if format_string.contains("%{des}") {
format_string =
format_string.replace("%{des}", &unix_crypt::hash(&pw).unwrap().to_string());
}
if format_string.contains("%{sha1}") {
format_string =
format_string.replace("%{sha1}", &sha1_crypt::hash(&pw).unwrap().to_string());
}
if format_string.contains("%{sha256}") {
format_string = format_string
.replace("%{sha256}", &sha256_crypt::hash(&pw).unwrap().to_string());
}
if format_string.contains("%{sha512}") {
format_string = format_string
.replace("%{sha512}", &sha512_crypt::hash(&pw).unwrap().to_string());
}
if format_string.contains("%{password}") {
format_string = format_string.replace("%{password}", &pw);
}
if format_string.contains("%{username}") && c.username.is_some() {
format_string = format_string.replace("%{username}", c.username.as_ref().unwrap());
}
if format_string.contains("%{database}") && c.database.is_some() {
format_string = format_string.replace("%{database}", c.database.as_ref().unwrap());
}
if format_string.contains("%{mysql}") {
let mut h = Sha1::new();
h.update(&pw);
let r = h.finalize();
let mut h = Sha1::new();
h.update(r);
let r = h.finalize();
format_string = format_string.replace("%{mysql}", &format!("*{:x}", r).to_string());
}
if format_string.contains("%{postgres}") {
let postgres_pass = postgres_pass(&pw);
format_string = format_string.replace("%{postgres}", &postgres_pass);
}
format_string = format_string.replace(r#"\n"#, "\n");
print!("{}", format_string);
continue;
}
for j in 1..8 {
let pw = prng_string(&mut c);
print!("{}{}", pw, if j != 8 { " " } else { "" },);
if c.word_list.is_some() {
break;
}
}
println!();
}
}