aboutsummaryrefslogblamecommitdiffstats
path: root/README.md
blob: a55bc0cd1ea2326b30cdff29b8efef28e2936d38 (plain) (tree)
1
2
3
4
5
6
7
8



                             


                                                                           
 









                                                                              



                                                                        
                                                                           









                                                                                
























                                                                                   


























































                                                                                 
                                                         





























                                                                               
 







                                                                              



                                                                                        
                                                                                                                 
 







                                                                                
                                                                        
                            

                                                                                 
 
                          

                                                                               
 
                          

                                                                                 
 


                                                                                 
 


                                                                               
 






                                                                                   

       






                                                  




           
                                                      


                                       
 
   
                                           


        
                                    
 


                                                                                                                               











                                                               





                        
                                                           

   
         
                                              


                                                                              

                                                                           
# makepass

*This is a work in progress!*

makepass is a program that outputs a series of random passwords with both
"normal" and "special" characters, and a series of passphrases from a given
dictionary. See below for an example of what the output looks like.

makepass is implemented in several languages for both fun and learning. The
current main version is `makepass.zsh`. The symlink `./makepass` will always
point to the main version.

## History

I wrote makepass long ago (somewhere between 2010 and 2013 I believe) to just
spit out some random strings I could use as passwords.

The first versions has been lost to time, and makepass was first commited to a
git-repo in 2018, as part of my dotfile-repo
[idgatt](https://git.dnns.no/idgatt/) ("It's Dangerous to Go Alone, Take
This!").

makepass was first written as a bash-script, but it was a zsh-script when I
commited it to my dotfile-repo. It was later changed back to a bash-script, and
in 2022 I rewrote it as both a POSIX shell-script and as a zsh-script.

Around then I found some joy in tinkering with the script, and I did some
optimalization of the zsh-script to minimilize forks and runtime. It is now pure
zsh, and does not fork out to any other programs.

Recently I decided I wanted to try to recreate makepass in other languages, and
maybe see if I can make it even faster.

## Example output

```
Normal passwords:
ZmvQB4r23KnctqjoV8fAlObMNu9Yt               f-FS1k7yXwxeTIZk
IpCL6RiHgh0DsJGzE_mvQB4r23KnctqjoV8fAlY     ANu9Yda5-FS1k7yXwxeTIZWPUpCL6RiHgh0Dsr
vE_mvQB4r23KnctqjoV8fAlObMNu9YdaD           dS1k7yXwxeTIZu
wpCL6RiHgh0DsJGzE_mvQB4r23KnctqjoV8fAN      XMNu9Yda5-FS1k7yXwxeTIZWPUpCL6
uHgh0DsJGzE_mV                              N4r23KnctqjoV8fAlObMNu9Yda5-FS1k7yXwxy

Passwords with special characters:
L&ROH=NKTcti-U#Sv_/Ojgx}1kd+jEFe)cX         fwVCfYRWXghK9AR$-Ex.vktyrE5
HAZG-EhuL&t4H:x}vc74HwFe|&Raj@Fy            w7>j!hev_JabEV(vIBqHMx.TcZGjwV0|c,i-!<W
QJa%g3ufIJaPw3C;Yla[=peTQ,>5E?}vAR4zMpCD6v  PENeD&lyr@xKF
ZazwVCLAJWzM?8fs{W%g#KvYZq[Mp(P

Passphrases:
tweak-boots-shun-pond-cone-wimp-happy-polar
shut-acre-decay-thank-pagan-crown-snack-cadet
slug-putt-twist-fresh-park-flock-deed-error
music-rerun-mocha-acid-taps-boast-rule-clad
churn-curvy-wreck-list-stove-bonus-ozone-atom
```

## Specifications
Here's the synopsis from `makepass.zsh`, which explains how makepass should work:

```
NAME
    makepass - create several random passwords

SYNOPSIS
    makepass [OPTIONS] [NUM]

    If a NUM is provided, passwords will be NUM characters long.

    By default `makepass` will output passwords from the three following classes:

    - Normal passwords - random strings with letters (both lower and upper
      case), numbers, and dashes and underscores.

    - Passwords with special characters - random strings generated from lower
      and upper case letters, numbers, and the following characters:
      !#$%&/()=?+-_,.;:<>[]{}|@*

    - Passphrases - if we find a dictionary, a series of eight random words
      from the dictionary, separated by dashes. The number of words can not be
      changed, but you do not have to use all of them. Use as mane as you want.

    The first and last letter will always be a letter.

DESCRIPTION
    makepass has the following options:

    -h
        output this help-text
    -l
        length of passwords. See MAKEPASS_LENGTH below
    -n
        number of passwords. See MAKEPASS_NUMBER below
    -p
        print length of number

ENVIRONMENT
    makepass examines the following environmental variables.

    MAKEPASS_LENGTH
        Specifies the length of passwords. Valid values are 0-255. If 0, a
        random value between 8 and 42 will be used for each password. -l
        overrides this environmental variable, and the argument NUM overrides
        that again. So `MAKEPASS_LENGTH=10 makepass -l 12 14` will give
        passwords that are 14 characters long, even though both -l and
        MAKEPASS_LENGTH also specifies a length.

    MAKEPASS_NUMBER
        The number of passwords to generate. This formula is used to determine
        how many passwords from each group should be generated:
        - (n) normal passwords
        - (n / 3 * 2 + 1) special passwords
        - (n / 2) passphrases
        Where n is 10 by default. Valid values for n are 1-255. Floating-poing
        math is not used, so results may vary.

    MAKEPASS_PRINTLEN
        If 1, print length of all passwords. If 0, don't.

    MAKEPASS_NORMAL
        String of characters from which to generate "normal" passwords.
        Defaults to:
        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_

    MAKEPASS_SPECIAL
        String of characters from which to generate passwords with special
        characters. Defaults to the same characters as in MAKEPASS_NORMAL, plus
        these:
        !#$%&/()=?+-_,.;:<>[]{}|@*

    MAKEPASS_WORDLIST
        Specifies the dictionary we find words for passphrases in. If this is
        unset or empty, we try "/usr/share/dict/words". If that file does not
        exist, no passphrases will be provided.

NOTES
    This scripts makes use of $RANDOM - a builtin in zsh which produces a
    pseudo-random integer between 0 and 32767, newly generated each time the
    parameter is referenced. We initially seed the random number generator with
    a random 32bit integer generated from /dev/random. This should provide
    enough randomnes to generate sufficiently secure passwords.

AUTHOR
    Dennis Eriksen <https://dnns.no>'
```

Also, the passwords should *preferably* be output in columns. The number of
columns should be dynamic, and dependant on the width of the screen.

#### Dependencies

I want these programs to be able to run without having to install lots of
extra packages. Therefore, I try to minimize external dependencies to what's
available with POSIX. However, this limitation does not apply to the languages
which get compiled - as long as they handle their own dependencies, and the
binary can run without the need to install extra fluff.

### Character sets

Normal character set: `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_`

Special character set: `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&/()=?+-_,.;:<>[]{}|@*`

## Benchmarks
I started out using just zshs `time` to time the runtime, but recently I started
checking out [hyperfine](https://github.com/sharkdp/hyperfine) which does a
nice job.

Here are the results so far:

```
% hyperfine --time-unit=millisecond --warmup=1 --shell=none ./makepass.*
Benchmark 1: ./makepass.bash
  Time (mean ± σ):      81.2 ms ±   1.9 ms    [User: 34.0 ms, System: 39.7 ms]
  Range (min … max):    77.3 ms …  85.2 ms    35 runs

Benchmark 2: ./makepass.go
  Time (mean ± σ):       6.7 ms ±   0.1 ms    [User: 1.0 ms, System: 4.9 ms]
  Range (min … max):     6.4 ms …   7.8 ms    444 runs

Benchmark 3: ./makepass.pl
  Time (mean ± σ):      40.4 ms ±   0.3 ms    [User: 19.7 ms, System: 18.3 ms]
  Range (min … max):    39.7 ms …  41.3 ms    75 runs

Benchmark 4: ./makepass.py
  Time (mean ± σ):     103.5 ms ±   1.2 ms    [User: 71.0 ms, System: 27.9 ms]
  Range (min … max):   101.9 ms … 107.8 ms    29 runs

Benchmark 5: ./makepass.rs
  Time (mean ± σ):       4.9 ms ±   0.2 ms    [User: 1.1 ms, System: 2.4 ms]
  Range (min … max):     4.4 ms …   5.6 ms    610 runs

Benchmark 6: ./makepass.sh
  Time (mean ± σ):     638.4 ms ±   2.9 ms    [User: 155.0 ms, System: 915.0 ms]
  Range (min … max):   634.0 ms … 643.9 ms    10 runs

Benchmark 7: ./makepass.zsh
  Time (mean ± σ):      26.9 ms ±   0.7 ms    [User: 13.4 ms, System: 12.0 ms]
  Range (min … max):    25.5 ms …  30.2 ms    109 runs

Summary
  ./makepass.rs ran
    1.36 ± 0.07 times faster than ./makepass.go
    5.44 ± 0.31 times faster than ./makepass.zsh
    8.19 ± 0.42 times faster than ./makepass.pl
   16.46 ± 0.91 times faster than ./makepass.bash
   20.96 ± 1.08 times faster than ./makepass.py
  129.36 ± 6.50 times faster than ./makepass.sh
```

## Versions

### Bash
Bash-version. It's a lot messier than the zsh-version.

### Go
Build width (from root folder in repo):

```
$ go build -C src/go -o .. -ldflags "-s -w"
```

### Perl
Perl version. I like this version <3

### Python
I don't really care for python, but here it is. It's pretty slow, but I don't really know Python. It should probably be faster.

To lint and format with `ruff`, `ruff` must first be installed.

```
$ cd src/python
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install --upgrade pip
$ pip install ruff
$ ruff check makepass.py
$ ruff format makepass.py
```

### Rust
Rust-version. It's fast!

Build with (from root):

```
$ cargo build --manifest-path src/rust/Cargo.toml --release
```

### Shell
*Should* be pure POSIX sh. Needs some cleanup.

### Zsh
This is currently the "main" version. It uses pure zsh, with no forking out to
other programs. Aside from the compiled languages, it is by far the fastest
version.