Category : UNIX Files
Archive   : KC910.ZIP
Filename : PASS.C

 
Output of file : PASS.C contained in archive : KC910.ZIP
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.
-x: check guesses with "funny" characters added on.
-[0-9]: Check for uppercase characters in an otherwise
all-lowercase guess.
-n: complain about null passwords (default is to keep quiet)
-i: check the student id number if one exists [Rutgers]
-p: print the password when guessed
*/


#define FDES 1
#include
#include
#include

int verbose = 0, singles = 0, backwards = 0, dictfile = 0,
checkgecos = 0, checkcase = 0, chknulls = 0, printit = 1,
users = 1, chkwords = 0, checkfchars = 0, chkid = 0,
num_uplow = 0;

char *fchars = "0123456789,<.>/?;:[{]}`~=+-_)(*&^%$#@! ";
int nums[10] = {0,0,0,0,0,0,0,0,0,0};

char *index(), *nreverse(); /* use *strchr() if need be */
long atol();
FILE *fopen();
char *fgets();

char PASSWD[] = "passwd";
char EMPTY[] = "";
static FILE *df = NULL, /* extended LARGE dictionary */
*pwf = NULL, /* passwd file */
*wlf = NULL, /* word list file */
*ulf = NULL; /* "users" file */

char line[BUFSIZ+1];
struct passwd passwd;
char *logid = NULL;
/* "Curpw" stuff nuked; using normal filename arg; faked here. */
char *Curpw = NULL;
char *Wordlist = NULL;
char nextc;

main(argc, argv)
char **argv;
{
register int i, c;
register char *arg;

/* root check nuked */

for (i = 1; i < argc; i++)
if (arg = argv[i]) /* not null */
if (*arg == '-') {
while (*++arg) {
if (isdigit ((int)*arg)) {
num_uplow++;
nums[*arg - '0']++;
} else {
switch (*arg) {
case 'i': /* check student id# */
chkid++;
break;
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 'x': /* extended check of 'funny' chars */
checkfchars++;
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;
default:
fprintf(stderr,
"%s: unknown option '%c'.\n",argv[0],*arg);
exit(1);
} /* switch */
} /* if digit */
} /* while arg */
} else {
/* no dash, must be a filename. */
/* They did "pwf = stdin;" originally to read stdin. */
if (setpwent (argv[i])) exit (0);
} /* if '-' */

/* cover our trax _H*/
for (i = 0; i <= argc; i++) argv[i] = NULL;
argv[0] = "*Security*";

chkpw();
endpwent();
exit(0);
}

#define ARB_CONST 16000

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

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) > 0)
{
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 ) {

done = 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;
}
if (strlen(pwd->pw_passwd) < 13) {
if (Curpw == NULL)
printf("No Problem:\t%s\tshell: %s\n",
pwd->pw_name, pwd->pw_shell);
else
printf("%s -- No Problem:\t%s\tshell: %s\tlength: %d\n",
Curpw, pwd->pw_name, pwd->pw_shell,strlen(pwd->pw_passwd));
fflush(stdout);
continue;
}
/*
* Try the user's login name
*/
strcpy(guess, pwd->pw_name);
if (uandltry(pwd,pwd->pw_name))
continue;
strcat(guess, pwd->pw_name);
if (uandltry(pwd, guess)) /* try login name repeated */
continue;
#ifdef DOUBLE
/* This code from 2.0, but user?user takes entirely too much time. _H*/
if (checkfchars) {
c = strlen(pwd->pw_name); /* reusing variable 'c' */
strcpy(&guess[c+1], pwd->pw_name); /* leave a one char hole */
cp = fchars; /* reusing variable 'cp' */
while (*cp != NULL)
{
guess[c] = *cp++;
if (uandltry(pwd, guess)) /* name?name try */
continue;
}
}
#endif

/*
* Try the student id# if one exists
*/
if (chkid) {
ulf = fopen("/usr/adm/users/userfile", "r+");
while (1) {
readatom(ulf, 100, stname);
if (nextc == EOF)
break;
if (strcmp(pwd->pw_name, stname) == 0) {
readatom(ulf, 100, junk);
readatom(ulf, 100, guess);
break;
}
newline(ulf);
}
fclose(ulf);
if (guess)
try(pwd, guess);
}
/*
* Try names from the gecos field
*/
if (checkgecos) {
strcpy(guess, pwd->pw_gecos);
cp = guess;
if (*cp == '-') cp++; /* special gecos field */
if ((cp2 = strchr(cp, ';')) != NULL)
*cp2 = '\0';
/* WHBjr hack to better divide words [from 2.0] _H*/
cp2 = cp;
while ((cp2 = strchr(cp2, ',')) != NULL)
*cp2++ = ' ';
for (;;) {
if ((cp2 = strchr(cp, ' ')) == NULL) {
if (uandltry(pwd,cp))
done++;
break;
}
*cp2 = '\0';
if (uandltry(pwd,cp)) {
done++;
break;
}
cp = ++cp2;
}
}

/* dictfile code from 2.0 version but since we've read a huge wordlist into
this one, we might not need this. _H*/
if (!done && dictfile) /* try dictionary file */
{
rewind(df);
cp = guess;
while ((c = getc(df)) != EOF)
{
if (c == '\n')
{
if ((cp - guess) > 8)
guess[8] = '\0';
else
*cp = '\0';
if(uandltry(pwd, guess))
{
done++;
break;
}
cp = guess;
continue;
}
*cp++ = c;
}
}

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 funny char append try,
* 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 [or N-mixed-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;

unsigned int num, nbits, len; /* uplow vars */
register unsigned int bits, maxbits, i, tmp;
char buf2[100];
register char *p2;

alllower = allupper = 1;

strcpy (buf, guess);
if (ftry(pwd,buf) || (backwards && ftry(pwd,nreverse(buf)))) return (1);

if (!checkcase) goto maybeuplow;

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 (ftry(pwd,buf) || (backwards && ftry(pwd,nreverse(buf))))
return (1);
}

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

if (ftry(pwd,buf) || (backwards && ftry(pwd,nreverse(buf))))
return (1);
}

maybeuplow: /* up-low code */
if (!num_uplow) return(0);

for ( cp = buf; *cp != '\0'; cp++) /* make all lower first */
if (isupper (*cp))
*cp += ' ';

for (num = 1; num < 10; num++) /* -# control array */
if (nums[num]) {
len = strlen(buf);
if (num >= len) /* sanity check */
return (0);
for (cp = buf; *cp != '\0'; cp++)
if (isupper (*cp)) *cp += ' ';
maxbits = 0;
for (i = 0; i < len; i++)
maxbits = (maxbits << 1) + 1; /* mask incr limit */
/* bits is uppercasing-mask control */
for (bits = 0; bits < maxbits+1; bits++) {
/* figger out how many bits of "bits" are on, and does it match num? */
tmp = bits; nbits = 0;
for (i = 0; i < len; i++) {
if ((tmp >> i) & (int)1) nbits++;
}
if (nbits == num) {
/* okay, we have the requisite number, so do a modified strcpy. Believe it
or not, it's faster to do these two separate loops than to combine
the strcpy into one big one -- byte-pushing chews cpu, I guess _H*/
tmp = bits; i = 0;
p2 = buf2;
/* this is gonna go sorta backwards, but wtf */
for (cp = buf; *cp != 0; cp++) {
*p2 = *cp;
if ((tmp >> i++) & (int)1) *p2 -= ' ';
p2++;
}
*p2 = 0; /* remember the final null! */
if (ftry(pwd,buf2) || (backwards && ftry(pwd,nreverse(buf2))))
return (1);
}
}
}
return (0);
}

/* append funny chars if selected -- stolen from 2.0 _H*/
ftry(pwd,guess)
register struct passwd *pwd;
char *guess;
{
char *fptr;
char tguess[100];
char t2guess[100];
short guesslen;

if (try(pwd, guess))
return(1);
if (!checkfchars)
return(0);
fptr = fchars;
guesslen = strlen(guess); /* first trailing char */
strcpy(tguess, guess); /* some parameters fixed len - defensive prog */
tguess[guesslen+1] = NULL; /* put in real end of string */
strcpy(t2guess+1, guess); /* leading char guess */
while (*fptr != NULL)
{
tguess[guesslen] = *fptr;
if (try(pwd, tguess))
return(1);
t2guess[0] = *fptr++; /* now leading char */
if (try(pwd, t2guess))
return(1);
}
}

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

#ifdef FDES
char *crypt ();
#else
char *crypt ();
#define crypt crypt
#endif

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()
{
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;
/* while(*p && *p != ',')
p++;
if(*p)
*p++ = '\0';
passwd.pw_age = p;
*/
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);
}

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

{
static char tmp[1024];
register char *p;

p = tmp +strlen(str);
*p = '\0';
while (*str && (*--p = *str++))
;
return(tmp);
}

readatom(fp, maxlen, buffer)
FILE *fp;
int maxlen;
char *buffer;
{
int i;

/* skip whitespace */
nextc = getc(fp);
while (nextc == ' ' || nextc == '\t')
nextc = getc(fp);
/* now read until break char or array is filled */
for (i = 0; nextc != ' ' && nextc != '\t' && nextc != '\n' &&
nextc != ':' && nextc != ',' && nextc != EOF; i++) {
if (i < maxlen)
buffer[i] = nextc;
nextc = getc(fp);
}
if (i < maxlen)
buffer[i] = '\0';
else
buffer[maxlen-1] = '\0';
}

newline(fp)
FILE *fp;
{
while (nextc != '\n' && nextc != EOF)
nextc = getc(fp);
}

/* Turbo C version of Fast DES (Unix xform algorithm) */
/* Industrial Crimes Research */


/* DO NOT DISTRIBUTE DO NOT DISTRIBUTE DO NOT DISTRIBUTE */


/* Misc defs for the fast password transform. */

#define reg register
#define uns unsigned
#define unsb uns char
#define unsl uns long

/* Types for the different ways to represent DES bit patterns.
* Bits are always right justified within fields.
* Bits which have lower indices in the NBS spec are stored in the
* vax bits with less significance (e.g., Bit 1 of NBS spec is stored
* in the bit with weight 2 ** 0 to the vax.
*/

#define obpb1 unsb /* One bit per byte. */
#define sbpb6 unsb /* Six bits per byte, 6 held. */
#define sbpb6R unsb /* Six bits per byte Reversed order, 6 held. */
#define sbpb24 unsl /* Six bits per byte, 24 held. */
#define ebpb24 unsl /* Eight bits per bit, 24 held. */
#define fbpb4 unsb /* Four bits per byte, 4 held. */
#define fbpb4R unsb /* Four bits per byte Reversed order, 4 held. */

/* Some damn systems still don't have prototypes or voids!!! */
#define VOID int
/*
Prototypes
sbpb24 tfTOsixbit (ebpb24);
ebpb24 sixbitTOtf (sbpb24);
VOID fsetkey (obpb1 *);
fbpb4 lookupS (unsl, sbpb6R);
VOID init_des (VOID);
VOID init (unsl, sbpb24 *, sbpb24 *);
VOID xform (sbpb24 *, sbpb24);
VOID Fperm (unsb *);
VOID undoe (obpb1 *, obpb1 *);
VOID toBA64 (reg sbpb24 *, obpb1 *);
char *fcrypt (char *, char *);
*/
/* Tables and initialization routines for the fast password transform. */

/* Big and little indians.
* "The first tribe we met arranged themselves with the smallest
* indian on the left and the biggest on the right. The second
* tribe used the reverse order. They put the smallest indian on
* the right. Of course there was one tribe that arranged the
* smallest half of their tribe on the left, but within each half
* they put the bigger members towards the left."
*
*
* The VAX tribe:
*
* Let us name the sixteen bytes that occupy addresses 1000 through 100F
* (hex) in memory a through h. That is the byte at address 1001 is
* called b. Successive byte fetches starting at 1000 would return the
* values: a, b, c, ... , h. Successive word fetches would return: ba,
* dc, fe, hg. Where the least significant bit (LSB) of ba is the LSB of
* a. Successive long fetches would return: dcba, hgfe. Where the most
* significant bit (MSB) of dcba is the MSB of d.
*
* Bits are numbered 0 through 31 with 0 being the LSB.
*
*
* The NBS tribe (related to IBM):
*
* Bits are numbered 1 through 64 and are written down with bit 1 leftmost
* and bit 64 rigt most. The variants on this are 48, 32, 6, and 4 bits
* wide but they follow the same numbering. In the case of 4 bit values
* (S-box outputs), they are encoded by number from zero through sixteen.
* This representation comes from the binary expansion of the sixteen
* decimal values. BUT the least significant bit of this expansion is
* the leftmost bit, not the rightmost as in the vax.
*/

/* Bastard representations for speed.
*
*
* To speed up the des computation the 32 bit values in the NBS spec are
* represented by 48 bits within the vax. By doing this, we can avoid
* the expansion permutation E.
*
* Those 48 bit values are held in two 32 bit words. To speed up the
* S-box table lookups, the 48 bits are divided into eight 6 bit groups
* which directly feed the eight S-boxes. The eight groups are stored in
* eight successive bytes in memory. Within each byte, the 6 bits are
* the least significant ones. The high two bits of each byte are zero.
*
* Bit 1 of the 48 bit value according to the NBS spec is stored as the
* LSB of the first byte in the eight byte representation. If the eight
* bytes are fetched as two long words (32 bits on the vax), bit 1 of the
* NBS spec will be held in the LSB of the first long fetched.
*
* Another representation of 48 bit values used by the code is to split
* the value into two 32 bit registers and store the 24 bit halves of the
* original value as the 24 least significant bits of each register.
*
* The final representation is to store one bit per byte in an array of
* bytes. This rep has the property that bit N of the NBS spec is stored
* as the LSB of the Nth byte in the array (i.e., index N-1).
*/

/* Final permutation, FP = IP^(-1) - changed index from 1 to 0 */
unsb FP[] =
{
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,
32, 0,40, 8,48,16,56,24,
};

/* 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.
*
* Not zero based!
*/
static unsb 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 unsb 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,
};

/* Permuted-choice 2, to pick out the bits from
* the CD array that generate the key schedule.
*/
static unsb 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 unsb 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 E bit-selection table. */
unsb 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,
};

/* P is a permutation on the selected combination
* of the current L and key.
*/
static unsb 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 8 selection functions. */
static fbpb4R 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,
};

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

/* The C and D arrays used to calculate the key schedule. */
static obpb1 C[28];
static obpb1 D[28];

/* Key schedule.
* Alternating longs with low and high bits of key.
* Low and high 24 bits of keys are stored alternately.
*/
sbpb24 KS[32];

/* The current block, divided into 2 halves. */
obpb1 L[32], R[32];

/* Tables that combine the S and P operations. */
sbpb24 S0L[64], S1L[64], S2L[64], S3L[64],
S4L[64], S5L[64], S6L[64], S7L[64];

sbpb24 S0H[64], S1H[64], S2H[64], S3H[64],
S4H[64], S5H[64], S6H[64], S7H[64];

/* It is slightly faster to indirect through this table than to specify
* the desired table directly.
*/
static sbpb24 *stt[] =
{
S0L, S0H,
S1L, S1H,
S2L, S2H,
S3L, S3H,
S4L, S4H,
S5L, S5H,
S6L, S6H,
S7L, S7H,
};










/* Convert unsl in twenty-four bit contiguous format
* to six bits per byte format. Return result.
*/
sbpb24 tfTOsixbit (tf)
ebpb24 tf;
{

sbpb24 res;

res = 0;
res |= (tf >> 0) & 077;
res |= (((tf >> 6) & 077) << 8);
res |= (((tf >> 12) & 077) << 16);
res |= (((tf >> 18) & 077) << 24);

return(res);

} /* End tfTOsixbit() */





/* Convert unsl in six bits per byte format
* to twenty-four bit contiguous format. Return result.
*/
ebpb24 sixbitTOtf (sb)
sbpb24 sb;
{

ebpb24 res;

res = 0;
res |= ((sb >> 0) & 077);
res |= (((sb >> 8) & 077) << 6);
res |= (((sb >> 16) & 077) << 12);
res |= (((sb >> 24) & 077) << 18);

return(res);

} /* End sixbitTOtf() */





/* Set up the key schedule from the key. */
VOID fsetkey (key)
obpb1 *key;
{

reg int i, j, k;
obpb1 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 < 32 ; i += 2)
{
/* rotate */
for (k = 0 ; k < shifts[i/2] ; 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. */
KS[i] = KS[i+1] = 0;
for (j = 0 ; j < 24 ; j++)
{
KS[i] |= ((sbpb24) C [PC2_C[j] - 1] << j);
KS[i+1] |= ((sbpb24) D [PC2_D[j] - 28 - 1] << j);
}
KS[i] = tfTOsixbit(KS[i]);
KS[i+1] = tfTOsixbit(KS[i+1]);
}

} /* End fsetkey() */





/* Lookup an S-box entry.*/
fbpb4 lookupS (tableno, t6bits)
unsl tableno;
sbpb6R t6bits;
{

sbpb6 fixed6bits;
fbpb4R r;
fbpb4 fixedr;

fixed6bits =
(((t6bits >> 0) &01) << 5)+
(((t6bits >> 1) &01) << 3)+
(((t6bits >> 2) &01) << 2)+
(((t6bits >> 3) &01) << 1)+
(((t6bits >> 4) &01) << 0)+
(((t6bits >> 5) &01) << 4);

r = (fbpb4)S[(int)tableno][(int)fixed6bits];

fixedr =
(((r >> 3)&01) << 0)+
(((r >> 2)&01) << 1)+
(((r >> 1)&01) << 2)+
(((r >> 0)&01) << 3);

return (fixedr);

} /* End lookupS() */





VOID init_des ()
{

init((unsl)0, S0L, S0H);
init((unsl)1, S1L, S1H);
init((unsl)2, S2L, S2H);
init((unsl)3, S3L, S3H);
init((unsl)4, S4L, S4H);
init((unsl)5, S5L, S5H);
init((unsl)6, S6L, S6H);
init((unsl)7, S7L, S7H);

} /* End init_des() */





VOID init (tableno, lowptr, highptr)
unsl tableno;
sbpb24 *lowptr;
sbpb24 *highptr;
{

static obpb1 tmp32[32];
static obpb1 tmpP32[32];
static obpb1 tmpE[48];
sbpb6R j;
int k, i;

for (j = 0 ; j < 64 ; j++)
{
k = lookupS(tableno, j);
for (i = 0 ; i < 32 ; i++)
tmp32[i] = 0;
for (i = 0 ; i < 4 ; i++)
tmp32[4 * (int)tableno + i] = (obpb1)(k >> i) & 01;
for (i = 0 ; i < 32 ; i++)
tmpP32[i] = tmp32[P[i] - 1];
for (i = 0 ; i < 48 ; i++)
tmpE[i] = tmpP32[(int)E[i] - 1];

lowptr[j] = 0;
highptr[j] = 0;
for (i = 0 ; i < 24 ; i++)
lowptr[(int)j] |= (unsl)tmpE[i] << i;
for (k = 0, i = 24 ; i < 48 ; i++, k++)
highptr[(int)j] |= (unsl)tmpE[i] << k;

lowptr[j] = tfTOsixbit(lowptr[j]);
highptr[j] = tfTOsixbit(highptr[j]);
}

} /* End init() */





/* Heart of the fast password transform.
*
* Speed up techniques:
* - Use 48 bit datapath throughout f.
* - Store 48 bit path in two longs, 24 bits each.
* - Byte align the four 6-bit groups in the 24 bits per long.
* - Combine the S and P tables into a single lookup.
* - Implement the SP lookup by 16 long word lookups.
* - Access the 16 SP tables via an indirection table to save registers.
* - Use sed script to use all available registers. See fdes.sed.doc.
* - Perform salting by XORing with a computed mask.
* - XOR table values directly into accumulators.
* - Indirection table alternates left and right half to save on
* pointer increment instructions.
* - Have loop indices count down to zero for faster code.
* - Put key schedule in single array alternating low and high longs,
* This allows access via an autoinc register variable.
* - Split computation of k to make register optimizing easier.
* - Unroll f loop to avoid the need to swap left and right halves.
*/


/* The payoff: encrypt a block. */
VOID xform (quarters, saltvalue)
sbpb24 *quarters;
sbpb24 saltvalue;
{
/* Only get six register vars on Vax, so sed script is used to
* move other variables into registers.
* Some vars are declared to be in registers so the compiler will
* generate easy to transform code.
*/
sbpb24 Rl, Rh;
sbpb24 Ll, Lh;
static sbpb24 Dl, Dh;
reg sbpb24 k;
sbpb24 negsalt;
reg sbpb6 *dp;
reg int mi;
reg sbpb24 *kp;
reg sbpb24 *kend;

negsalt = ~saltvalue; /* Vax has bit clear instr not AND. */
Ll = Lh = Rl = Rh = 0;
kend = &KS[32];

for (mi = 25 ; --mi >= 0 ; )
{
for (kp = KS ; kp < kend ; )
{
reg sbpb24 **stp;
k = (Rl ^ Rh);
k &= (~negsalt);
Dl = (k ^( Rl ^ *kp++));
Dh = (k ^( Rh ^ *kp++));
stp = ((sbpb24 **) stt);

#ifdef sun
#define auto *dp--
#define offs 3
#else
#define auto *dp++
#define offs 0
#endif

dp = ((sbpb6 *) &Dl) + offs;
/* Compiler bug prevents putting all of these on one line.*/
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];
dp = ((sbpb6 *) &Dh) + offs;
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];
Ll ^= (*stp++)[*dp];
Lh ^= (*stp++)[auto];

k = (Ll ^ Lh);
k &= (~negsalt);
Dl = (k ^ Ll ^ *kp++);
Dh = (k ^ Lh ^ *kp++);

stp = ((sbpb24 **) stt);

dp = ((sbpb6 *) &Dl) + offs;
/* Compiler bug prevents putting all of these on one line.*/
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
dp = ((sbpb6 *) &Dh) + offs;
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
Rl ^= (*stp++)[*dp];
Rh ^= (*stp++)[auto];
}
Ll ^= Rl; Lh ^= Rh;
Rl ^= Ll; Rh ^= Lh;
Ll ^= Rl; Lh ^= Rh;
}

{
reg sbpb24 *qp;

qp = quarters;
*qp++ = Ll;
*qp++ = Lh;
*qp++ = Rl;
*qp++ = Rh;
}

} /* End xform() */





/* Final permutation. Takes input from globals L and R. */
VOID Fperm (block)
unsb *block;
{

reg j, k;

for (j = 0 ; j < 64 ; j++)
{
k = FP[j]; /* used to be block[j] = L[FP[j]] */
block[j] = (k<32) ? L[k] : R[k-32];
}

} /* End Fperm() */





/* Inverse of E permutation. */
VOID undoe (fromarr, toarr)
obpb1 *fromarr;
obpb1 *toarr;
{

reg int j;

for (j = 0 ; j < 32 ; j++)
toarr[j] = fromarr[1 + (j & 03) + 6 * (j >> 2)];

} /* End undoe() */





VOID toBA64 (quarters, onebits64)
reg sbpb24 *quarters;
obpb1 *onebits64;
{

int j;
static obpb1 tmpE[48];
reg unsb *onebits48;
reg sbpb24 quarter;

onebits48 = tmpE;
quarter = sixbitTOtf(*quarters++);
for (j = 0 ; j < 24 ; j++)
*onebits48++ = ((quarter >> j) & 01);
quarter = sixbitTOtf(*quarters++);
for ( j = 0 ; j < 24 ; j++)
*onebits48++ = ((quarter >> j) & 01);
undoe(tmpE,L);

onebits48 = tmpE;
quarter = sixbitTOtf(*quarters++);
for ( j = 0 ; j < 24 ; j++)
*onebits48++ = ((quarter >> j) & 01);
quarter = sixbitTOtf(*quarters++);
for ( j = 0 ; j < 24 ; j++)
*onebits48++ = ((quarter >> j) & 01);
undoe(tmpE,R);

Fperm(onebits64);

} /* End toBA64() */





char *fcrypt (pw, salt)
char *pw;
char *salt;
{
reg int i;
reg obpb1 j, c;
static obpb1 block[66];
static char iobuf[16];
static sbpb24 out96[4];
sbpb24 saltvalue;

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++; /* Skip parity bit. */
}

fsetkey(block);

for (i = 0 ; i < 66 ; i++)
block[i] = 0;

saltvalue = 0;
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++)
saltvalue |= ((c >> j) & 01) << (6 * i + j);
}
saltvalue = tfTOsixbit(saltvalue);

xform (out96, saltvalue);
toBA64 (out96, block);

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);

} /* End fcrypt() */


  3 Responses to “Category : UNIX Files
Archive   : KC910.ZIP
Filename : PASS.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/