File pwtool-0.6.1.obscpio of Package pwtool
07070100000000000081A400000000000000000000000167CF4CB700000132000000000000000000000000000000000000001C00000000pwtool-0.6.1/.gitlab-ci.ymlimage: "rust:latest"
before_script:
- apt-get update -yqq
- apt-get install -yqq --no-install-recommends build-essential pandoc
# Use cargo to test the project
test:cargo:
script: |
rustc --version && cargo --version # Print version info for debugging
cargo test --workspace --verbose
07070100000001000081A400000000000000000000000167CF4CB700002160000000000000000000000000000000000000001800000000pwtool-0.6.1/Cargo.lock# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "blowfish"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32fa6a061124e37baba002e496d203e23ba3d7b73750be82dbfbc92913048a5b"
dependencies = [
"byteorder",
"cipher",
"opaque-debug",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
dependencies = [
"generic-array",
]
[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "crypto-mac"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer 0.10.4",
"crypto-common",
"subtle",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hmac"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
dependencies = [
"crypto-mac",
"digest 0.9.0",
]
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest 0.10.7",
]
[[package]]
name = "libc"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "md-5"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
dependencies = [
"block-buffer 0.9.0",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest 0.10.7",
"hmac 0.12.1",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "pwhash"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "419a3ad8fa9f9d445e69d9b185a24878ae6e6f55c96e4512f4a0e28cd3bc5c56"
dependencies = [
"blowfish",
"byteorder",
"hmac 0.10.1",
"md-5",
"rand",
"sha-1",
"sha2 0.9.9",
]
[[package]]
name = "pwtool"
version = "0.6.1"
dependencies = [
"base64",
"getopts",
"hmac 0.12.1",
"md5",
"pbkdf2",
"pwhash",
"rand",
"sha1",
"sha2 0.10.8",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "sha-1"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.7",
]
[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.7",
]
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
07070100000002000081A400000000000000000000000167CF4CB7000002BC000000000000000000000000000000000000001800000000pwtool-0.6.1/Cargo.toml[package]
name = "pwtool"
version = "0.6.1"
edition = "2021"
description = "pwtool, user account password tool"
authors = ["ed neville <ed@s5h.net>"]
license = "GPL-3.0-or-later"
homepage = "https://www.usenix.org.uk/content/pwtool.html"
repository = "https://gitlab.com/edneville/pwtool"
readme = "README.md"
categories = ["command-line-utilities"]
documentation = "https://www.usenix.org.uk/content/pwtool.html"
keywords = ["password","util","hash"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8"
pwhash = "1"
getopts = "0.2"
sha1 = "0.10"
md5 = "0.7"
pbkdf2 = "0.12.2"
base64 = "0.22"
sha2 = "0.10.8"
hmac = "0.12.1"
07070100000003000081A400000000000000000000000167CF4CB70000135F000000000000000000000000000000000000001700000000pwtool-0.6.1/README.md# pwtool
Generate passwords from random characters or words and optionally show their cryptographic hash.
The default generated password set is copy/paste friendly without extended characters that would break the default copy selection you get when double-clicking a word. They also are don't break quotation strings (quote marks, double quotes or backticks).
# installing
From cargo, ensuring that the install path (normally ~/.cargo/bin) is in your `PATH` environment.
```
cargo install pwtool
```
source code
```
git clone https://gitlab.com/edneville/pwtool.git
cd pwtool
cargo build --release
```
please or sudo
```
please install -m0755 -o0 -g0 target/release/pwtool /usr/local/bin/
```
snap
```
please snap install pwtool
```
# modifiers
`lowercase`, `uppercase`, `numeric` and `extended` will set requirements on the passwords.
# word lists
If you want a password generated from words rather than a mixture of letters and numbers, use the `words` option, which by default uses the file `/usr/share/dict/words`. Use `wordsfile` to specify a different list.
# cryptographic hash
The `--md5`, `--bcrypt`, `--des`, `--sha1`, `--sha256` and `--sha512` options will print the cryptographic hash which can be used instead of storing the password in some systems.
The hash output can be used with `useradd`/`usermod` or `.htaccess`:
```
LINE=`pwtool --number 1 --sha256`
PW="${LINE% *}"
HASH="${LINE##* }"
USR=newuser
useradd -m -p "$HASH" -s /bin/bash $USR
echo "Password for $USR is $PW"
```
Or issue a new password to an existing user with `usermod`:
```
LINE=`pwtool --number 1 --sha256`
PW=`echo "$LINE" | sed -e 's/ .*//g'`
HASH=`echo "$LINE" | sed -e 's/.* //g'`
USR=newuser
usermod -p "$HASH" $USR
echo "Password for $USR is now $PW"
```
# options
`--userfmt`, `--mysqlfmt`, `--pgfmt`, `--htauthfmt`, `--usermodfmt` are convenience options for format variables below, with the exception that they will also print the password in a comment:
pwtool --username thingy --userfmt
This then outputs like this:
useradd -m -s /bin/bash -p '$5$YLtTnPhYiQ891nAz$SHzSCc5vMIARxd4PYtxIOZ7mGICNsLGEGimMyFpRjE7' thingy # 8OtQUoUjV9
`--createdatabase` when combined with one of the database options will prefix with a `create database %{database};` string.
# format strings
With `--format` the variables can be used to output a custom string.
The variables (below) can be used within a `--format` string to output in a convenient way:
pwtool --username thingy --format "useradd -m -s /bin/bash -p '%{sha256}' %{username} # %{password}\n"
This then outputs like this:
useradd -m -s /bin/bash -p '$5$YLtTnPhYiQ891nAz$SHzSCc5vMIARxd4PYtxIOZ7mGICNsLGEGimMyFpRjE7' thingy # 8OtQUoUjV9
You can then copy/paste that around different systems where people need the same account.
Another common way is to use it for mysql setup at the same time:
pwtool --username thingy --database thing --format "grant all privileges on %{database}.* to %{username}@'%' identified with mysql_native_password as '%{mysql}';\n";
| variable | output |
|----------|--------|
| %{des} | traditional crypt |
| %{bcrypt} | BSD standard hash |
| %{md5} | MD5 hash |
| %{sha1} | HMAC SHA1 |
| %{sha256} | SHA256 |
| %{sha512} | SHA512 |
| %{mysql} | password in mysql_native format |
| %{password} | cleartext password |
| %{username} | placeholder for --username |
| %{database} | placeholder for --database |
| %{postgres} | postgres SCRAM-SHA-256 password |
| %{userfmt} | expands to `useradd -m -s /bin/bash -p '%{sha256}' %{username}` |
| %{usermodfmt} | expands to `usermod -p '%{sha256}' %{username}` |
| %{mysqlfmt} | expands to `grant all privileges on %{database}.* to %{username}@'%' identified with mysql_native_password as '%{mysql}';` |
| %{pgfmt} | expands to `create user thingy password '%{postgres}';` |
| %{htauthfmt} | expands to `%{username}:%{sha256}` |
# executing output
Should you want to execute the output, `tee` is quite handy as it will print to stdout and an elevated file descriptor:
pwtool --username moo --format "useradd -m -s /bin/bash -p '%{sha256}' %{username} # %{password}\n" --number 1 | tee >( please /bin/bash )
useradd -m -s /bin/bash -p '$5$pZxFddWqXpBuozZF$l1Eyw2HqsGP0E9pdQctqeCPTOL3eJOPq4pNiI6MoZG5' moo # 6nIFhAKJSC
This will both add the user and print the password in the shell.
# http basic authentication
You can populate entries in basic authentication files too:
pwtool --username moo --format '%{htauthfmt}'
Not the output has the password in a comment prior to the auth line as data after the `:` is normally treated as the hashed password. You can store this in `/etc/apache2/restricted`:
AuthType Basic
AuthName "Keep out!"
AuthUserFile "/etc/apache2/restricted"
Require valid-user
or with nginx, in `/etc/nginx/restricted`:
auth_basic "Keep out!";
auth_basic_user_file /etc/nginx/restricted;
07070100000004000081A400000000000000000000000167CF4CB7000001CB000000000000000000000000000000000000001A00000000pwtool-0.6.1/changelog.md0.6.1
* --onlylowercase and --onlyuppercase convert --words options to desired case
* --nospaces option for --words
0.6.0
* change convenience variables to not include \n
* new options --htauthfmt --mysqlfmt --pgfmt --userfmt --usermodfmt
0.5.0
* correct naming of htauth -> htauthfmt to match other similar helpers
0.4.1
* default convenience formatting for mysql, postgres, htauth and useradd
commands
* docs and tests
0.4.0
* mysql and postgres
07070100000005000041ED00000000000000000000000267CF4CB700000000000000000000000000000000000000000000001100000000pwtool-0.6.1/src07070100000006000081A400000000000000000000000167CF4CB700002AEA000000000000000000000000000000000000001800000000pwtool-0.6.1/src/lib.rsuse base64::prelude::*;
use hmac::{Hmac, Mac};
use pbkdf2::pbkdf2_hmac;
use pwhash::*;
use rand::distributions::Alphanumeric;
use rand::thread_rng;
use rand::Rng;
use sha1::{Digest, Sha1};
use sha2::Sha256;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
pub struct Config {
pub number: u32,
pub len: u32,
pub pw_type: Option<u32>,
pub word_list: Option<String>,
pub words: Option<Vec<String>>,
pub username: Option<String>,
pub database: Option<String>,
pub create_database: bool,
pub spaces: bool,
}
impl Config {
pub fn new() -> Config {
Config {
len: 15,
pw_type: None,
number: 20,
word_list: None,
words: None,
username: None,
database: None,
create_database: false,
spaces: true,
}
}
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
}
pub enum PwClass {
Num = 1 << 0,
Alpha = 1 << 1,
Ext = 1 << 2,
Lower = 1 << 3,
Upper = 1 << 4,
}
pub fn valid_word(s: &str, word_set: Option<u32>) -> bool {
if word_set.is_some() {
let mut valid = false;
if word_set.as_ref().unwrap() & PwClass::Num as u32 != 0 {
for j in s.chars() {
if j.is_ascii_digit() {
valid = true;
}
}
}
if word_set.as_ref().unwrap() & PwClass::Lower as u32 != 0 {
for j in s.chars() {
if j.is_ascii_lowercase() {
valid = true;
}
}
}
if word_set.as_ref().unwrap() & PwClass::Upper as u32 != 0 {
for j in s.chars() {
if j.is_ascii_uppercase() {
valid = true;
}
}
}
if word_set.as_ref().unwrap() & PwClass::Ext as u32 != 0 {
for j in s.chars() {
if !j.is_ascii_digit() && !j.is_ascii_lowercase() && !j.is_ascii_uppercase() {
valid = true;
}
}
}
return valid;
};
true
}
pub fn prng_string(c: &mut Config) -> String {
let mut set = c.pw_type;
if set.is_none() {
set = Some(
PwClass::Num as u32
| PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32,
);
}
let mut rng = rand::thread_rng();
if c.word_list.is_some() {
let word_list = c.word_list.as_ref().unwrap();
if c.words.is_none() {
let f = File::open(word_list);
if f.is_err() {
eprintln!("Cannot open {}: {}", word_list, f.err().unwrap());
std::process::exit(1);
}
let f = f.unwrap();
let mut line = String::new();
let mut br = BufReader::new(f);
let mut wv: Vec<String> = vec![];
loop {
line.clear();
let l = br.read_line(&mut line);
match l {
Ok(i) => {
if i == 0 {
break;
}
}
Err(_) => {
break;
}
}
// skip words with apostrophes etc
if line.find('\'').is_some() {
continue;
}
let s = line.clone().trim().to_string();
if s.is_empty() {
continue;
}
if !valid_word(&s, c.pw_type) {
continue;
}
wv.push(s);
}
c.words = Some(wv);
}
let mut phrase = vec![];
let words_len = c.words.as_ref().unwrap().len();
if c.words.as_ref().unwrap().is_empty() {
eprintln!("no words to process");
std::process::exit(1);
}
for _j in 0..c.len {
phrase.push(
c.words.as_ref().unwrap()[rng.gen_range(0..words_len)]
.clone()
.to_string(),
);
}
let mut phrase = phrase.join(if c.spaces { " " } else { "" });
if c.pw_type.is_some() {
let set = c.pw_type.as_ref().unwrap();
if set & PwClass::Lower as u32 != 0 {
phrase = phrase.to_lowercase();
}
if set & PwClass::Upper as u32 != 0 {
phrase = phrase.to_uppercase();
}
}
return phrase;
}
let set = set.unwrap();
let mut chars = "".to_string();
if set & PwClass::Num as u32 != 0 {
chars += "0123456789";
};
if set & PwClass::Alpha as u32 != 0 {
chars += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
};
if set & PwClass::Lower as u32 != 0 {
chars += "abcdefghijklmnopqrstuvwxyz";
};
if set & PwClass::Upper as u32 != 0 {
chars += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
};
if set & PwClass::Ext as u32 != 0 {
chars += r#"!"$%^&*()-={}[]:;@'<>,./\|"#;
};
let one_char = || chars.chars().nth(rng.gen_range(0..chars.len())).unwrap();
std::iter::repeat_with(one_char)
.take(c.len as usize)
.collect()
}
pub fn gen_salt_str(chars: usize) -> String {
let rng = thread_rng();
rng.sample_iter(&Alphanumeric)
.take(chars)
.map(|x| x as char)
.collect()
}
pub fn postgres_pass(pw: &str) -> String {
let salt_size = 16;
let iterations = 4096;
let salt = gen_salt_str(salt_size);
let mut key = [0u8; 32];
pbkdf2_hmac::<Sha256>(pw.as_bytes(), salt.as_bytes(), iterations, &mut key);
let mut client_key = Hmac::<Sha256>::new_from_slice(&key).unwrap();
client_key.update(b"Client Key");
let client_result = client_key.finalize();
let mut server_key = Hmac::<Sha256>::new_from_slice(&key).unwrap();
server_key.update(b"Server Key");
let server_result = server_key.finalize();
let mut stored_key = Sha256::new();
stored_key.update(client_result.clone().into_bytes());
let stored_key = stored_key.finalize();
let bstored_key = BASE64_STANDARD.encode(stored_key);
let bsalt = BASE64_STANDARD.encode(salt);
let bserver_key = BASE64_STANDARD.encode(server_result.clone().into_bytes());
format!("SCRAM-SHA-256${iterations}:{bsalt}${bstored_key}:{bserver_key}")
}
pub fn mysql_pass(pw: &str) -> String {
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!("*{:x}", r).to_string()
}
pub fn useradd_format() -> String {
"useradd -m -s /bin/bash -p '%{sha256}' %{username}".to_string()
}
pub fn usermod_format() -> String {
"usermod -p '%{sha256}' %{username}".to_string()
}
pub fn mysql_format() -> String {
"grant all privileges on %{database}.* to %{username}@'%' identified with mysql_native_password as '%{mysql}';".to_string()
}
pub fn postgres_format() -> String {
"create user %{username} password '%{postgres}';".to_string()
}
pub fn htauth_format() -> String {
"%{username}:%{sha256}".to_string()
}
#[allow(deprecated)]
pub fn process_format_string(format_string: &mut String, c: &Config, pw: &str) -> String {
if format_string.contains("%{userfmt}") {
*format_string = format_string.replace("%{userfmt}", &useradd_format().to_string());
}
if format_string.contains("%{usermodfmt}") {
*format_string = format_string.replace("%{usermodfmt}", &usermod_format().to_string());
}
if format_string.contains("%{mysqlfmt}") {
*format_string = format_string.replace("%{mysqlfmt}", &mysql_format().to_string());
}
if format_string.contains("%{pgfmt}") {
*format_string = format_string.replace("%{pgfmt}", &postgres_format().to_string());
}
if format_string.contains("%{htauthfmt}") {
*format_string = format_string.replace("%{htauthfmt}", &htauth_format().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}") {
*format_string = format_string.replace("%{mysql}", &mysql_pass(pw).to_string());
}
if format_string.contains("%{postgres}") {
*format_string = format_string.replace("%{postgres}", &postgres_pass(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}") {
*format_string = format_string.replace("%{mysql}", &mysql_pass(pw));
}
*format_string = format_string.replace(r#"\n"#, "\n");
format_string.to_string()
}
pub fn create_pg_database(c: &Config) -> String {
if c.create_database {
return format!(
"create database {}; ",
c.database.as_ref().unwrap_or(&"".to_string())
)
.to_string();
}
"".to_string()
}
pub fn create_mysql_database(c: &Config) -> String {
if c.create_database {
return format!(
"create database {}; ",
c.database.as_ref().unwrap_or(&"".to_string())
)
.to_string();
}
"".to_string()
}
07070100000007000081A400000000000000000000000167CF4CB700002F58000000000000000000000000000000000000001900000000pwtool-0.6.1/src/main.rsuse getopts::Options;
use pwhash::*;
use pwtool::*;
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("createdatabase") {
c.create_database = true;
}
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",
"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.spaces = !matches.opt_present("nospaces");
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.optflag("", "mysqlfmt", "alias for --format \"%{mysqlfmt}\\n\"");
opts.optflag("", "pgfmt", "alias for --format \"%{pgfmt}\\n\"");
opts.optflag("", "userfmt", "alias for --format \"%{userfmt}\\n\"");
opts.optflag("", "usermodfmt", "alias for --format \"%{usermodfmt}\\n\"");
opts.optflag("", "htauthfmt", "alias for --format \"%{htauthfm}\\n\"");
opts.optopt("", "username", "for %{username} formatter", "STRING");
opts.optopt("", "database", "for %{database} formatter", "STRING");
opts.optflag(
"",
"createdatabase",
"when using --pgfmt or --mysqlfmt, prefix with a create database statement",
);
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.optflag("", "nospaces", "don't join words with spaces");
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.\nmysqlfmt, pgfmt, userfmt, htauthfmt\n",
"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 {
let pw = prng_string(&mut c);
let mut donefmtopt = false;
if matches.opt_present("md5") {
println!("{} {}", pw, md5_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha1") {
println!("{} {}", pw, sha1_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha256") {
println!("{} {}", pw, sha256_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha512") {
println!("{} {}", pw, sha512_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("bcrypt") {
println!("{} {}", pw, bcrypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("des") {
println!("{} {}", pw, unix_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("pgfmt") {
let mut format_string =
format!("{}%{{pgfmt}} -- # %{{password}}\n", create_pg_database(&c)).to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("mysqlfmt") {
let mut format_string = format!(
"{}%{{mysqlfmt}} -- # %{{password}}\n",
create_mysql_database(&c)
)
.to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("htauthfmt") {
let mut format_string = "# %{password}\n%{htauthfmt}\n".to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("userfmt") {
let mut format_string = "%{userfmt} # %{password}\n".to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("usermodfmt") {
let mut format_string = "%{usermodfmt} # %{password}\n".to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("format") {
let mut format_string = matches.opt_str("format").unwrap().to_string();
if format_string.trim() == "useradd" {
format_string = "%{userfmt} # %{password}\n".to_string();
}
if format_string.trim() == "usermod" {
format_string = "%{usermodfmt} # %{password}\n".to_string();
}
if format_string.trim() == "mysql" {
format_string = "%{mysqlfmt} -- %{password}\n".to_string();
}
if format_string.trim() == "pg" {
format_string = "%{pgfmt} -- %{password}\n".to_string();
}
if format_string.trim() == "htauth" {
format_string = "# %{password}\n%{htauthfmt}\n".to_string();
}
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
continue;
}
if donefmtopt {
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!();
}
}
07070100000008000041ED00000000000000000000000267CF4CB700000000000000000000000000000000000000000000001300000000pwtool-0.6.1/tests07070100000009000081A400000000000000000000000167CF4CB700000628000000000000000000000000000000000000001900000000pwtool-0.6.1/tests/pw.rs#[cfg(test)]
mod test {
use pwtool::*;
#[test]
fn test_acceptable_lowercase() {
let test = "abc";
let test_bad = "ABC";
let set = Some(PwClass::Lower as u32);
assert_eq!(valid_word(&test, set), true);
assert_eq!(valid_word(&test_bad, set), false);
}
#[test]
fn test_acceptable_uppercase() {
let test = "ABC";
let test_bad = "abc";
let set = Some(PwClass::Upper as u32);
assert_eq!(valid_word(&test, set), true);
assert_eq!(valid_word(&test_bad, set), false);
}
#[test]
fn test_acceptable_numeric() {
let test = "abc1";
let test_bad = "abcABC";
let set = Some(PwClass::Num as u32);
assert_eq!(valid_word(&test, set), true);
assert_eq!(valid_word(&test_bad, set), false);
}
#[test]
fn test_acceptable_extended() {
let test_bad = "abcABC";
let set = Some(PwClass::Ext as u32);
for j in '!'..='/' {
assert_eq!(valid_word(j.to_string().as_ref(), set), true);
}
assert_eq!(valid_word(&test_bad, set), false);
}
#[test]
fn test_gen_salt() {
use base64::prelude::*;
let salt = gen_salt_str(40);
let e = BASE64_STANDARD.decode(salt);
assert!(e.is_ok());
}
#[test]
fn test_postgres_pass() {
let pass = postgres_pass("foo");
assert!(pass.len() > 40);
}
#[test]
fn test_mysql_pass() {
let pass = mysql_pass("foo");
assert!(pass.len() > 40);
}
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!81 blocks