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 to not 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:
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.
When you store the user's password on the computer, encrypt it.
If nothing else, use the crypt() library function. Use random numbers to choose the password's salt. When the user provides a password, check to see if it is the original password by encrypting the provided password with the same salt.
For example, the following bit of a simple Perl code takes a password in the $password variable, generates a random salt, and places an encrypted password in the variable $encrypted_password:
$salts="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; srand(time); local($s1) = rand(64); local($s2) = rand(64); $salt = substr($salts,$s1,1) . substr($salts,$s2,1); $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($new_password, $encrypted_password){ print "password matched.\n";}
If you need access to crypt() from a shell script, consider using /usr/lib/makekey, which provides much the same functionality.
Instead of using the crypt() function to store an encrypted password, consider using a cryptographic hash function such as MD5. Using a cryptographic hash allows the user to type a password (or, properly, a passphrase) of any length.
This technique is the one that PGP uses for encrypting files with "conventional cryptography," as well as for encrypting the secret key that is stored on your hard disk. When you type in a passphrase, this phrase is processed with the MD5 message digest algorithm (described in Chapter 6). The resulting 128-bit hash is used as the key for the IDEA encryption algorithm.
If you need to be able to verify a password, but you do not need an encryption key, you can store the MD5 hash. When you need to verify the user's password, take the new value entered by the user, compute the value's MD5, and see if the new MD5 matches the stored value.
As with the crypt() function, you can include a random salt with the passphrase. If you do so, you must record the salt with the saved MD5 and use it whenever you wish to verify the user's password.
The primary benefit to using a cryptographic hash value is that it takes whatever input the user types as the password, no matter how long that output might be. [13] This may encourage users to type longer passwords or passphrases that will be resistant to dictionary attacks. You might also remind them of this practice when you prompt them for new passwords.
[13] But remember to check for buffer overflow when reading the password.