TUCoPS :: Password Security :: pwhack.txt

A few Unix password hackers

/*   Found and distributed by Sauron 
 *   This file contains two unix password hackers, found on a local
 *   system.  Apparently they were written for sysops to test their
 *   systems - and that's all we're doing, right?
*/
/*   pverify - A Unix System Password Security Checker
 *
 *   This procedure is intended for those who are concerned
 *   about password security. As more Unix applications, notably
 *   uucp and sendmail, are made more secure, the weak link in
 *   system security remains the user-chosen password.
 *
 *   This program reports on users whose passwords are "suspect":
 *   too easily guessable.
 *
 *   Usage (on Berkeley Unix)
 *        cc -O pverify.c -o pverify
 *        nohup nice -20 pverify > p.out &
 *        chmod 600 p.out
 *        /etc/renice 20 -p `ps aux | egrep "[0-9] pverify | awk '{print $2}'
 *
 *   Monitor progress with: tail -f 100 p.out
 */
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/times.h>
#include <sys/param.h>

#define MAXWORD 30

char *crypt();
char fname[80];
char storage[64];
char pass[64];

struct passwd *getpwent();
struct passwd *pptr;
char reduced[40], two[3];
char notreduced[40];

FILE *fp;
char *fgets();
char word[MAXWORD];

main(argc,argv)
int argc;
char **argv;
{
    register i;
    int usercnt,found,crypts;
    long tim;
    struct tms clock1,clock2;

    usercnt = found = crypts = 0;
    fp = fopen("/usr/dict/words","r");
    pptr = getpwent();
    times(&clock1);
    while (pptr != NULL) {
        usercnt++;
        printf("Investigating user %s\n",pptr->pw_name); fflush(stdout);
        strcpy(notreduced,pptr->pw_passwd);
        for (i = 0; i < strlen(pptr->pw_passwd); i++) {
            if (i >= 2)
                reduced[i-2] = pptr->pw_passwd[i];
            if (i < 2)
                two[i] = pptr->pw_passwd[i];
        }
        while (fgets(word,MAXWORD,fp) != NULL) {
            word[strlen(word)-1] = NULL;
            if (strlen(word) >= 6) {    /* check only words of right length */
              if (strcmp(crypt(word,two),notreduced) == 0) {
                 printf("\t*** %s %s ***\n",pptr->pw_name,word);
                 found++;
              }
              crypts++;
           }
        }
        fseek(fp,0,0);
        pptr = getpwent();
    }
    times(&clock2);
    endpwent();
    printf("Statistics: Found %d in %d users (%3.1f%%)\n",
        found,usercnt,((float)found/(float)usercnt)*100.0);
    tim =       (float)(clock2.tms_utime+clock2.tms_stime -
                clock1.tms_utime-clock1.tms_stime) / (float)HZ;
    printf("Statistics: Time used: %d, Crypts: %d, Time per crypt: %4.2f\n",
        tim, crypts, tim / (float)crypts);
}

-------------------cut here------------------------------------------
 
#include <stdio.h>
#include <pwd.h>
#include <ctype.h>

/*
 * Warning: this program burns a lot of cpu.
 */
/*
 * Insecure - find accounts with poor passwords
        Date: Tue, 29 Nov 83 18:19:32 pst
        From: leres%ucbarpa@Berkeley (Craig Leres)
            Modified by Seth Alford, Roger Southwick, Steve Dum, and
            Rick Lindsley for Tektronix
 */

/*
 *      $Log:   pwchkr.c,v $
 *      Revision 1.1  85/09/10  16:00:56  root
 *      Initial revision
 *
 *
 * By default, this program only checks for accounts with passwords the same
 * as the login name. The following options add more extensive checking. (The
 * tradeoff is cpu time -- with all options enabled it can run into the 100's
 * of MINUTES.) Any argument that does not begin with a "-" is assumed to be
 * a file name. (A single '-' means stdin.) If no file name is given,
 * /etc/passwd is used.
 *
 * Options:
 *
 *              -v:     verbose -- list all guesses on stdout
 *              -u:     output the username on the line of the password file
 *                      currently being checked. If the program stops
 *                      abruptly you will then know how far it got.
 *              -w file: use the list of words contained in "file" as likely
 *                      passwords. Words in the file are one to a line.
 *              -b:     check all guesses backwards too
 *              -g:     use the Full Name portion of the gecos field to
 *                      generate more guesses
 *              -s:     check the single letters a-z, A-Z, 0-9 as passwords
 *              -c:     with each guess, check for all-lowercase and
 *                      all-uppercase versions too.
 *              -n:     complain about null passwords (default is to keep quiet)
 *              -p:     print the password when guessed
 */

int verbose = 0, singles = 0, backwards = 0, checkgecos = 0, checkcase = 0,
    chknulls = 0, printit = 0, users = 0, chkwords = 0;

char *index(),*reverse();
long atol();
FILE *fopen();
char *fgets();

char PASSWD[] = "/etc/passwd";
char EMPTY[] = "";
static FILE *pwf = NULL, *wlf = NULL;
char line[BUFSIZ+1];
char    *Curpw, *Wordlist = NULL;

main(argc, argv)
char **argv;
{
    register int i;
    register char *arg;
    int onedone = 0;

    for (i = 1; i < argc; i++)
        if ((arg = argv[i]) && *arg == '-')
            while (*++arg) {
                switch (*arg) {
                    case 'n':
                        /*
                         * complain about null passwords
                         */
                        chknulls++;
                        break;
                    case 'c':
                        /*
                         * check cases
                         */
                        checkcase++;
                        break;
                    case 'g':
                        /*
                         * use gecos
                         */
                        checkgecos++;
                        break;
                    case 'v':
                        /*
                         * turn on motormouth
                         */
                        verbose++;
                        break;
                    case 'b':
                        /*
                         * check all attempts forwards and backwards
                         */
                        backwards++;
                        break;
                    case 's':
                        /*
                         * carry out a more intensive search, checking for
                         * single letter passwords
                         */
                        singles++;
                        break;
                    case 'p':
                        /*
                         * print out the password when found
                         */
                        printit++;
                        break;
                    case 'u':
                        /*
                         * print out users as testing
                         */
                        users++;
                        break;
                    case 'w':
                        /*
                         * consult word list of likely passwords
                         */
                        if ((Wordlist = argv[i+1]) == NULL) {
                            fprintf(stderr,
                                "%s: No file supplied with -w option\n",
                                argv[0]);
                            exit (1);
                            }
                        argv[i+1] = NULL;
                        break;
                    case '\0':
                        /*
                         * read from stdin
                         */
                        break;
                    default:
                        fprintf(stderr,
                            "%s: unknown option '%c'. Options are:\n",argv[0],
                            *arg);
                        /* FALL THRU */
                    case '-':
                        fprintf(stderr,"-v:\t\tverbose -- list all guesses on stdout\n");
                        fprintf(stderr,"-u:\t\toutput the username currently being checked\n");
                        fprintf(stderr,"-w file:\tconsult the indicated file for words to check as passwords\n");
                        fprintf(stderr,"-b:\t\tcheck all guesses forwards and backwards\n");
                        fprintf(stderr,"-g:\t\tuse the Full name portion of the gecos field for more guesses\n");
                        fprintf(stderr,"-s:\t\tcheck the single letters a-z, A-Z, 0-9 as passwords\n");
                        fprintf(stderr,"-c:\t\tcheck the all-upper and all-lower case version of each guess\n");
                        fprintf(stderr,"-n:\t\tcomplain about null passwords\n");
                        fprintf(stderr,"-p:\t\tprint the password when guessed\n");
                        exit(1);
                    }
                argv[i] = NULL;
                }

    for (i = 1; i < argc; i++) {
        if (argv[i] == NULL) continue;
        onedone++;
        if (*(argv[i]) == '-') {
            /*
             * read from stdin; we'll cheat and set pwf directly
             */
            pwf = stdin;
            chkpw();
            /*
             * don't fclose stdin!
             */
            clearerr(stdin);
            }
        else {
            if (setpwent(argv[i])) {
                perror(argv[i]);
                continue;
                }
            Curpw = argv[i];
            chkpw();
            endpwent();
            }
        }
    if (!onedone) {
        Curpw = NULL;
        chkpw();
        }
    exit(0);
}

#define ARB_CONST       100

chkpw()

{
    register char       *cp, *cp2;
    register struct passwd *pwd;
    struct passwd       *getpwent();
    char                guess[100];
    char                *wordarray[ARB_CONST];
    char                *malloc(), **wordptr, **endptr;
    int                 done = 0;


    if (Wordlist)
    {
        if ((wlf = fopen(Wordlist,"r")) == NULL)
        {
            perror(Wordlist);
            exit(1);
        }

        wordptr = wordarray;
        /*
         * note that endptr points to space OUTSIDE of wordarray
         */
        endptr = wordarray + (sizeof(wordarray)/sizeof(char *));

        while (fscanf(wlf,"%[^\n]\n",guess) != EOF)
        {
            if (wordptr == endptr)
            {
                fprintf(stderr,"Ran out of wordlist space. ARB_CONST %d must be too small.\n", ARB_CONST);
                exit(1);
            }
            if ((*wordptr = malloc(1+strlen(guess))) == NULL)
            {
                fprintf(stderr,"malloc: no more memory for wordlist\n");
                exit (1);
            }
            strcpy(*wordptr,guess);
            wordptr++;
        }
        *wordptr = NULL;
    }

    while ((pwd = getpwent()) != 0 ) {

        if (verbose || users) {
            if (Curpw == NULL)
                printf("\t%s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);
            else
                printf("%s -- \t%s \"%s\"\n", Curpw, pwd->pw_name,
                    pwd->pw_gecos);
            fflush(stdout);
            }
        if (*pwd->pw_passwd == '\0') {
            if (chknulls) {
                if (Curpw == NULL)
                    printf("Problem: null passwd:\t%s\tshell: %s\n",
                        pwd->pw_name, pwd->pw_shell);
                else
                    printf("%s -- Problem: null passwd:\t%s\tshell: %s\n",
                        Curpw, pwd->pw_name, pwd->pw_shell);
                fflush(stdout);
                }
            continue;
        }
        /*
         * Try the user's login name
         */
        if (uandltry(pwd,pwd->pw_name))
            continue;

        /*
         * Try names from the gecos field
         */
        if (checkgecos) {
            strcpy(guess, pwd->pw_gecos);
            cp = guess;
            if (*cp == '-') cp++;               /* special gecos field */
            if ((cp2 = index(cp, ';')) != NULL)
                *cp2 = '\0';

            for (;;) {
                if ((cp2 = index(cp, ' ')) == NULL) {
                    if (uandltry(pwd,cp)) done++;
                    break;
                }

                *cp2 = '\0';

                if (uandltry(pwd,cp)) {
                    done++;
                    break;
                    }
                cp = ++cp2;
                }
            }

        if (!done && Wordlist)
        {
            /*
             * try the words in the wordlist
             */
            wordptr = wordarray;
            while (endptr != wordptr)
            {
                if (*wordptr == NULL)
                    break;
                if (uandltry(pwd,*wordptr++))
                {
                    done++;
                    break;
                }
            }
        }
        if (!done && singles) {
            /*
             * Try all single letters
             * (try digits too .  --Seth)
             */
            guess[1] = '\0';
            for (guess[0]='a'; guess[0] <= 'z'; guess[0]++)
                if (try(pwd,guess))
                    break;
            for (guess[0]='A'; guess[0] <= 'Z'; guess[0]++)
                if (try(pwd,guess))
                    break;
            for (guess[0]='0'; guess[0] <= '9'; guess[0]++)
                if (try(pwd,guess))
                    break;
            }
    }
}

/*
 * Stands for "upper and lower" try.  Calls the "real" try, below,
 * with the supplied version of the password, and with
 * an upper and lowercase version of the password. If the user doesn't
 * want to try upper and lower case then we just return after the one
 * check.
*/

uandltry (pwd,guess)
char *guess;
struct passwd *pwd;
{
    register char *cp;
    char buf[100];
    int alllower, allupper;

    alllower = allupper = 1;

    if (try(pwd,guess) || (backwards && try(pwd,reverse(guess)))) return (1);

    if (!checkcase) return(0);

    strcpy (buf, guess);
    cp = buf-1;
    while (*++cp) {
        if (isupper(*cp))
            alllower = 0;
        if (islower(*cp))
            allupper = 0;
        }

    if (!allupper) {
        for ( cp=buf; *cp != '\0'; cp++)
            if (islower (*cp))
                *cp += 'A' - 'a';

        if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
        }

    if (!alllower) {
        for ( cp = buf; *cp != '\0'; cp++)
            if (isupper (*cp))
                *cp += 'a' - 'A';

        if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
        }
    return (0);
}

try(pwd,guess)
char *guess;
register struct passwd *pwd;
{
    register char  *cp;
    char   *crypt ();

    if (verbose) {
        if (Curpw == NULL)
            printf ("Trying \"%s\" on %s\n", guess, pwd -> pw_name);
        else
            printf ("%s -- Trying \"%s\" on %s\n", Curpw, guess,
                pwd -> pw_name);
        fflush (stdout);
        }
    if (! guess || ! *guess) return(0);
    cp = crypt (guess, pwd -> pw_passwd);
    if (strcmp (cp, pwd -> pw_passwd))
        return (0);
    if (Curpw == NULL)
        if (printit)
            printf ("Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
                pwd -> pw_name, pwd -> pw_shell, guess);
        else
            printf ("Problem: Guessed:\t%s\tshell: %s\n", pwd -> pw_name,
                pwd -> pw_shell);
    else
        if (printit)
            printf ("%s -- Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
                Curpw, pwd -> pw_name, pwd -> pw_shell, guess);
        else
            printf ("%s -- Problem: Guessed:\t%s\tshell: %s\n",
                Curpw, pwd -> pw_name, pwd -> pw_shell);
    fflush (stdout);
    return (1);
}
/* end of PW guessing program */

#define MAXUID 0x7fff   /* added by tonyb 12/29/83 */
                        /* altered to a reasonable number - mae 8/20/84 */

/*
 * Add a parameter to "setpwent" so I can override the file name.
 */

setpwent(file)
char *file;
{
        if ((pwf = fopen(file,"r")) == NULL)
            return(1);
        return(0);
}

endpwent()

{
    fclose(pwf);
    pwf = NULL;
}

char *
pwskip(p)
register char *p;
{
        while(*p && *p != ':' && *p != '\n')
                ++p;
        if(*p == '\n')
                *p = '\0';
        else if(*p)
                *p++ = '\0';
        return(p);
}

struct passwd *
getpwent()
{
        static struct passwd passwd;
        register char *p;
        long    x;

        if(pwf == NULL)
            if (setpwent(PASSWD)) {
                perror(PASSWD);
                return(NULL);
                }
        p = fgets(line, BUFSIZ, pwf);
        if(p == NULL)
                return(0);
        passwd.pw_name = p;
        p = pwskip(p);
        passwd.pw_passwd = p;
        p = pwskip(p);
        x = atol(p);
        passwd.pw_uid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
        p = pwskip(p);
        x = atol(p);
        passwd.pw_gid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
        passwd.pw_comment = EMPTY;
        p = pwskip(p);
        passwd.pw_gecos = p;
        p = pwskip(p);
        passwd.pw_dir = p;
        p = pwskip(p);
        passwd.pw_shell = p;
        (void) pwskip(p);

        p = passwd.pw_passwd;

        return(&passwd);

}


/*
 * reverse a string
 */
char *reverse(str)
char *str;

{
    register char *ptr;
    register int len;
    char        *malloc();

    if ((ptr = malloc((len = strlen(str))+1)) == NULL)
        return(NULL);
    ptr += len;
    *ptr = '\0';
    while (*str && (*--ptr = *str++))
        ;
    return(ptr);
}


char *index(ptr,c)
char    c,*ptr;
{
        while (*ptr != c) {
                if (*ptr++ == '\0') return((char *)0L);
        }
        return(ptr);
}


/*
 * This program implements the
 * Proposed Federal Information Processing
 *  Data Encryption Standard.
 * See Federal Register, March 17, 1975 (40FR12134)
 */

/*
 * Initial permutation,
 */
static  char    IP[] = {
        58,50,42,34,26,18,10, 2,
        60,52,44,36,28,20,12, 4,
        62,54,46,38,30,22,14, 6,
        64,56,48,40,32,24,16, 8,
        57,49,41,33,25,17, 9, 1,
        59,51,43,35,27,19,11, 3,
        61,53,45,37,29,21,13, 5,
        63,55,47,39,31,23,15, 7,
};

/*
 * Final permutation, FP = IP^(-1)
 */
static  char    FP[] = {
        40, 8,48,16,56,24,64,32,
        39, 7,47,15,55,23,63,31,
        38, 6,46,14,54,22,62,30,
        37, 5,45,13,53,21,61,29,
        36, 4,44,12,52,20,60,28,
        35, 3,43,11,51,19,59,27,
        34, 2,42,10,50,18,58,26,
        33, 1,41, 9,49,17,57,25,
};

/*
 * Permuted-choice 1 from the key bits
 * to yield C and D.
 * Note that bits 8,16... are left out:
 * They are intended for a parity check.
 */
static  char    PC1_C[] = {
        57,49,41,33,25,17, 9,
         1,58,50,42,34,26,18,
        10, 2,59,51,43,35,27,
        19,11, 3,60,52,44,36,
};

static  char    PC1_D[] = {
        63,55,47,39,31,23,15,
         7,62,54,46,38,30,22,
        14, 6,61,53,45,37,29,
        21,13, 5,28,20,12, 4,
};

/*
 * Sequence of shifts used for the key schedule.
*/
static  char    shifts[] = {
        1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,
};

/*
 * Permuted-choice 2, to pick out the bits from
 * the CD array that generate the key schedule.
 */
static  char    PC2_C[] = {
        14,17,11,24, 1, 5,
         3,28,15, 6,21,10,
        23,19,12, 4,26, 8,
        16, 7,27,20,13, 2,
};

static  char    PC2_D[] = {
        41,52,31,37,47,55,
        30,40,51,45,33,48,
        44,49,39,56,34,53,
        46,42,50,36,29,32,
};

/*
 * The C and D arrays used to calculate the key schedule.
 */

static  char    C[28];
static  char    D[28];
/*
 * The key schedule.
 * Generated from the key.
 */
static  char    KS[16][48];

/*
 * Set up the key schedule from the key.
 */

setkey(key)
char *key;
{
        register i, j, k;
        int t;

        /*
         * First, generate C and D by permuting
         * the key.  The low order bit of each
         * 8-bit char is not used, so C and D are only 28
         * bits apiece.
         */
        for (i=0; i<28; i++) {
                C[i] = key[PC1_C[i]-1];
                D[i] = key[PC1_D[i]-1];
        }
        /*
         * To generate Ki, rotate C and D according
         * to schedule and pick up a permutation
         * using PC2.
         */
        for (i=0; i<16; i++) {
                /*
                 * rotate.
                 */
                for (k=0; k<shifts[i]; k++) {
                        t = C[0];
                        for (j=0; j<28-1; j++)
                                C[j] = C[j+1];
                        C[27] = t;
                        t = D[0];
                        for (j=0; j<28-1; j++)
                                D[j] = D[j+1];
                        D[27] = t;
                }
                /*
                 * get Ki. Note C and D are concatenated.
                 */
                for (j=0; j<24; j++) {
                        KS[i][j] = C[PC2_C[j]-1];
                        KS[i][j+24] = D[PC2_D[j]-28-1];
                }
        }
}

/*
 * The E bit-selection table.
 */
static  char    E[48];
static  char    e[] = {
        32, 1, 2, 3, 4, 5,
         4, 5, 6, 7, 8, 9,
         8, 9,10,11,12,13,
        12,13,14,15,16,17,
        16,17,18,19,20,21,
        20,21,22,23,24,25,
        24,25,26,27,28,29,
        28,29,30,31,32, 1,
};

/*
 * The 8 selection functions.
 * For some reason, they give a 0-origin
 * index, unlike everything else.
 */
static  char    S[8][64] = {
        14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
         0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
         4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
        15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13,

        15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
         3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
         0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
        13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9,

        10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
        13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
        13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
         1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12,

         7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
        13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
        10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
         3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14,

         2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
        14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
         4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
        11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3,

        12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
        10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8,
         9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
         4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13,

         4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
        13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6,
         1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
         6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12,

        13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
         1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
         7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
         2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11,
};

/*
 * P is a permutation on the selected combination
 * of the current L and key.
 */
static  char    P[] = {
        16, 7,20,21,
        29,12,28,17,
         1,15,23,26,
         5,18,31,10,
         2, 8,24,14,
        32,27, 3, 9,
        19,13,30, 6,
        22,11, 4,25,
};

/*
 * The current block, divided into 2 halves.
 */
static  char    L[32], R[32];
static  char    tempL[32];
static  char    f[32];

/*
 * The combination of the key and the input, before selection.
 */
static  char    preS[48];

/*
 * The payoff: encrypt a block.
 */

encrypt(block, edflag)
char *block;
{
        int i, ii;
        register t, j, k;

        /*
         * First, permute the bits in the input
         */
        for (j=0; j<64; j++)
                L[j] = block[IP[j]-1];
        /*
         * Perform an encryption operation 16 times.
         */
        for (ii=0; ii<16; ii++) {
                /*
                 * Set direction
                 */
                if (edflag)
                        i = 15-ii;
                else
                        i = ii;
                /*
                 * Save the R array,
                 * which will be the new L.
                 */
                for (j=0; j<32; j++)
                        tempL[j] = R[j];
                /*
                 * Expand R to 48 bits using the E selector;
                 * exclusive-or with the current key bits.
                 */
                for (j=0; j<48; j++)
                        preS[j] = R[E[j]-1] ^ KS[i][j];
                /*
                 * The pre-select bits are now considered
                 * in 8 groups of 6 bits each.
                 * The 8 selection functions map these
                 * 6-bit quantities into 4-bit quantities
                 * and the results permuted
                 * to make an f(R, K).
                 * The indexing into the selection functions
                 * is peculiar; it could be simplified by
                 * rewriting the tables.
                 */
                for (j=0; j<8; j++) {
                        t = 6*j;
                        k = S[j][(preS[t+0]<<5)+
                                (preS[t+1]<<3)+
                                (preS[t+2]<<2)+
                                (preS[t+3]<<1)+
                                (preS[t+4]<<0)+
                                (preS[t+5]<<4)];
                        t = 4*j;
                        f[t+0] = (k>>3)&01;
                        f[t+1] = (k>>2)&01;
                        f[t+2] = (k>>1)&01;
                        f[t+3] = (k>>0)&01;
                }
                /*
                 * The new R is L ^ f(R, K).
                 * The f here has to be permuted first, though.
                 */
                for (j=0; j<32; j++)
                        R[j] = L[j] ^ f[P[j]-1];
                /*
                 * Finally, the new L (the original R)
                 * is copied back.
                 */
                for (j=0; j<32; j++)
                        L[j] = tempL[j];
        }
        /*
         * The output L and R are reversed.
         */
        for (j=0; j<32; j++) {
                t = L[j];
                L[j] = R[j];
                R[j] = t;
        }
        /*
         * The final output
         * gets the inverse permutation of the very original.
         */
        for (j=0; j<64; j++)
                block[j] = L[FP[j]-1];
}

char *
crypt(pw,salt)
char *pw;
char *salt;
{
        register i, j, c;
        int temp;
        static char block[66], iobuf[16];
        for(i=0; i<66; i++)
                block[i] = 0;
        for(i=0; (c= *pw) && i<64; pw++){
                for(j=0; j<7; j++, i++)
                        block[i] = (c>>(6-j)) & 01;
                i++;
        }
        
        setkey(block);
        
        for(i=0; i<66; i++)
                block[i] = 0;

        for(i=0;i<48;i++)
                E[i] = e[i];

        for(i=0;i<2;i++){
                c = *salt++;
                iobuf[i] = c;
                if(c>'Z') c -= 6;
                if(c>'9') c -= 7;
                c -= '.';
                for(j=0;j<6;j++){
                        if((c>>j) & 01){
                                temp = E[6*i+j];
                                E[6*i+j] = E[6*i+j+24];
                                E[6*i+j+24] = temp;
                                }
                        }
                }
        
        for(i=0; i<25;"[V-)jR$H            encrypt(block,0);
        
        for(i=0; i<11; i++){
                c = 0;
                for(j=0; j<6; j++){
                        c <<= 1;
                        c |= block[6*i+j];
                        }
                c += '.';
                if(c>'9') c += 7;
                if(c>'Z') c += 6;
                iobuf[i+2] = c;
        }
        iobuf[i+2] = 0;
        if(iobuf[1]==0)
                iobuf[1] = iobuf[0];
        return(iobuf);
}

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH