### 32.3 Encrypting Passwords

— Function: char * crypt (const char *key, const char *salt)

> Preliminary: | MT-Unsafe race:crypt | AS-Unsafe corrupt lock heap dlopen | AC-Unsafe lock mem | See POSIX Safety Concepts.

> The `crypt` function takes a password, key, as a string, and a salt character array which is described below, and returns a printable ASCII string which starts with another salt. It is believed that, given the output of the function, the best way to find a key that will produce that output is to guess values of key until the original value of key is found.

> The salt parameter does two things. Firstly, it selects which algorithm is used, the MD5-based one or the DES-based one. Secondly, it makes life harder for someone trying to guess passwords against a file containing many passwords; without a salt, an intruder can make a guess, run `crypt` on it once, and compare the result with all the passwords. With a salt, the intruder must run `crypt` once for each different salt.

> For the MD5-based algorithm, the salt should consist of the string `$1$`, followed by up to 8 characters, terminated by either another `$` or the end of the string. The result of `crypt` will be the salt, followed by a `$` if the salt didn't end with one, followed by 22 characters from the alphabet `./0-9A-Za-z`, up to 34 characters total. Every character in the key is significant.

> For the DES-based algorithm, the salt should consist of two characters from the alphabet `./0-9A-Za-z`, and the result of `crypt` will be those two characters followed by 11 more from the same alphabet, 13 in total. Only the first 8 characters in the key are significant.

> The MD5-based algorithm has no limit on the useful length of the password used, and is slightly more secure. It is therefore preferred over the DES-based algorithm.

> When the user enters their password for the first time, the salt should be set to a new string which is reasonably random. To verify a password against the result of a previous call to `crypt`, pass the result of the previous call as the salt.

The following short program is an example of how to use `crypt` the first time a password is entered. Note that the salt generation is just barely acceptable; in particular, it is not unique between machines, and in many applications it would not be acceptable to let an attacker know what time the user's password was last set.

         #include <stdio.h>
         #include <time.h>
         #include <unistd.h>
         #include <crypt.h>

         int
         main(void)
         {
           unsigned long seed[2];
           char salt[] = "$1$........";
           const char *const seedchars =
             "./0123456789ABCDEFGHIJKLMNOPQRST"
             "UVWXYZabcdefghijklmnopqrstuvwxyz";
           char *password;
           int i;

           /* Generate a (not very) random seed.
              You should do it better than this... */
           seed[0] = time(NULL);
           seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000);

           /* Turn it into printable characters from `seedchars'. */
           for (i = 0; i < 8; i++)
             salt[3+i] = seedchars[(seed[i/5] >> (i%5)*6) & 0x3f];

           /* Read in the user's password and encrypt it. */
           password = crypt(getpass("Password:"), salt);

           /* Print the results. */
           puts(password);
           return 0;
         }

The next program shows how to verify a password. It prompts the user for a password and prints “Access granted.” if the user types `GNU libc manual`.

         #include <stdio.h>
         #include <string.h>
         #include <unistd.h>
         #include <crypt.h>

         int
         main(void)
         {
           /* Hashed form of "GNU libc manual". */
           const char *const pass = "$1$/iSaq7rB$EoUw5jJPPvAPECNaaWzMK/";

           char *result;
           int ok;

           /* Read in the user's password and encrypt it,
              passing the expected password in as the salt. */
           result = crypt(getpass("Password:"), pass);

           /* Test the result. */
           ok = strcmp (result, pass) == 0;

           puts(ok ? "Access granted." : "Access denied.");
           return ok ? 0 : 1;
         }

— Function: char * crypt_r (const char *key, const char *salt, struct crypt_data * data)

> Preliminary: | MT-Safe | AS-Unsafe corrupt lock heap dlopen | AC-Unsafe lock mem | See POSIX Safety Concepts.

> The `crypt_r` function does the same thing as `crypt`, but takes an extra parameter which includes space for its result (among other things), so it can be reentrant. `data->initialized` must be cleared to zero before the first time `crypt_r` is called.

> The `crypt_r` function is a GNU extension.

The `crypt` and `crypt_r` functions are prototyped in the header `crypt.h`.