33

How do you create a readable password using bash with one line? What if i'm looking for 128 bits of entropy?

EDIT

By readable I mean the 94 printable ascii characters (without space). It can use less than these characters as long as it has at least 128 bits of entropy.

user10008
  • 4,315
  • 21
  • 33
Andras Gyomrey
  • 821
  • 3
  • 9
  • 17

11 Answers11

53

It depends on what you mean by "readable". If you want to use only hexadecimal characters, you will need 32 of them to reach 128 bits of entropy; this line will work (using only commands from the coreutils package):

head -c16 /dev/urandom | md5sum

This variant produces passwords with only lowercase letters, from 'a' to 'p' (this is what you will want if you have to "type" the password on a smartphone):

head -c16 /dev/urandom | md5sum | tr 0-9 g-p

If you want to type one less characters, try this:

head -16 /dev/urandom | md5sum

(Probability of getting all first 16 random bytes as 0x0A, i.e. the "newline" character, is 2-128, hence this line still gets 128 bits of entropy.)

Still limiting yourself to commands from coreutils, you can do this:

mktemp -u XXXXXXXXXXXXXXXXXXXXXX

This one generates a 22-character password, using /dev/urandom as internal source of randomness (I checked in the source code, and a strace call confirms). The characters are letters (uppercase and lowercase) and digits; since 6222 is greater than 2128, the 22 characters are sufficient.

Yet another one:

od -An -x /dev/urandom | head -1

this displays eight sequences of four hexadecimal digits. Arguably, this split into small sequences may help reading.

For a much longer line and a quite distinct kind of password, try this:

for i in {1..8} ; do head -$(expr $(head -c7 /dev/urandom | od -An -t dL) % $(wc -l < /usr/share/dict/british-english)) /usr/share/dict/british-english | tail -1 ; done

(this one works only on a 64-bit host; will you notice why ?). Apart from coreutils, that version also requires a dictionary file, here the one for British English.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • 11
    This answer proves, once again, that there are many ways to reach the same goal in Linux. I only wish I were this skilled in Linux. – phyrfox Oct 21 '14 at 07:55
  • 2
    *from 'a' to 'p'* I guess that removing uppercase and numbers make it easier to type on a smartphone keyboard, but why does it stop at *p*? – A.L Oct 21 '14 at 08:14
  • 10
    @A.L Because the input stems from hex, which outputs 0-9 and A-F. A-F don't need to be modified, 0-9 are mapped to letters starting from g. 9 happens to map to p. When you map 16 different characters to letters via simple substitution you only reach 16 letters, and p is the 16th letter in the alphabet. – CodesInChaos Oct 21 '14 at 09:25
  • 4
    I would not use this answer because any hash-sum (md5sum, sha256sum, ...) outputs hexadecimals. They contain only 4 bits of randomness per byte while being just as hard to remember as any same-cased alphanumeric string. There are lots of packages and other ways to do this properly, even if you only use tools that are available on almost every Unix-like OS. – Luc Oct 21 '14 at 19:16
  • 4
    Conceptually, `mktemp` should not be considered cryptographically secure. If it is, that's an implementation detail, not part of its job, and failures in its strength would probably not be CVE-worthy (since it's not designed for that) so it seems like a bad choice. – R.. GitHub STOP HELPING ICE Oct 21 '14 at 20:49
  • 5
    Sample password produced by the last item: `cold-hammered brazen-face self-displicency Bajocian transcends grewsome harpoon pedanticness`. Probably easier to remember if you draw a cartoon for it. – tylerl Oct 22 '14 at 06:06
  • 2
    Android should have a 16 letter keyboard for easier typing passwords! – SPRBRN Oct 22 '14 at 08:03
  • 3
    @R..: actually, `mktemp` is supposed to be used by shell script that need to create a temporary file. If `mktemp` is predictable, then an attacker can exploit the race condition between name lookup and file creation to put a symbolic link in place, and make the script overwrite any target file. This has been done and was a common exploit a decade ago. Thus, `mktemp` not feeding on a strong random source _would_ be CVE-worthy. – Thomas Pornin Oct 22 '14 at 11:10
  • 1
    @ThomasPornin: No, they can't. Safety of temp file creation has nothing to do with unpredictability of names but with correct use of `O_EXCL`, `O_NOFOLLOW`, and other operations (e.g. `mkdir`) which atomically fail if a file/symlink already exists. – R.. GitHub STOP HELPING ICE Oct 22 '14 at 13:13
  • I did a variant of your last one, building up the numbers as a list of options to sed like `-e 1234p -e 5678p -e d` and then using `sed` to make just one pass over the file to get all the words. – David Conrad Oct 22 '14 at 20:37
  • 1
    If you want better randomness, use `/dev/random`, – Kaz Wolfe Oct 23 '14 at 09:03
  • 1
    @Mew: `/dev/random` does not provide "better" randomness than `/dev/urandom`. In fact it is arguably worse in several ways. Read [this](http://www.2uo.de/myths-about-urandom/). – Thomas Pornin Oct 23 '14 at 10:47
22

Some fab suggestions in the other answers. I find that makepasswd is not available everywhere, and using tr is (slightly) tricky, so there's another option using OpenSSL:

openssl rand -base64 16

The number is the number of bytes of randomness - so 16 bytes for 128-bits of entropy.

paj28
  • 32,736
  • 8
  • 92
  • 130
  • Example result: `WZ+HURTPwSsdQFTzaZ4edA==`. I don't think it's a *readable password* because of the two `=`. – A.L Oct 21 '14 at 09:31
  • 7
    Well you just read them... Regardless, they're not actually part of the password, as they encode zero entropy. – OrangeDog Oct 21 '14 at 10:22
  • Base64 has 64 possible characters while there are in fact 95 printable characters. Would not recommend. – Luc Oct 21 '14 at 19:18
  • 6
    @Luc Using 95 characters reduces the password length from 22 to 20 characters. Not a big difference. – CodesInChaos Oct 22 '14 at 07:54
12

Using pwgen

Simplest oneliner ever:

pwgen

It attempts to make passwords that are easy to remember. To disable that and create more secure passwords, use the --secure or -s flag.

pwgen -s

Are the generated passwords too long? Too short? Just append the desired length:

pwgen 9
# Or
pwgen -s 9
# Or
pwgen 9 -s

Similar tools

I just happen to know pwgen, there are other tools out there. You can find them using the search function from your distribution. In Debian this is:

apt-cache search password generator

It does do an exact (though case-insensitive) search. Using password generat instead broadens the search.

Before installing the package it can be useful to view its description. Again in Debian:

apt-cache show $DESIRED_PACKAGE
# E.g.
apt-cache show pwgen

Tools that I could find this way:

  • pwgen
  • makepasswd
  • apg
  • otp (meant for one-time pads, not recommended)
  • gpw (focuses heavily on pronounceability, not recommended)

Using standard Unix tools

Not all systems may have pwgen available. Like others have answered, you can use md5sum or sha256sum, but that only outputs 0-9 and a-f. No g-z or mixed case, let alone special characters. It's better to simply filter out non-printable characters from /dev/urandom until you have a password of the desired length:

cat /dev/urandom | tr -cd '@-~' | head -c 8

Which gives something like XiVsdn[y or V@FPV^lY. You can change the 8 at the end for the desired password length. You can also change the @-~ part to limit the characters. For example this will only print alphanumeric characters:

cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 8

This is almost identical to what pwgen -s would do and gives passwords like nZiUzNtE.

As a bonus, the tr tool is included in almost every operating system (Mac OS X, GNU/Linux, Android/Linux, Solaris, FreeBSD, etc.) except Microsoft Windows.

Luc
  • 31,973
  • 8
  • 71
  • 135
  • `cat /dev/urandom | tr -cd '[a-zA-Z0-9]' | head -c 8` also lets `[` and `]` (GNU coreutils 8.25). For alphanumeric output you need `cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 8`. Could you edit it? I can't edit less than 6 characters. – Yağmur Oymak Sep 19 '17 at 06:26
10

Depending on the type of characters you may include, an easy command to create a readable password with 128 bits of entropy looks like this:

< /dev/urandom tr -dc [:graph:] | head -c20; echo;

(Taken from here). [:graph:] are all ascii pritable characters except space.

Explanation:

128 bits are equivalent to 3.40e+38 combinations. If you're using the 94 readable ascii characters (except space), you'd need 20 characters to reach at least that amount of combinations: 94^20 = 2.90e+39.

If, for example, you're only allowed to use _A-Za-z0-9:

< /dev/urandom tr -dc '_A-Za-z0-9' | head -c22; echo;

For 63 possible characters: 63^22 = 3.85e+39. It only adds two characters to reach full entropy.

For hexadecimal passwords:

< /dev/urandom tr -dc 'A-F0-9' | head -c32; echo;

Hexadecimal is easy: 128 bits are 32 times the bits of a hexadecimal character.

Important notice: Most of the situations where you need a password, you'll be using a hash function behind, which will actually derive the real string which will be used. This analysis is subject to the way the password is hashed/used.

Additional note: /dev/urandom is secure for this operation. Please check Is a rand from /dev/urandom secure for a login key?.

Additional note: If you're using more than one iteration with a hash function, you can substract the bits needed to express the iteration of the total amounts of bits you can to reach, e.g.:

65536 iterations = 2^16 iterations, add roughly 16 bits (2 bytes) of entropy to the choosen password, because in a brute force attack, you need to perform 2^16 additional iterations before calculating the used hash.

Just for the record, going beyond 128 bits of entropy, is unnecerary as explained here: Amount of simple operations that is safely out of reach for all humanity?

But if your paranoia goes beyond that, here are some useful numbers:

All ascii readable (29 characters, 1.6e+57 combinations), 192 bits (6.28e+57 combinations) of entropy:

< /dev/urandom tr -dc [:graph:] | head -c29; echo;

_A-Za-z0-9 (32 characters, 3.79e+57 combinations), 192 bits (6.28e+57 combinations) of entropy:

< /dev/urandom tr -dc '_A-Za-z0-9' | head -c32; echo;

A-F0-9 (48 characters, 16^48 combinations), 192 bits (2^192 combinations) of entropy:

< /dev/urandom tr -dc 'A-F0-9' | head -c48; echo;

All ascii readable (39 characters, 8.95e+76 combinations), 256 bits (1.16e+77 combinations) of entropy:

< /dev/urandom tr -dc [:graph:] | head -c39; echo;

_A-Za-z0-9 (43 characters, 2.35e+77 combinations), 256 bits (1.16e+77 combinations) of entropy:

< /dev/urandom tr -dc '_A-Za-z0-9' | head -c43; echo;

A-F0-9 (64 characters, 16^64 combinations), 256 bits (2^256 combinations) of entropy:

< /dev/urandom tr -dc 'A-F0-9' | head -c64; echo;

Considering the last six options are already paranoid, it's completely pointless choosing complexer or larger passwords than the ones described above.

Andras Gyomrey
  • 821
  • 3
  • 9
  • 17
5

A one-liner to create a readable and relatively easy-to-remember password:

cat /usr/share/dict/words | shuf -n 4 | tr '\n' ' '| tr -d \'

Example output:

correct horse battery staple

If you want a longer password, change the 4 to a higher number. For a password without spaces, add an escaped space to the end of the line:

cat /usr/share/dict/words | shuf -n 4 | tr '\n' ' ' | tr -d \ \'
OrangeDog
  • 274
  • 3
  • 15
ONOZ
  • 151
  • 2
  • 3
    Nice idea, but in order to have the required 128 bits of entropy, you’d rather need `shuf -n 8 --random-source=/dev/urandom` (assuming the dictionary contains > 2^16 words; mine has ~99k). Also, `cat` is redundant here. – Emil Jeřábek Oct 21 '14 at 21:33
  • 2
    It depends on the version of coreutils/`shuf`, it *used* to use `/dev/urandom`, this was *undone* in the shared randread code (affecting multiple tools) in coreutils-7.3 due to [poor performance of `shred`](http://savannah.gnu.org/patch/?6797). Insert face in palm. – mr.spuratic Oct 22 '14 at 09:45
3

There is a package called makepasswd which can do this.

 $ makepasswd --chars 64
Fred Concklin
  • 821
  • 8
  • 15
1

I would use apg with 16-byte seed from /dev/urandom (maximum allowed)

apg -a 0 -d -m 15 -n 1 -c "`head -c16 /dev/urandom`"; echo

You can chain the apg commands so you can have longer password from more entropy.

Erbureth
  • 111
  • 2
1

For the random information to be readable, we can encode it in base64. One character in base64 has 6 bits of entropy. Thus, for 128 bits of entropy you need 22 characters (128/6=21+⅓).

This leads us to the command:

base64 < /dev/urandom | head -c 22

Which can be translated in English by "generate cryptographic quality random data with /dev/urandom and convert it to base64, keep the first 22 characters".

You might want to add an extra "end of line" character at the end of the output:

echo $(base64 < /dev/urandom | head -c 22)
  • Very similar to my `function password_generate { head -c ${1-12} /dev/urandom | base64; }`. – TRiG Oct 21 '14 at 19:53
0
uuidgen

will provide you with a UUID; remember to check which version of UUID it generates on your computer as some versions will allow someone who snoops your password to track it to your computer, which may (probably is) a security issue. You can use

uuidgen -r

to make sure that the ID only consists of random(ish) digits and cannot be tracked to you. The string will consist of [a-z0-9] and -. Example ouput:

4bc1b05b-77b5-4a4c-8300-e9dc53350fcb

The quality of the string depends on your operating system's ability to generate random numbers (/dev/random).

A.L
  • 302
  • 3
  • 12
Clearer
  • 111
  • 3
  • 1
    A uuid of type random only has 122 bits of entropy (4 bits used for the version + 2 reserved bits). See [wikipedia description](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29). – Ángel Oct 22 '14 at 11:17
  • It does. I still think it's usefull. I use uuidgen to generate unique symbols for headerguard instead of relying on filename (which may clash) or #pragma once and as a password generator, it's fairly simple to use. – Clearer Oct 29 '14 at 21:46
0

I know you asked for one line, but it's really more robust with more. ;-)

The major work can be compressed down to one line if you want to eliminate the error checking and compatibility across different versions of the base64 utility; this implementation works on both OS X and Linux. (see the create_password function, and replace do_base64 with just plain base64 with the appropriate arguments.) You could replace the do_base64 function with your own function for selecting ASCII characters based on a binary input, but using base64 (with a sed to eliminate the /, +, and =) this gets you uppercase, lowercase, and numbers. (26 + 26 + 10 = 62; not sure which 94 characters you meant.)

Specify the password length you want as the argument.

#!/bin/bash

function abort {
    echo "Error: $*"
    exit 2
}

function do_base64 {
    WRAP=""
    base64 --help | grep -q -- --wrap && WRAP="-w 0"
    base64 $WRAP $@
}

function create_password {
    let bytes=$1*2
    dd if=/dev/urandom 2> /dev/null bs=$bytes count=1 \
        | do_base64 \
        | sed s/[\/\+=]//g \
        | cut -c 1-${1}
}

if [ "$1" == "" ]; then
    echo "Usage: $0 <desired-password-length>"
    exit 1
fi
let length=0+"$1" 2> /dev/null || abort "Password length must be numeric"

create_password $1

Example output:

$ mkpasswd 16
2LjxTkQHP7Lv4z0J

$ mkpasswd 24
txhhbeHfGZSl0UNRvsz78yFo

$ mkpasswd 64
TykZF3hMXcZp0rP4ig0d9zRsuVEDxHjIcLHGcNaf0ROhk66VCPc7tE8GXcVv7AKh

Also, you'll probably want to replace /dev/urandom with /dev/random if you care about getting proper entropy. (I changed it to /dev/urandom during development since my entropy pool was exhausted.)

mpontillo
  • 131
  • 3
0

Here's a function that builds a password with a minimum of 128 bits of entropy using random numbers between 33 and 126.

pgen() {
    local start=33 end=126 # printable, non-whitespace characters
    local entropy=128

    # Calculate minimum length to meet required entropy
    local length=$(echo "($entropy/(l($((end+1-start)))/l(2)))" | bc -l)
    length=$(echo "scale=0; ($length+0.5)/1" | bc) # round result up

    # Use $1 as length if it has enough entropy
    [ -n "$1" ] && [ $1 -gt $length 2>/dev/null ] && length=$1

    for _ in $(seq $length); do
        printf \\$(printf '%03o' \
            $(shuf --random-source=/dev/urandom -i $start-$end -n1))
    done
    echo
}

The function calculates the minimum length required to meet entropy requirements (length of 20 in this case) and outputs password of that length.

The first argument may specify the length of the password written to stdout, as long as it is greater than the minimum length to meet the entropy requirement.

$ pgen
xx6r6e%Og;_8<4)o#aPO
John B
  • 109
  • 3
  • 1
    DO NOT USE $RANDOM. It is in no way cryptographically secure. This applies to bash, zsh, and probably all the others (dash, ash, ksh, etc). It uses numbers which are seeded from the time of day XORed with the PID, sent through an LCG. You would have to patch bash with something like this in order to (opportunistically) make $RANDOM not utterly, trivially predictable: https://bpaste.net/show/67b8eb752dbc – forest Apr 08 '16 at 02:18
  • @forest Agreed. Much naivety in the original answer. The updated answer uses a better source. – John B Apr 08 '16 at 05:34
  • (Original link broke: https://bpaste.net/show/6243826650c3) – forest Apr 08 '16 at 07:38