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
openSUSE Build Service is sponsored by