home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Previous Section Next Section

16.6 Tips on Using Passwords

Lots of computer programs use passwords for user authentication. Beyond the standard Unix password, users soon find that they have passwords for special electronic mail accounts, special accounting programs, and even fantasy role-playing games.

Few users are good at memorizing passwords, and there is a great temptation to use a single password for all uses. This is a bad idea. Users should be encouraged not to type their login password into some MUD that's running over at the local university, for example.

As a programmer, there are several steps that you can take in programs that ask for passwords to make the process more secure:

  1. Don't echo the password as the user types it. Normally, Unix turns off echo when people type passwords. You can do this yourself by using the getpass( ) function. In recent years, however, a trend has evolved to echo asterisks (*) for each character of the password typed. This provides some help for the person typing the password to see if they have made a mistake in their typing, but it also enables somebody looking over the user's shoulders to see how many characters are in the password.

  2. When you store the user's password on the computer, concatenate a key and a salt, and encrypt the password with a cryptographically secure one-way function. Never have programs store passwords in plaintext form in files or databases. If this file is compromised, all of the passwords need to be changed!

    Traditionally, the easy way to store a password on a Unix system was to use the Unix crypt( ) library function with a randomly generated salt. For example, the following bit of simple Perl code takes a password in the $password variable, generates a random salt, and places an encrypted password in the variable $encrypted_password:[20]

    [20] This functionality can be accessed from a shell script using the program /usr/lib/makekey or /usr/libexec/makekey if you have it.

    my $salts="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
    my $s1 = rand(64);
    my $s2 = rand(64);
    my $salt = substr($salts,$s1,1) . substr($salts,$s2,1);
    my $encrypted_password = crypt($password,$salt);

    You can then check to see if a newly provided password is in fact the encrypted password with this simple Perl fragment:

    if($encrypted_password eq crypt($entered_password, $encrypted_password) {
      print "password matched.\n";
    }

    This code fragment can be significantly improved by rewriting it to use the MD5 message digest algorithm:

    use Digest::MD5 qw(md5_base64);
    
    my $salts="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
    my $key  ="justakey";
    
    my $s1 = rand(64);
    my $s2 = rand(64);
    my $salt = substr($salts,$s1,1) . substr($salts,$s2,1);
    my $encrypted_password = $salt . md5_base64("$salt/$password/$key");

    To verify this password, we would use:

    use Digest::MD5 qw(md5_base64);
    
    my $salts= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
    my $key  ="justakey";
    
    my $salt = substr($encrypted_password,0,2);
    my $pw2 = $salt . md5_base64("$salt/$entered_password/$key");
    
    if($encrypted_password eq $pw2) {
        print "passwords match.\n";
    }

The primary benefit of using a cryptographic hash value is that it takes whatever input the user types as the password, no matter how long that value might be. This may encourage users to type longer passwords or passphrases that will be more resistant to dictionary attacks. You might also want to remind them of this practice when you prompt them for new passwords.

    Previous Section Next Section