home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / hacking / unix / pwhack.hac < prev    next >
Encoding:
Text File  |  2003-06-11  |  27.5 KB  |  990 lines

  1. /*   Found and distributed by Sauron 
  2.  *   This file contains two unix password hackers, found on a local
  3.  *   system.  Apparently they were written for sysops to test their
  4.  *   systems - and that's all we're doing, right?
  5. */
  6. /*   pverify - A Unix System Password Security Checker
  7.  *
  8.  *   This procedure is intended for those who are concerned
  9.  *   about password security. As more Unix applications, notably
  10.  *   uucp and sendmail, are made more secure, the weak link in
  11.  *   system security remains the user-chosen password.
  12.  *
  13.  *   This program reports on users whose passwords are "suspect":
  14.  *   too easily guessable.
  15.  *
  16.  *   Usage (on Berkeley Unix)
  17.  *        cc -O pverify.c -o pverify
  18.  *        nohup nice -20 pverify > p.out &
  19.  *        chmod 600 p.out
  20.  *        /etc/renice 20 -p `ps aux | egrep "[0-9] pverify | awk '{print $2}'
  21.  *
  22.  *   Monitor progress with: tail -f 100 p.out
  23.  */
  24. #include <stdio.h>
  25. #include <pwd.h>
  26. #include <sys/types.h>
  27. #include <sys/times.h>
  28. #include <sys/param.h>
  29.  
  30. #define MAXWORD 30
  31.  
  32. char *crypt();
  33. char fname[80];
  34. char storage[64];
  35. char pass[64];
  36.  
  37. struct passwd *getpwent();
  38. struct passwd *pptr;
  39. char reduced[40], two[3];
  40. char notreduced[40];
  41.  
  42. FILE *fp;
  43. char *fgets();
  44. char word[MAXWORD];
  45.  
  46. main(argc,argv)
  47. int argc;
  48. char **argv;
  49. {
  50.     register i;
  51.     int usercnt,found,crypts;
  52.     long tim;
  53.     struct tms clock1,clock2;
  54.  
  55.     usercnt = found = crypts = 0;
  56.     fp = fopen("/usr/dict/words","r");
  57.     pptr = getpwent();
  58.     times(&clock1);
  59.     while (pptr != NULL) {
  60.         usercnt++;
  61.         printf("Investigating user %s\n",pptr->pw_name); fflush(stdout);
  62.         strcpy(notreduced,pptr->pw_passwd);
  63.         for (i = 0; i < strlen(pptr->pw_passwd); i++) {
  64.             if (i >= 2)
  65.                 reduced[i-2] = pptr->pw_passwd[i];
  66.             if (i < 2)
  67.                 two[i] = pptr->pw_passwd[i];
  68.         }
  69.         while (fgets(word,MAXWORD,fp) != NULL) {
  70.             word[strlen(word)-1] = NULL;
  71.             if (strlen(word) >= 6) {    /* check only words of right length */
  72.               if (strcmp(crypt(word,two),notreduced) == 0) {
  73.                  printf("\t*** %s %s ***\n",pptr->pw_name,word);
  74.                  found++;
  75.               }
  76.               crypts++;
  77.            }
  78.         }
  79.         fseek(fp,0,0);
  80.         pptr = getpwent();
  81.     }
  82.     times(&clock2);
  83.     endpwent();
  84.     printf("Statistics: Found %d in %d users (%3.1f%%)\n",
  85.         found,usercnt,((float)found/(float)usercnt)*100.0);
  86.     tim =       (float)(clock2.tms_utime+clock2.tms_stime -
  87.                 clock1.tms_utime-clock1.tms_stime) / (float)HZ;
  88.     printf("Statistics: Time used: %d, Crypts: %d, Time per crypt: %4.2f\n",
  89.         tim, crypts, tim / (float)crypts);
  90. }
  91.  
  92. -------------------cut here------------------------------------------
  93.  
  94. #include <stdio.h>
  95. #include <pwd.h>
  96. #include <ctype.h>
  97.  
  98. /*
  99.  * Warning: this program burns a lot of cpu.
  100.  */
  101. /*
  102.  * Insecure - find accounts with poor passwords
  103.         Date: Tue, 29 Nov 83 18:19:32 pst
  104.         From: leres%ucbarpa@Berkeley (Craig Leres)
  105.             Modified by Seth Alford, Roger Southwick, Steve Dum, and
  106.             Rick Lindsley for Tektronix
  107.  */
  108.  
  109. /*
  110.  *      $Log:   pwchkr.c,v $
  111.  *      Revision 1.1  85/09/10  16:00:56  root
  112.  *      Initial revision
  113.  *
  114.  *
  115.  * By default, this program only checks for accounts with passwords the same
  116.  * as the login name. The following options add more extensive checking. (The
  117.  * tradeoff is cpu time -- with all options enabled it can run into the 100's
  118.  * of MINUTES.) Any argument that does not begin with a "-" is assumed to be
  119.  * a file name. (A single '-' means stdin.) If no file name is given,
  120.  * /etc/passwd is used.
  121.  *
  122.  * Options:
  123.  *
  124.  *              -v:     verbose -- list all guesses on stdout
  125.  *              -u:     output the username on the line of the password file
  126.  *                      currently being checked. If the program stops
  127.  *                      abruptly you will then know how far it got.
  128.  *              -w file: use the list of words contained in "file" as likely
  129.  *                      passwords. Words in the file are one to a line.
  130.  *              -b:     check all guesses backwards too
  131.  *              -g:     use the Full Name portion of the gecos field to
  132.  *                      generate more guesses
  133.  *              -s:     check the single letters a-z, A-Z, 0-9 as passwords
  134.  *              -c:     with each guess, check for all-lowercase and
  135.  *                      all-uppercase versions too.
  136.  *              -n:     complain about null passwords (default is to keep quiet)
  137.  *              -p:     print the password when guessed
  138.  */
  139.  
  140. int verbose = 0, singles = 0, backwards = 0, checkgecos = 0, checkcase = 0,
  141.     chknulls = 0, printit = 0, users = 0, chkwords = 0;
  142.  
  143. char *index(),*reverse();
  144. long atol();
  145. FILE *fopen();
  146. char *fgets();
  147.  
  148. char PASSWD[] = "/etc/passwd";
  149. char EMPTY[] = "";
  150. static FILE *pwf = NULL, *wlf = NULL;
  151. char line[BUFSIZ+1];
  152. char    *Curpw, *Wordlist = NULL;
  153.  
  154. main(argc, argv)
  155. char **argv;
  156. {
  157.     register int i;
  158.     register char *arg;
  159.     int onedone = 0;
  160.  
  161.     for (i = 1; i < argc; i++)
  162.         if ((arg = argv[i]) && *arg == '-')
  163.             while (*++arg) {
  164.                 switch (*arg) {
  165.                     case 'n':
  166.                         /*
  167.                          * complain about null passwords
  168.                          */
  169.                         chknulls++;
  170.                         break;
  171.                     case 'c':
  172.                         /*
  173.                          * check cases
  174.                          */
  175.                         checkcase++;
  176.                         break;
  177.                     case 'g':
  178.                         /*
  179.                          * use gecos
  180.                          */
  181.                         checkgecos++;
  182.                         break;
  183.                     case 'v':
  184.                         /*
  185.                          * turn on motormouth
  186.                          */
  187.                         verbose++;
  188.                         break;
  189.                     case 'b':
  190.                         /*
  191.                          * check all attempts forwards and backwards
  192.                          */
  193.                         backwards++;
  194.                         break;
  195.                     case 's':
  196.                         /*
  197.                          * carry out a more intensive search, checking for
  198.                          * single letter passwords
  199.                          */
  200.                         singles++;
  201.                         break;
  202.                     case 'p':
  203.                         /*
  204.                          * print out the password when found
  205.                          */
  206.                         printit++;
  207.                         break;
  208.                     case 'u':
  209.                         /*
  210.                          * print out users as testing
  211.                          */
  212.                         users++;
  213.                         break;
  214.                     case 'w':
  215.                         /*
  216.                          * consult word list of likely passwords
  217.                          */
  218.                         if ((Wordlist = argv[i+1]) == NULL) {
  219.                             fprintf(stderr,
  220.                                 "%s: No file supplied with -w option\n",
  221.                                 argv[0]);
  222.                             exit (1);
  223.                             }
  224.                         argv[i+1] = NULL;
  225.                         break;
  226.                     case '\0':
  227.                         /*
  228.                          * read from stdin
  229.                          */
  230.                         break;
  231.                     default:
  232.                         fprintf(stderr,
  233.                             "%s: unknown option '%c'. Options are:\n",argv[0],
  234.                             *arg);
  235.                         /* FALL THRU */
  236.                     case '-':
  237.                         fprintf(stderr,"-v:\t\tverbose -- list all guesses on stdout\n");
  238.                         fprintf(stderr,"-u:\t\toutput the username currently being checked\n");
  239.                         fprintf(stderr,"-w file:\tconsult the indicated file for words to check as passwords\n");
  240.                         fprintf(stderr,"-b:\t\tcheck all guesses forwards and backwards\n");
  241.                         fprintf(stderr,"-g:\t\tuse the Full name portion of the gecos field for more guesses\n");
  242.                         fprintf(stderr,"-s:\t\tcheck the single letters a-z, A-Z, 0-9 as passwords\n");
  243.                         fprintf(stderr,"-c:\t\tcheck the all-upper and all-lower case version of each guess\n");
  244.                         fprintf(stderr,"-n:\t\tcomplain about null passwords\n");
  245.                         fprintf(stderr,"-p:\t\tprint the password when guessed\n");
  246.                         exit(1);
  247.                     }
  248.                 argv[i] = NULL;
  249.                 }
  250.  
  251.     for (i = 1; i < argc; i++) {
  252.         if (argv[i] == NULL) continue;
  253.         onedone++;
  254.         if (*(argv[i]) == '-') {
  255.             /*
  256.              * read from stdin; we'll cheat and set pwf directly
  257.              */
  258.             pwf = stdin;
  259.             chkpw();
  260.             /*
  261.              * don't fclose stdin!
  262.              */
  263.             clearerr(stdin);
  264.             }
  265.         else {
  266.             if (setpwent(argv[i])) {
  267.                 perror(argv[i]);
  268.                 continue;
  269.                 }
  270.             Curpw = argv[i];
  271.             chkpw();
  272.             endpwent();
  273.             }
  274.         }
  275.     if (!onedone) {
  276.         Curpw = NULL;
  277.         chkpw();
  278.         }
  279.     exit(0);
  280. }
  281.  
  282. #define ARB_CONST       100
  283.  
  284. chkpw()
  285.  
  286. {
  287.     register char       *cp, *cp2;
  288.     register struct passwd *pwd;
  289.     struct passwd       *getpwent();
  290.     char                guess[100];
  291.     char                *wordarray[ARB_CONST];
  292.     char                *malloc(), **wordptr, **endptr;
  293.     int                 done = 0;
  294.  
  295.  
  296.     if (Wordlist)
  297.     {
  298.         if ((wlf = fopen(Wordlist,"r")) == NULL)
  299.         {
  300.             perror(Wordlist);
  301.             exit(1);
  302.         }
  303.  
  304.         wordptr = wordarray;
  305.         /*
  306.          * note that endptr points to space OUTSIDE of wordarray
  307.          */
  308.         endptr = wordarray + (sizeof(wordarray)/sizeof(char *));
  309.  
  310.         while (fscanf(wlf,"%[^\n]\n",guess) != EOF)
  311.         {
  312.             if (wordptr == endptr)
  313.             {
  314.                 fprintf(stderr,"Ran out of wordlist space. ARB_CONST %d must be too small.\n", ARB_CONST);
  315.                 exit(1);
  316.             }
  317.             if ((*wordptr = malloc(1+strlen(guess))) == NULL)
  318.             {
  319.                 fprintf(stderr,"malloc: no more memory for wordlist\n");
  320.                 exit (1);
  321.             }
  322.             strcpy(*wordptr,guess);
  323.             wordptr++;
  324.         }
  325.         *wordptr = NULL;
  326.     }
  327.  
  328.     while ((pwd = getpwent()) != 0 ) {
  329.  
  330.         if (verbose || users) {
  331.             if (Curpw == NULL)
  332.                 printf("\t%s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);
  333.             else
  334.                 printf("%s -- \t%s \"%s\"\n", Curpw, pwd->pw_name,
  335.                     pwd->pw_gecos);
  336.             fflush(stdout);
  337.             }
  338.         if (*pwd->pw_passwd == '\0') {
  339.             if (chknulls) {
  340.                 if (Curpw == NULL)
  341.                     printf("Problem: null passwd:\t%s\tshell: %s\n",
  342.                         pwd->pw_name, pwd->pw_shell);
  343.                 else
  344.                     printf("%s -- Problem: null passwd:\t%s\tshell: %s\n",
  345.                         Curpw, pwd->pw_name, pwd->pw_shell);
  346.                 fflush(stdout);
  347.                 }
  348.             continue;
  349.         }
  350.         /*
  351.          * Try the user's login name
  352.          */
  353.         if (uandltry(pwd,pwd->pw_name))
  354.             continue;
  355.  
  356.         /*
  357.          * Try names from the gecos field
  358.          */
  359.         if (checkgecos) {
  360.             strcpy(guess, pwd->pw_gecos);
  361.             cp = guess;
  362.             if (*cp == '-') cp++;               /* special gecos field */
  363.             if ((cp2 = index(cp, ';')) != NULL)
  364.                 *cp2 = '\0';
  365.  
  366.             for (;;) {
  367.                 if ((cp2 = index(cp, ' ')) == NULL) {
  368.                     if (uandltry(pwd,cp)) done++;
  369.                     break;
  370.                 }
  371.  
  372.                 *cp2 = '\0';
  373.  
  374.                 if (uandltry(pwd,cp)) {
  375.                     done++;
  376.                     break;
  377.                     }
  378.                 cp = ++cp2;
  379.                 }
  380.             }
  381.  
  382.         if (!done && Wordlist)
  383.         {
  384.             /*
  385.              * try the words in the wordlist
  386.              */
  387.             wordptr = wordarray;
  388.             while (endptr != wordptr)
  389.             {
  390.                 if (*wordptr == NULL)
  391.                     break;
  392.                 if (uandltry(pwd,*wordptr++))
  393.                 {
  394.                     done++;
  395.                     break;
  396.                 }
  397.             }
  398.         }
  399.         if (!done && singles) {
  400.             /*
  401.              * Try all single letters
  402.              * (try digits too .  --Seth)
  403.              */
  404.             guess[1] = '\0';
  405.             for (guess[0]='a'; guess[0] <= 'z'; guess[0]++)
  406.                 if (try(pwd,guess))
  407.                     break;
  408.             for (guess[0]='A'; guess[0] <= 'Z'; guess[0]++)
  409.                 if (try(pwd,guess))
  410.                     break;
  411.             for (guess[0]='0'; guess[0] <= '9'; guess[0]++)
  412.                 if (try(pwd,guess))
  413.                     break;
  414.             }
  415.     }
  416. }
  417.  
  418. /*
  419.  * Stands for "upper and lower" try.  Calls the "real" try, below,
  420.  * with the supplied version of the password, and with
  421.  * an upper and lowercase version of the password. If the user doesn't
  422.  * want to try upper and lower case then we just return after the one
  423.  * check.
  424. */
  425.  
  426. uandltry (pwd,guess)
  427. char *guess;
  428. struct passwd *pwd;
  429. {
  430.     register char *cp;
  431.     char buf[100];
  432.     int alllower, allupper;
  433.  
  434.     alllower = allupper = 1;
  435.  
  436.     if (try(pwd,guess) || (backwards && try(pwd,reverse(guess)))) return (1);
  437.  
  438.     if (!checkcase) return(0);
  439.  
  440.     strcpy (buf, guess);
  441.     cp = buf-1;
  442.     while (*++cp) {
  443.         if (isupper(*cp))
  444.             alllower = 0;
  445.         if (islower(*cp))
  446.             allupper = 0;
  447.         }
  448.  
  449.     if (!allupper) {
  450.         for ( cp=buf; *cp != '\0'; cp++)
  451.             if (islower (*cp))
  452.                 *cp += 'A' - 'a';
  453.  
  454.         if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
  455.         }
  456.  
  457.     if (!alllower) {
  458.         for ( cp = buf; *cp != '\0'; cp++)
  459.             if (isupper (*cp))
  460.                 *cp += 'a' - 'A';
  461.  
  462.         if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
  463.         }
  464.     return (0);
  465. }
  466.  
  467. try(pwd,guess)
  468. char *guess;
  469. register struct passwd *pwd;
  470. {
  471.     register char  *cp;
  472.     char   *crypt ();
  473.  
  474.     if (verbose) {
  475.         if (Curpw == NULL)
  476.             printf ("Trying \"%s\" on %s\n", guess, pwd -> pw_name);
  477.         else
  478.             printf ("%s -- Trying \"%s\" on %s\n", Curpw, guess,
  479.                 pwd -> pw_name);
  480.         fflush (stdout);
  481.         }
  482.     if (! guess || ! *guess) return(0);
  483.     cp = crypt (guess, pwd -> pw_passwd);
  484.     if (strcmp (cp, pwd -> pw_passwd))
  485.         return (0);
  486.     if (Curpw == NULL)
  487.         if (printit)
  488.             printf ("Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
  489.                 pwd -> pw_name, pwd -> pw_shell, guess);
  490.         else
  491.             printf ("Problem: Guessed:\t%s\tshell: %s\n", pwd -> pw_name,
  492.                 pwd -> pw_shell);
  493.     else
  494.         if (printit)
  495.             printf ("%s -- Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
  496.                 Curpw, pwd -> pw_name, pwd -> pw_shell, guess);
  497.         else
  498.             printf ("%s -- Problem: Guessed:\t%s\tshell: %s\n",
  499.                 Curpw, pwd -> pw_name, pwd -> pw_shell);
  500.     fflush (stdout);
  501.     return (1);
  502. }
  503. /* end of PW guessing program */
  504.  
  505. #define MAXUID 0x7fff   /* added by tonyb 12/29/83 */
  506.                         /* altered to a reasonable number - mae 8/20/84 */
  507.  
  508. /*
  509.  * Add a parameter to "setpwent" so I can override the file name.
  510.  */
  511.  
  512. setpwent(file)
  513. char *file;
  514. {
  515.         if ((pwf = fopen(file,"r")) == NULL)
  516.             return(1);
  517.         return(0);
  518. }
  519.  
  520. endpwent()
  521.  
  522. {
  523.     fclose(pwf);
  524.     pwf = NULL;
  525. }
  526.  
  527. char *
  528. pwskip(p)
  529. register char *p;
  530. {
  531.         while(*p && *p != ':' && *p != '\n')
  532.                 ++p;
  533.         if(*p == '\n')
  534.                 *p = '\0';
  535.         else if(*p)
  536.                 *p++ = '\0';
  537.         return(p);
  538. }
  539.  
  540. struct passwd *
  541. getpwent()
  542. {
  543.         static struct passwd passwd;
  544.         register char *p;
  545.         long    x;
  546.  
  547.         if(pwf == NULL)
  548.             if (setpwent(PASSWD)) {
  549.                 perror(PASSWD);
  550.                 return(NULL);
  551.                 }
  552.         p = fgets(line, BUFSIZ, pwf);
  553.         if(p == NULL)
  554.                 return(0);
  555.         passwd.pw_name = p;
  556.         p = pwskip(p);
  557.         passwd.pw_passwd = p;
  558.         p = pwskip(p);
  559.         x = atol(p);
  560.         passwd.pw_uid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
  561.         p = pwskip(p);
  562.         x = atol(p);
  563.         passwd.pw_gid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
  564.         passwd.pw_comment = EMPTY;
  565.         p = pwskip(p);
  566.         passwd.pw_gecos = p;
  567.         p = pwskip(p);
  568.         passwd.pw_dir = p;
  569.         p = pwskip(p);
  570.         passwd.pw_shell = p;
  571.         (void) pwskip(p);
  572.  
  573.         p = passwd.pw_passwd;
  574.  
  575.         return(&passwd);
  576.  
  577. }
  578.  
  579.  
  580. /*
  581.  * reverse a string
  582.  */
  583. char *reverse(str)
  584. char *str;
  585.  
  586. {
  587.     register char *ptr;
  588.     register int len;
  589.     char        *malloc();
  590.  
  591.     if ((ptr = malloc((len = strlen(str))+1)) == NULL)
  592.         return(NULL);
  593.     ptr += len;
  594.     *ptr = '\0';
  595.     while (*str && (*--ptr = *str++))
  596.         ;
  597.     return(ptr);
  598. }
  599.  
  600.  
  601. char *index(ptr,c)
  602. char    c,*ptr;
  603. {
  604.         while (*ptr != c) {
  605.                 if (*ptr++ == '\0') return((char *)0L);
  606.         }
  607.         return(ptr);
  608. }
  609.  
  610.  
  611. /*
  612.  * This program implements the
  613.  * Proposed Federal Information Processing
  614.  *  Data Encryption Standard.
  615.  * See Federal Register, March 17, 1975 (40FR12134)
  616.  */
  617.  
  618. /*
  619.  * Initial permutation,
  620.  */
  621. static  char    IP[] = {
  622.         58,50,42,34,26,18,10, 2,
  623.         60,52,44,36,28,20,12, 4,
  624.         62,54,46,38,30,22,14, 6,
  625.         64,56,48,40,32,24,16, 8,
  626.         57,49,41,33,25,17, 9, 1,
  627.         59,51,43,35,27,19,11, 3,
  628.         61,53,45,37,29,21,13, 5,
  629.         63,55,47,39,31,23,15, 7,
  630. };
  631.  
  632. /*
  633.  * Final permutation, FP = IP^(-1)
  634.  */
  635. static  char    FP[] = {
  636.         40, 8,48,16,56,24,64,32,
  637.         39, 7,47,15,55,23,63,31,
  638.         38, 6,46,14,54,22,62,30,
  639.         37, 5,45,13,53,21,61,29,
  640.         36, 4,44,12,52,20,60,28,
  641.         35, 3,43,11,51,19,59,27,
  642.         34, 2,42,10,50,18,58,26,
  643.         33, 1,41, 9,49,17,57,25,
  644. };
  645.  
  646. /*
  647.  * Permuted-choice 1 from the key bits
  648.  * to yield C and D.
  649.  * Note that bits 8,16... are left out:
  650.  * They are intended for a parity check.
  651.  */
  652. static  char    PC1_C[] = {
  653.         57,49,41,33,25,17, 9,
  654.          1,58,50,42,34,26,18,
  655.         10, 2,59,51,43,35,27,
  656.         19,11, 3,60,52,44,36,
  657. };
  658.  
  659. static  char    PC1_D[] = {
  660.         63,55,47,39,31,23,15,
  661.          7,62,54,46,38,30,22,
  662.         14, 6,61,53,45,37,29,
  663.         21,13, 5,28,20,12, 4,
  664. };
  665.  
  666. /*
  667.  * Sequence of shifts used for the key schedule.
  668. */
  669. static  char    shifts[] = {
  670.         1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,
  671. };
  672.  
  673. /*
  674.  * Permuted-choice 2, to pick out the bits from
  675.  * the CD array that generate the key schedule.
  676.  */
  677. static  char    PC2_C[] = {
  678.         14,17,11,24, 1, 5,
  679.          3,28,15, 6,21,10,
  680.         23,19,12, 4,26, 8,
  681.         16, 7,27,20,13, 2,
  682. };
  683.  
  684. static  char    PC2_D[] = {
  685.         41,52,31,37,47,55,
  686.         30,40,51,45,33,48,
  687.         44,49,39,56,34,53,
  688.         46,42,50,36,29,32,
  689. };
  690.  
  691. /*
  692.  * The C and D arrays used to calculate the key schedule.
  693.  */
  694.  
  695. static  char    C[28];
  696. static  char    D[28];
  697. /*
  698.  * The key schedule.
  699.  * Generated from the key.
  700.  */
  701. static  char    KS[16][48];
  702.  
  703. /*
  704.  * Set up the key schedule from the key.
  705.  */
  706.  
  707. setkey(key)
  708. char *key;
  709. {
  710.         register i, j, k;
  711.         int t;
  712.  
  713.         /*
  714.          * First, generate C and D by permuting
  715.          * the key.  The low order bit of each
  716.          * 8-bit char is not used, so C and D are only 28
  717.          * bits apiece.
  718.          */
  719.         for (i=0; i<28; i++) {
  720.                 C[i] = key[PC1_C[i]-1];
  721.                 D[i] = key[PC1_D[i]-1];
  722.         }
  723.         /*
  724.          * To generate Ki, rotate C and D according
  725.          * to schedule and pick up a permutation
  726.          * using PC2.
  727.          */
  728.         for (i=0; i<16; i++) {
  729.                 /*
  730.                  * rotate.
  731.                  */
  732.                 for (k=0; k<shifts[i]; k++) {
  733.                         t = C[0];
  734.                         for (j=0; j<28-1; j++)
  735.                                 C[j] = C[j+1];
  736.                         C[27] = t;
  737.                         t = D[0];
  738.                         for (j=0; j<28-1; j++)
  739.                                 D[j] = D[j+1];
  740.                         D[27] = t;
  741.                 }
  742.                 /*
  743.                  * get Ki. Note C and D are concatenated.
  744.                  */
  745.                 for (j=0; j<24; j++) {
  746.                         KS[i][j] = C[PC2_C[j]-1];
  747.                         KS[i][j+24] = D[PC2_D[j]-28-1];
  748.                 }
  749.         }
  750. }
  751.  
  752. /*
  753.  * The E bit-selection table.
  754.  */
  755. static  char    E[48];
  756. static  char    e[] = {
  757.         32, 1, 2, 3, 4, 5,
  758.          4, 5, 6, 7, 8, 9,
  759.          8, 9,10,11,12,13,
  760.         12,13,14,15,16,17,
  761.         16,17,18,19,20,21,
  762.         20,21,22,23,24,25,
  763.         24,25,26,27,28,29,
  764.         28,29,30,31,32, 1,
  765. };
  766.  
  767. /*
  768.  * The 8 selection functions.
  769.  * For some reason, they give a 0-origin
  770.  * index, unlike everything else.
  771.  */
  772. static  char    S[8][64] = {
  773.         14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
  774.          0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
  775.          4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
  776.         15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13,
  777.  
  778.         15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
  779.          3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
  780.          0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
  781.         13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9,
  782.  
  783.         10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
  784.         13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
  785.         13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
  786.          1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12,
  787.  
  788.          7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
  789.         13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
  790.         10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
  791.          3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14,
  792.  
  793.          2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
  794.         14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
  795.          4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
  796.         11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3,
  797.  
  798.         12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
  799.         10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8,
  800.          9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
  801.          4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13,
  802.  
  803.          4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
  804.         13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6,
  805.          1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
  806.          6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12,
  807.  
  808.         13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
  809.          1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
  810.          7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
  811.          2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11,
  812. };
  813.  
  814. /*
  815.  * P is a permutation on the selected combination
  816.  * of the current L and key.
  817.  */
  818. static  char    P[] = {
  819.         16, 7,20,21,
  820.         29,12,28,17,
  821.          1,15,23,26,
  822.          5,18,31,10,
  823.          2, 8,24,14,
  824.         32,27, 3, 9,
  825.         19,13,30, 6,
  826.         22,11, 4,25,
  827. };
  828.  
  829. /*
  830.  * The current block, divided into 2 halves.
  831.  */
  832. static  char    L[32], R[32];
  833. static  char    tempL[32];
  834. static  char    f[32];
  835.  
  836. /*
  837.  * The combination of the key and the input, before selection.
  838.  */
  839. static  char    preS[48];
  840.  
  841. /*
  842.  * The payoff: encrypt a block.
  843.  */
  844.  
  845. encrypt(block, edflag)
  846. char *block;
  847. {
  848.         int i, ii;
  849.         register t, j, k;
  850.  
  851.         /*
  852.          * First, permute the bits in the input
  853.          */
  854.         for (j=0; j<64; j++)
  855.                 L[j] = block[IP[j]-1];
  856.         /*
  857.          * Perform an encryption operation 16 times.
  858.          */
  859.         for (ii=0; ii<16; ii++) {
  860.                 /*
  861.                  * Set direction
  862.                  */
  863.                 if (edflag)
  864.                         i = 15-ii;
  865.                 else
  866.                         i = ii;
  867.                 /*
  868.                  * Save the R array,
  869.                  * which will be the new L.
  870.                  */
  871.                 for (j=0; j<32; j++)
  872.                         tempL[j] = R[j];
  873.                 /*
  874.                  * Expand R to 48 bits using the E selector;
  875.                  * exclusive-or with the current key bits.
  876.                  */
  877.                 for (j=0; j<48; j++)
  878.                         preS[j] = R[E[j]-1] ^ KS[i][j];
  879.                 /*
  880.                  * The pre-select bits are now considered
  881.                  * in 8 groups of 6 bits each.
  882.                  * The 8 selection functions map these
  883.                  * 6-bit quantities into 4-bit quantities
  884.                  * and the results permuted
  885.                  * to make an f(R, K).
  886.                  * The indexing into the selection functions
  887.                  * is peculiar; it could be simplified by
  888.                  * rewriting the tables.
  889.                  */
  890.                 for (j=0; j<8; j++) {
  891.                         t = 6*j;
  892.                         k = S[j][(preS[t+0]<<5)+
  893.                                 (preS[t+1]<<3)+
  894.                                 (preS[t+2]<<2)+
  895.                                 (preS[t+3]<<1)+
  896.                                 (preS[t+4]<<0)+
  897.                                 (preS[t+5]<<4)];
  898.                         t = 4*j;
  899.                         f[t+0] = (k>>3)&01;
  900.                         f[t+1] = (k>>2)&01;
  901.                         f[t+2] = (k>>1)&01;
  902.                         f[t+3] = (k>>0)&01;
  903.                 }
  904.                 /*
  905.                  * The new R is L ^ f(R, K).
  906.                  * The f here has to be permuted first, though.
  907.                  */
  908.                 for (j=0; j<32; j++)
  909.                         R[j] = L[j] ^ f[P[j]-1];
  910.                 /*
  911.                  * Finally, the new L (the original R)
  912.                  * is copied back.
  913.                  */
  914.                 for (j=0; j<32; j++)
  915.                         L[j] = tempL[j];
  916.         }
  917.         /*
  918.          * The output L and R are reversed.
  919.          */
  920.         for (j=0; j<32; j++) {
  921.                 t = L[j];
  922.                 L[j] = R[j];
  923.                 R[j] = t;
  924.         }
  925.         /*
  926.          * The final output
  927.          * gets the inverse permutation of the very original.
  928.          */
  929.         for (j=0; j<64; j++)
  930.                 block[j] = L[FP[j]-1];
  931. }
  932.  
  933. char *
  934. crypt(pw,salt)
  935. char *pw;
  936. char *salt;
  937. {
  938.         register i, j, c;
  939.         int temp;
  940.         static char block[66], iobuf[16];
  941.         for(i=0; i<66; i++)
  942.                 block[i] = 0;
  943.         for(i=0; (c= *pw) && i<64; pw++){
  944.                 for(j=0; j<7; j++, i++)
  945.                         block[i] = (c>>(6-j)) & 01;
  946.                 i++;
  947.         }
  948.         
  949.         setkey(block);
  950.         
  951.         for(i=0; i<66; i++)
  952.                 block[i] = 0;
  953.  
  954.         for(i=0;i<48;i++)
  955.                 E[i] = e[i];
  956.  
  957.         for(i=0;i<2;i++){
  958.                 c = *salt++;
  959.                 iobuf[i] = c;
  960.                 if(c>'Z') c -= 6;
  961.                 if(c>'9') c -= 7;
  962.                 c -= '.';
  963.                 for(j=0;j<6;j++){
  964.                         if((c>>j) & 01){
  965.                                 temp = E[6*i+j];
  966.                                 E[6*i+j] = E[6*i+j+24];
  967.                                 E[6*i+j+24] = temp;
  968.                                 }
  969.                         }
  970.                 }
  971.         
  972.         for(i=0; i<25;"[V-)jR$H            encrypt(block,0);
  973.         
  974.         for(i=0; i<11; i++){
  975.                 c = 0;
  976.                 for(j=0; j<6; j++){
  977.                         c <<= 1;
  978.                         c |= block[6*i+j];
  979.                         }
  980.                 c += '.';
  981.                 if(c>'9') c += 7;
  982.                 if(c>'Z') c += 6;
  983.                 iobuf[i+2] = c;
  984.         }
  985.         iobuf[i+2] = 0;
  986.         if(iobuf[1]==0)
  987.                 iobuf[1] = iobuf[0];
  988.         return(iobuf);
  989. }
  990.