Encrypting Passwords with Perl

Example Code | Verifying Passwords | Uncrypting Passwords

Password hashes must not be generated with algorithms such as Digest::MD5 or Digest::SHA1, as these do not implement salting and other security measures required by passwords. Instead, use the built-in Perl crypt function or the Crypt::PasswdMD5 module to produce hashes. Examples of the legacy Unix Data Encryption Standard (DES) and newer Message Digest Algorithm #5 (MD5) encrypted passwords are shown below.

des lRk62l2WdzX1k
md5 $1$43SgvNjO$5a68aNBxASAChyjBZ3hj2/

Modern Unix systems have updated the system crypt(3) function to also generate MD5 password hashs. If the Perl program will be used on many different operating systems, use the module Crypt::PasswdMD5, as this should be more portable. Consider also the excellent Crypt::Eksblowfish::Bcrypt devised by Niels Provos and David Mazieres for OpenBSD. Alternatives to passwords include Kerberos, SSH public key authentication, or cookie-based web authentication, or by increasing the number of authentication factors required: password and a secure token, or the password and a biometric check.

Example Code

The crypt-example program demonstrates how to generate legacy DES password hashes and MD5 hashes. The code is duplicated below. Avoid using crypt with DES passwords, if possible.

#!/usr/bin/perl -wl
use strict;

use Crypt::PasswdMD5 qw(unix_md5_crypt);
my @salt = ( '.', '/', 0 .. 9, 'A' .. 'Z', 'a' .. 'z' );

# this takes password as argument: good for simple example, bad for
# security (perldoc -q password)
my $password = shift || die "usage: $0 password";

my %encrypted;

# generate traditional (weak!) DES password, and more modern md5
$encrypted{des} = crypt( $password, gensalt(2) );
$encrypted{md5} = unix_md5_crypt( $password, gensalt(8) );

print "$_ $encrypted{$_}" for sort keys %encrypted;

# uses global @salt to construct salt string of requested length
sub gensalt {
my $count = shift;

my $salt;
for (1..$count) {
$salt .= (@salt)[rand @salt];
}

return $salt;
}

Verifying Passwords

The crypt function documentation covers how to verify a password against an encrypted password. Briefly:

#!/usr/bin/perl -l
print "match" if crypt('password', 'QQjYbirnCGD7A') eq 'QQjYbirnCGD7A';

Uncrypting Passwords

Brute force methods must be used to determine the password for a given password hash, if the plaintext password has been forgotten or otherwise lost, and no means exists to reset the password. Be sure to consult the security policy, if any, to see whether and if so how password cracking is allowed in a company. Research the “Intel versus Randal Schwartz” court case for an example of a negative management reaction towards password cracking.

The legacy Unix DES password hash can be brute forced very quickly by modern systems. MD5 password hashes will likewise suffer the same fate. Other implementations—OpenBSD Blowfish, for example—offer configurable means of increasing the cost to verify a password, which should help thwart or delay brute force attacks, though these implementations may not be easily portable to other operating systems or custom Perl programs.