How to generate (random) and store (key-derived) passwords in Linux (using pwgen/apg/makepasswd/mkpasswd and crypt/bcrypt/scrypt)

Password strength is a measure of the effectiveness of a password in resisting guessing and brute-force attacks. They should not be repeated hence cryptographically secure random or one-time password.

Generating passwords/strings

# generates a base64 encoded 32 chars length random string
$ openssl rand -base64 32
  • pwgen@man generates pronounceable random (using /dev/urandom) passwords which are designed to be easily memorized by humans, while being as secure as possible.
$ yum install pwgen (EPEL) | apt-get install pwgen | pacman -S pwgen

'-s,--secure' generate completely random, hard-to-memorize passwords
'-B,--ambiguous' dont use characters 'I,1,O,0' that could be confused when printed
'-N,--num-passwords=NUM' number of passwords to generate
'-y,--symbols' include at least one special character in the password
# generate 2 passwords of 20 chars length each (default is 8)
$ pwgen -n 2 20

from pwgen@tecmint and pwgen@nixcraft

  • apg@man generates random passwords using pronounceable password generation algorithm (default) or /dev/urandom.
$ apt-get install apg | yum install apg | pacman -S apg

'-a ALG' 0 for pronounceable or 1 for urandom
'-n NUM' number of passwords to generate
'-m MIN, -x MAX' min/max password length
'-E CHARS' exclude chars from password
'-M MODE' 'S/s' must/should include special chars, 'N/n' numeral, 'C/c' capital, 'L/l' lowercase
'-r DICTFILE' check against a dictionary file
'-y' print encrypted password using crypt(3)
'-t' print pronunciation
$ apg -n 1 -t
  • makepasswd@ubuntu is a perl script that generates random (using /dev/urandom as seed) passwords with the emphasis on security over pronounceability. Optionally it also hashes/encrypts using crypt(3) des or md5.
$ apt-get install makepasswd | pacman -S makepasswd
# note (el/fedora): rawhide's makepasswd is a different program, same idea but in in C also using /dev/random and crypt(3)

'-chars N' password length (default is 10)
'--count N' number of passwords to generate
'-string STRING' uses chars in STRING to generate random password
# generates 2 passwords of 20 chars each
$ makepasswd --char 20 --count 2

'--clearfrom FILE' use tpassword from FILE instead of generating passwords
'--crypt' generates encrypted passwords
'--crypt-md5' encrypts using MD5 (default to DES)
'--cryptsalt N' uses crypt() salt N, defaults to 0 (random seeds)
# encrypt a password (instead of generating)
$ cat PASSWORD > pwd.txt
$ makepasswd --clearfrom pwd.txt --crypt

from makepasswd@tecmint and makepasswd@nixcraft

$ apt-get install expect | yum install expect | pacman -S expect
# note(deb/ubuntu): mkpasswd (from whois) is just a crypt(3) wrapper, use expect_mkpasswd instead

# generates a 10 char password and applies to current user
$ ?expect_?mkpasswd -l 10 $USER

from mkpasswd@tecmint and mkpasswd@nixcraft

Using key derivation functions (to store passwords)

Passwords should not be stored as plain-text, but instead be stored as result of key derivation functions. Basically a hash with a salt (a long random string that needn’t be kept secret) called many times.

passwd@wki is used to change user’s password. It is stored in /etc/shadow file encrypted/hashed by crypt(3). Format is $id$salt$encrypted where $id$ is $1$ for MD5, $2$ for blowfish, $5$ for SHA-256 and $6$ for SHA-512(default).

  • openssl dgst digest/hash functions output the message digest of a supplied file or files in hexadecimal.
# sha512 hash a script
$ echo -n STRING | openssl dgst -sha512
  • crypt(3) is the traditional Unix key derivation function. It uses DES by default, but also supports others.
# using deb/ubuntu mkpasswd (from whois), a crypt(3) wrapper
# SHA-512/crypt a password using given a salt
$(deb) mkpasswd PASSWORD -s SALTSASLT -m SHA-512

# DES/crypt a password using a random salt
$ openssl passwd -crypt PASSWORD
  • pbkdf2 is a key derivation function that is part of RSA. It applies a pseudorandom function, such as a cryptographic hash, cipher, or HMAC to the input password along with a salt value and repeats the process many times to produce a derived key. OpenSSL’s PKCS5_PBKDF2_HMAC is one implementation.
$ vi pbkdf2.c
/* usage:  % $0 password salt 1024 56 | openssl base64 */
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <openssl/evp.h>
int main(int argc, char *argv[])
    const char *usage = "usage: %s <password> <salt> <iterations> <keylen>";
    if (argc != 5) errx(1, usage, argv[0]);
    const char *pass = argv[1], *salt = argv[2]; 
    int iter = (int)strtol(argv[3], (char **)NULL, 10);
    int keylen = (int)strtol(argv[4], (char **)NULL, 10);

    unsigned char *out = malloc(keylen);
    PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass), salt, strlen(salt), iter, keylen, out); 
    return (write(1, out, keylen) == -1) ? 1: 0;

from pbkdf2.c

# blowfish in CFB mode, prompts for password
$ openssl enc -base64 -e -bf -in <infile> -out <outfile>
$ yum install scrypt | apt-get install scrypt | pacman -S scrypt 

# prompts for password 
$ scrypt enc infile outfile