Encrypting Passwords using Crypt()

Encrypting Passwords using crypt()


Theory:

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

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.*/


Function: char * crypt_r (const char *key, const char *salt, struct crypt_data * data)
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.

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//   C program:
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    char salt[] = "$1$abcdefgh"; /* This should be random */
    char *password;

    printf("salt is : %s\n", salt);

    /* Read in the user's password and encrypt it. */

    printf("##################################################################\n");
    printf("Enter Original Password\n");
    password = crypt(getpass("Password:"), salt);
    printf("##################################################################\n");

    /* Print the results. */
    puts(password);
    char original_pass[50] = {0};
    strcpy(original_pass, password);


    printf("##################################################################\n");
    char *cur_passwd;
    printf("Enter password same as original password\n");
    cur_passwd = crypt(getpass("Password:"), password);
    /* Print the results. */
    puts(cur_passwd);
    printf("##################################################################\n");

    printf("\n\nCompare Now: Original password: %s Current Password: %s", original_pass, cur_passwd);

    if (strcmp(original_pass, cur_passwd) == 0)
    {
        printf("\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
        printf("****************** PASSWORD MATCH *****************\n");
        printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    } else {
        printf("\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
        printf("\nCurrent Password and Original Password Don't Match\n");
        printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    }

    return 0;
}

Compilation:
gcc -o crypt crypt.c  -lcrypt

Output:

Password match Case:
Neelkanth_221$ ./crypt
salt is : $1$abcdefgh
##################################################################
Enter Original Password
Password:
##################################################################
$1$abcdefgh$Qlx6NNORPMsnE3/ehfisr1
##################################################################
Enter password same as original password
Password:
$1$abcdefgh$Qlx6NNORPMsnE3/ehfisr1
##################################################################


Compare Now: Original password: $1$abcdefgh$Qlx6NNORPMsnE3/ehfisr1 Current Password: $1$abcdefgh$Qlx6NNORPMsnE3/ehfisr1

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
****************** PASSWORD MATCH *****************
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Password No-match Case:

Neelkanth_221$ ./crypt
salt is : $1$abcdefgh
##################################################################
Enter Original Password
Password:
##################################################################
$1$abcdefgh$Qlx6NNORPMsnE3/ehfisr1
##################################################################
Enter password same as original password
Password:
$1$abcdefgh$e.zGC9egaBizsEd9YFd.C.
##################################################################


Compare Now: Original password: $1$abcdefgh$Qlx6NNORPMsnE3/ehfisr1 Current Password: $1$abcdefgh$e.zGC9egaBizsEd9YFd.C.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Current Password and Original Password Don't Match
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@