35

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.

3
  • 4
    A few tools listed here. I use apg.
    – Sparhawk
    Oct 21, 2014 at 3:00
  • 2
    Can you please define readable password?Does it exclude numbers, or only non-alphanumeric characters?
    – A.L
    Oct 21, 2014 at 9:29
  • 3
    OSX/Mac: head -16 /dev/urandom | openssl sha1
    – Xeoncross
    Oct 23, 2014 at 15:03

11 Answers 11

55

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.

12
  • 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, 2014 at 7:55
  • 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. Oct 21, 2014 at 9: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, 2014 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. Oct 21, 2014 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, 2014 at 6:06
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.

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

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.

1
  • 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. Sep 19, 2017 at 6: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.

2
  • 1
    For all ASCII readable characters, you can make your tr command tr -dc '!-~', or even tr -dc '[:graph:]' Oct 21, 2014 at 21:50
  • 1
    Oh and you might want to explain the need for the ${1:-20} parameter expansion Oct 21, 2014 at 21:57
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 \ \'
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. Oct 21, 2014 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. Insert face in palm. Oct 22, 2014 at 9:45
3

There is a package called makepasswd which can do this.

 $ makepasswd --chars 64
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.

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)
1
  • Very similar to my function password_generate { head -c ${1-12} /dev/urandom | base64; }.
    – TRiG
    Oct 21, 2014 at 19:53
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.)

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).

2
  • 1
    A uuid of type random only has 122 bits of entropy (4 bits used for the version + 2 reserved bits). See wikipedia description.
    – Ángel
    Oct 22, 2014 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, 2014 at 21:46
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
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: bpaste.net/show/67b8eb752dbc
    – forest
    Apr 8, 2016 at 2:18
  • @forest Agreed. Much naivety in the original answer. The updated answer uses a better source.
    – John B
    Apr 8, 2016 at 5:34
  • (Original link broke: bpaste.net/show/6243826650c3)
    – forest
    Apr 8, 2016 at 7:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .