diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /lib/libskey |
initial import of NetBSD tree
Diffstat (limited to 'lib/libskey')
-rw-r--r-- | lib/libskey/Makefile | 7 | ||||
-rw-r--r-- | lib/libskey/md4.c | 325 | ||||
-rw-r--r-- | lib/libskey/md4.h | 71 | ||||
-rw-r--r-- | lib/libskey/put.c | 2322 | ||||
-rw-r--r-- | lib/libskey/shlib_version | 2 | ||||
-rw-r--r-- | lib/libskey/skey.h | 77 | ||||
-rw-r--r-- | lib/libskey/skeylogin.c | 366 | ||||
-rw-r--r-- | lib/libskey/skeysubr.c | 317 |
8 files changed, 3487 insertions, 0 deletions
diff --git a/lib/libskey/Makefile b/lib/libskey/Makefile new file mode 100644 index 00000000000..7e616b17dc6 --- /dev/null +++ b/lib/libskey/Makefile @@ -0,0 +1,7 @@ +# $Id: Makefile,v 1.1 1995/10/18 08:43:11 deraadt Exp $ + +LIB= skey +SRCS= skeylogin.c skeysubr.c md4.c put.c +CFLAGS+= -DUSE_ECHO + +.include <bsd.lib.mk> diff --git a/lib/libskey/md4.c b/lib/libskey/md4.c new file mode 100644 index 00000000000..29a77c59bff --- /dev/null +++ b/lib/libskey/md4.c @@ -0,0 +1,325 @@ +/* + * md4.c -- Implementation of MD4 Message Digest Algorithm + * Updated: 2/16/90 by Ronald L. Rivest + * Portability nits fixed and reformatted - 2/12/91 Phil Karn + * + * Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD4 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD4 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + * + * $Id: md4.c,v 1.1 1995/10/18 08:43:11 deraadt Exp $ + */ + +/* + * To use MD4: + * -- Include md4.h in your program + * -- Declare an MDstruct MD to hold the state of the digest computation. + * -- Initialize MD using MDbegin(&MD) + * -- For each full block (64 bytes) X you wish to process, call + * MDupdate(&MD,X,512) + * (512 is the number of bits in a full block.) + * -- For the last block (less than 64 bytes) you wish to process, + * MDupdate(&MD,X,n) + * where n is the number of bits in the partial block. A partial + * block terminates the computation, so every MD computation should + * terminate by processing a partial block, even if it has n = 0. + * -- The message digest is available in MD.buffer[0] ... MD.buffer[3]. + * (Least-significant byte of each word should be output first.) + * -- You can print out the digest using MDprint(&MD) + */ + +/* Implementation notes: + * This implementation assumes that longs are 32-bit quantities. + * Note that on big endian machines the routine + * MDupdate modifies has a side-effect on its input array (the order of bytes + * in each word are reversed). If this is undesired a call to MDreverse(X) can + * reverse the bytes of X back into order after each call to MDupdate. + */ +/* Compile-time includes */ +#include <stdio.h> +#include <machine/endian.h> +#include "md4.h" + +static void MDblock __ARGS((MDptr, unsigned long *)); + +/* Compile-time declarations of MD4 ``magic constants'' */ +#define I0 0x67452301 /* Initial values for MD buffer */ +#define I1 0xefcdab89 +#define I2 0x98badcfe +#define I3 0x10325476 +#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ +#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ +/* C2 and C3 are from Knuth, The Art of Programming, Volume 2 + * (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. + * Table 2, page 660. + */ +#define fs1 3 /* round 1 shift amounts */ +#define fs2 7 +#define fs3 11 +#define fs4 19 +#define gs1 3 /* round 2 shift amounts */ +#define gs2 5 +#define gs3 9 +#define gs4 13 +#define hs1 3 /* round 3 shift amounts */ +#define hs2 9 +#define hs3 11 +#define hs4 15 + + +/* Compile-time macro declarations for MD4. + * Note: The ``rot'' operator uses the variable ``tmp''. + * It assumes tmp is declared as unsigned long, so that the >> + * operator will shift in zeros rather than extending the sign bit. + */ +#define f(X,Y,Z) ((X&Y) | ((~X)&Z)) +#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) +#define h(X,Y,Z) (X^Y^Z) +#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S))) +#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s) +#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s) +#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s) + +void MDreverse __ARGS((unsigned long *X)); + +/* MDprint(MDp) + * Print message digest buffer MDp as 32 hexadecimal digits. + * Order is from low-order byte of buffer[0] to high-order byte of buffer[3]. + * Each byte is printed with high-order hexadecimal digit first. + * This is a user-callable routine. + */ +void +MDprint(MDp) +MDptr MDp; +{ + int i,j; + + for(i=0;i<4;i++) + for(j=0;j<32;j=j+8) + printf("%02lx",(MDp->buffer[i]>>j) & 0xFF); +} + +/* MDbegin(MDp) + * Initialize message digest buffer MDp. + * This is a user-callable routine. + */ +void +MDbegin(MDp) +MDptr MDp; +{ + int i; + + MDp->buffer[0] = I0; + MDp->buffer[1] = I1; + MDp->buffer[2] = I2; + MDp->buffer[3] = I3; + for(i=0;i<8;i++) + MDp->count[i] = 0; + MDp->done = 0; +} + +/* MDreverse(X) + * Reverse the byte-ordering of every long in X. + * Assumes X is an array of 16 longs. + * The macro revx reverses the byte-ordering of the next word of X. + */ +#define revx { t = (*X << 16) | (*X >> 16); \ + *X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); } +void +MDreverse(X) +unsigned long *X; +{ + register unsigned long t; + + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; + revx; +} + +/* MDblock(MDp,X) + * Update message digest buffer MDp->buffer using 16-word data block X. + * Assumes all 16 words of X are full of data. + * Does not update MDp->count. + * This routine is not user-callable. + */ +static void +MDblock(MDp,X) +MDptr MDp; +unsigned long *X; +{ + register unsigned long tmp, A, B, C, D; + +#if BYTE_ORDER == BIG_ENDIAN + MDreverse(X); +#endif + A = MDp->buffer[0]; + B = MDp->buffer[1]; + C = MDp->buffer[2]; + D = MDp->buffer[3]; + /* Update the message digest buffer */ + ff(A,B,C,D,0,fs1); /* Round 1 */ + ff(D,A,B,C,1,fs2); + ff(C,D,A,B,2,fs3); + ff(B,C,D,A,3,fs4); + ff(A,B,C,D,4,fs1); + ff(D,A,B,C,5,fs2); + ff(C,D,A,B,6,fs3); + ff(B,C,D,A,7,fs4); + ff(A,B,C,D,8,fs1); + ff(D,A,B,C,9,fs2); + ff(C,D,A,B,10,fs3); + ff(B,C,D,A,11,fs4); + ff(A,B,C,D,12,fs1); + ff(D,A,B,C,13,fs2); + ff(C,D,A,B,14,fs3); + ff(B,C,D,A,15,fs4); + gg(A,B,C,D,0,gs1); /* Round 2 */ + gg(D,A,B,C,4,gs2); + gg(C,D,A,B,8,gs3); + gg(B,C,D,A,12,gs4); + gg(A,B,C,D,1,gs1); + gg(D,A,B,C,5,gs2); + gg(C,D,A,B,9,gs3); + gg(B,C,D,A,13,gs4); + gg(A,B,C,D,2,gs1); + gg(D,A,B,C,6,gs2); + gg(C,D,A,B,10,gs3); + gg(B,C,D,A,14,gs4); + gg(A,B,C,D,3,gs1); + gg(D,A,B,C,7,gs2); + gg(C,D,A,B,11,gs3); + gg(B,C,D,A,15,gs4); + hh(A,B,C,D,0,hs1); /* Round 3 */ + hh(D,A,B,C,8,hs2); + hh(C,D,A,B,4,hs3); + hh(B,C,D,A,12,hs4); + hh(A,B,C,D,2,hs1); + hh(D,A,B,C,10,hs2); + hh(C,D,A,B,6,hs3); + hh(B,C,D,A,14,hs4); + hh(A,B,C,D,1,hs1); + hh(D,A,B,C,9,hs2); + hh(C,D,A,B,5,hs3); + hh(B,C,D,A,13,hs4); + hh(A,B,C,D,3,hs1); + hh(D,A,B,C,11,hs2); + hh(C,D,A,B,7,hs3); + hh(B,C,D,A,15,hs4); + MDp->buffer[0] += A; + MDp->buffer[1] += B; + MDp->buffer[2] += C; + MDp->buffer[3] += D; +} + +/* MDupdate(MDp,X,count) + * Input: MDp -- an MDptr + * X -- a pointer to an array of unsigned characters. + * count -- the number of bits of X to use. + * (if not a multiple of 8, uses high bits of last byte.) + * Update MDp using the number of bits of X given by count. + * This is the basic input routine for an MD4 user. + * The routine completes the MD computation when count < 512, so + * every MD computation should end with one call to MDupdate with a + * count less than 512. A call with count 0 will be ignored if the + * MD has already been terminated (done != 0), so an extra call with count + * 0 can be given as a ``courtesy close'' to force termination if desired. + */ +void +MDupdate(MDp,X,count) +MDptr MDp; +unsigned char *X; +unsigned int count; +{ + int i,bit,byte,mask; + unsigned long tmp; + unsigned char XX[64]; + unsigned char *p; + + /* return with no error if this is a courtesy close with count + * zero and MDp->done is true. + */ + if(count == 0 && MDp->done) + return; + /* check to see if MD is already done and report error */ + if(MDp->done){ + printf("\nError: MDupdate MD already done."); + return; + } + /* Add count to MDp->count */ + tmp = count; + p = MDp->count; + while(tmp){ + tmp += *p; + *p++ = tmp; + tmp = tmp >> 8; + } + /* Process data */ + if(count == 512){ + /* Full block of data to handle */ + MDblock(MDp,(unsigned long *)X); + } else if(count > 512){ + /* Check for count too large */ + printf("\nError: MDupdate called with illegal count value %ld.",count); + return; + } else { + /* partial block -- must be last block so finish up + * Find out how many bytes and residual bits there are + */ + byte = count >> 3; + bit = count & 7; + /* Copy X into XX since we need to modify it */ + for(i=0;i<=byte;i++) + XX[i] = X[i]; + for(i=byte+1;i<64;i++) + XX[i] = 0; + /* Add padding '1' bit and low-order zeros in last byte */ + mask = 1 << (7 - bit); + XX[byte] = (XX[byte] | mask) & ~( mask - 1); + /* If room for bit count, finish up with this block */ + if(byte <= 55){ + for(i=0;i<8;i++) + XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned long *)XX); + } else { + /* need to do two blocks to finish up */ + MDblock(MDp,(unsigned long *)XX); + for(i=0;i<56;i++) + XX[i] = 0; + for(i=0;i<8;i++) + XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned long *)XX); + } + /* Set flag saying we're done with MD computation */ + MDp->done = 1; + } +} +/* End of md4.c */ diff --git a/lib/libskey/md4.h b/lib/libskey/md4.h new file mode 100644 index 00000000000..1564d3b76ac --- /dev/null +++ b/lib/libskey/md4.h @@ -0,0 +1,71 @@ +/* + * + * md4.h -- Header file for implementation of MD4 Message Digest Algorithm + * Updated: 2/13/90 by Ronald L. Rivest + * Reformatted and de-linted - 2/12/91 Phil Karn + * + * Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD4 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD4 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + * + * $Id: md4.h,v 1.1 1995/10/18 08:43:11 deraadt Exp $ + */ + +#ifdef __STDC__ +#define __ARGS(X) X /* For ANSI C */ +#else +#define __ARGS(X) () +#endif + +/* MDstruct is the data structure for a message digest computation. */ +typedef struct { + unsigned long buffer[4];/* Holds 4-word result of MD computation */ + unsigned char count[8]; /* Number of bits processed so far */ + unsigned int done; /* Nonzero means MD computation finished */ +} MDstruct, *MDptr; + +/* MDbegin(MD) + * Input: MD -- an MDptr + * Initialize the MDstruct prepatory to doing a message digest computation. + */ +extern void MDbegin __ARGS((MDptr MDp)); + +/* MDupdate(MD,X,count) + * Input: MD -- an MDptr + * X -- a pointer to an array of unsigned characters. + * count -- the number of bits of X to use (an unsigned int). + * Updates MD using the first ``count'' bits of X. + * The array pointed to by X is not modified. + * If count is not a multiple of 8, MDupdate uses high bits of last byte. + * This is the basic input routine for a user. + * The routine terminates the MD computation when count < 512, so + * every MD computation should end with one call to MDupdate with a + * count less than 512. Zero is OK for a count. + */ +extern void MDupdate __ARGS((MDptr MDp,unsigned char *X,unsigned int count)); + +/* MDprint(MD) + * Input: MD -- an MDptr + * Prints message digest buffer MD as 32 hexadecimal digits. + * Order is from low-order byte of buffer[0] to high-order byte of buffer[3]. + * Each byte is printed with high-order hexadecimal digit first. + */ +extern void MDprint __ARGS((MDptr MDp)); + +/* End of md4.h */ diff --git a/lib/libskey/put.c b/lib/libskey/put.c new file mode 100644 index 00000000000..1a493f1e35c --- /dev/null +++ b/lib/libskey/put.c @@ -0,0 +1,2322 @@ +/* S/KEY v1.1b (put.c) + * + * Authors: + * Neil M. Haller <nmh@thumper.bellcore.com> + * Philip R. Karn <karn@chicago.qualcomm.com> + * John S. Walden <jsw@thumper.bellcore.com> + * Scott Chasin <chasin@crimelab.com> + * + * Dictionary lookup and extraction. + * + * $Id: put.c,v 1.1 1995/10/18 08:43:11 deraadt Exp $ + */ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> +#include "skey.h" + +static unsigned long extract __ARGS ((char *s, int start, int length)); +static void standard __ARGS ((char *word)); +static void insert __ARGS ((char *s, int x, int start, int length)); +static int wsrch __ARGS ((char *w, int low, int high)); + +/* Dictionary for integer-word translations */ +char Wp[2048][4] = { + "A", + "ABE", + "ACE", + "ACT", + "AD", + "ADA", + "ADD", + "AGO", + "AID", + "AIM", + "AIR", + "ALL", + "ALP", + "AM", + "AMY", + "AN", + "ANA", + "AND", + "ANN", + "ANT", + "ANY", + "APE", + "APS", + "APT", + "ARC", + "ARE", + "ARK", + "ARM", + "ART", + "AS", + "ASH", + "ASK", + "AT", + "ATE", + "AUG", + "AUK", + "AVE", + "AWE", + "AWK", + "AWL", + "AWN", + "AX", + "AYE", + "BAD", + "BAG", + "BAH", + "BAM", + "BAN", + "BAR", + "BAT", + "BAY", + "BE", + "BED", + "BEE", + "BEG", + "BEN", + "BET", + "BEY", + "BIB", + "BID", + "BIG", + "BIN", + "BIT", + "BOB", + "BOG", + "BON", + "BOO", + "BOP", + "BOW", + "BOY", + "BUB", + "BUD", + "BUG", + "BUM", + "BUN", + "BUS", + "BUT", + "BUY", + "BY", + "BYE", + "CAB", + "CAL", + "CAM", + "CAN", + "CAP", + "CAR", + "CAT", + "CAW", + "COD", + "COG", + "COL", + "CON", + "COO", + "COP", + "COT", + "COW", + "COY", + "CRY", + "CUB", + "CUE", + "CUP", + "CUR", + "CUT", + "DAB", + "DAD", + "DAM", + "DAN", + "DAR", + "DAY", + "DEE", + "DEL", + "DEN", + "DES", + "DEW", + "DID", + "DIE", + "DIG", + "DIN", + "DIP", + "DO", + "DOE", + "DOG", + "DON", + "DOT", + "DOW", + "DRY", + "DUB", + "DUD", + "DUE", + "DUG", + "DUN", + "EAR", + "EAT", + "ED", + "EEL", + "EGG", + "EGO", + "ELI", + "ELK", + "ELM", + "ELY", + "EM", + "END", + "EST", + "ETC", + "EVA", + "EVE", + "EWE", + "EYE", + "FAD", + "FAN", + "FAR", + "FAT", + "FAY", + "FED", + "FEE", + "FEW", + "FIB", + "FIG", + "FIN", + "FIR", + "FIT", + "FLO", + "FLY", + "FOE", + "FOG", + "FOR", + "FRY", + "FUM", + "FUN", + "FUR", + "GAB", + "GAD", + "GAG", + "GAL", + "GAM", + "GAP", + "GAS", + "GAY", + "GEE", + "GEL", + "GEM", + "GET", + "GIG", + "GIL", + "GIN", + "GO", + "GOT", + "GUM", + "GUN", + "GUS", + "GUT", + "GUY", + "GYM", + "GYP", + "HA", + "HAD", + "HAL", + "HAM", + "HAN", + "HAP", + "HAS", + "HAT", + "HAW", + "HAY", + "HE", + "HEM", + "HEN", + "HER", + "HEW", + "HEY", + "HI", + "HID", + "HIM", + "HIP", + "HIS", + "HIT", + "HO", + "HOB", + "HOC", + "HOE", + "HOG", + "HOP", + "HOT", + "HOW", + "HUB", + "HUE", + "HUG", + "HUH", + "HUM", + "HUT", + "I", + "ICY", + "IDA", + "IF", + "IKE", + "ILL", + "INK", + "INN", + "IO", + "ION", + "IQ", + "IRA", + "IRE", + "IRK", + "IS", + "IT", + "ITS", + "IVY", + "JAB", + "JAG", + "JAM", + "JAN", + "JAR", + "JAW", + "JAY", + "JET", + "JIG", + "JIM", + "JO", + "JOB", + "JOE", + "JOG", + "JOT", + "JOY", + "JUG", + "JUT", + "KAY", + "KEG", + "KEN", + "KEY", + "KID", + "KIM", + "KIN", + "KIT", + "LA", + "LAB", + "LAC", + "LAD", + "LAG", + "LAM", + "LAP", + "LAW", + "LAY", + "LEA", + "LED", + "LEE", + "LEG", + "LEN", + "LEO", + "LET", + "LEW", + "LID", + "LIE", + "LIN", + "LIP", + "LIT", + "LO", + "LOB", + "LOG", + "LOP", + "LOS", + "LOT", + "LOU", + "LOW", + "LOY", + "LUG", + "LYE", + "MA", + "MAC", + "MAD", + "MAE", + "MAN", + "MAO", + "MAP", + "MAT", + "MAW", + "MAY", + "ME", + "MEG", + "MEL", + "MEN", + "MET", + "MEW", + "MID", + "MIN", + "MIT", + "MOB", + "MOD", + "MOE", + "MOO", + "MOP", + "MOS", + "MOT", + "MOW", + "MUD", + "MUG", + "MUM", + "MY", + "NAB", + "NAG", + "NAN", + "NAP", + "NAT", + "NAY", + "NE", + "NED", + "NEE", + "NET", + "NEW", + "NIB", + "NIL", + "NIP", + "NIT", + "NO", + "NOB", + "NOD", + "NON", + "NOR", + "NOT", + "NOV", + "NOW", + "NU", + "NUN", + "NUT", + "O", + "OAF", + "OAK", + "OAR", + "OAT", + "ODD", + "ODE", + "OF", + "OFF", + "OFT", + "OH", + "OIL", + "OK", + "OLD", + "ON", + "ONE", + "OR", + "ORB", + "ORE", + "ORR", + "OS", + "OTT", + "OUR", + "OUT", + "OVA", + "OW", + "OWE", + "OWL", + "OWN", + "OX", + "PA", + "PAD", + "PAL", + "PAM", + "PAN", + "PAP", + "PAR", + "PAT", + "PAW", + "PAY", + "PEA", + "PEG", + "PEN", + "PEP", + "PER", + "PET", + "PEW", + "PHI", + "PI", + "PIE", + "PIN", + "PIT", + "PLY", + "PO", + "POD", + "POE", + "POP", + "POT", + "POW", + "PRO", + "PRY", + "PUB", + "PUG", + "PUN", + "PUP", + "PUT", + "QUO", + "RAG", + "RAM", + "RAN", + "RAP", + "RAT", + "RAW", + "RAY", + "REB", + "RED", + "REP", + "RET", + "RIB", + "RID", + "RIG", + "RIM", + "RIO", + "RIP", + "ROB", + "ROD", + "ROE", + "RON", + "ROT", + "ROW", + "ROY", + "RUB", + "RUE", + "RUG", + "RUM", + "RUN", + "RYE", + "SAC", + "SAD", + "SAG", + "SAL", + "SAM", + "SAN", + "SAP", + "SAT", + "SAW", + "SAY", + "SEA", + "SEC", + "SEE", + "SEN", + "SET", + "SEW", + "SHE", + "SHY", + "SIN", + "SIP", + "SIR", + "SIS", + "SIT", + "SKI", + "SKY", + "SLY", + "SO", + "SOB", + "SOD", + "SON", + "SOP", + "SOW", + "SOY", + "SPA", + "SPY", + "SUB", + "SUD", + "SUE", + "SUM", + "SUN", + "SUP", + "TAB", + "TAD", + "TAG", + "TAN", + "TAP", + "TAR", + "TEA", + "TED", + "TEE", + "TEN", + "THE", + "THY", + "TIC", + "TIE", + "TIM", + "TIN", + "TIP", + "TO", + "TOE", + "TOG", + "TOM", + "TON", + "TOO", + "TOP", + "TOW", + "TOY", + "TRY", + "TUB", + "TUG", + "TUM", + "TUN", + "TWO", + "UN", + "UP", + "US", + "USE", + "VAN", + "VAT", + "VET", + "VIE", + "WAD", + "WAG", + "WAR", + "WAS", + "WAY", + "WE", + "WEB", + "WED", + "WEE", + "WET", + "WHO", + "WHY", + "WIN", + "WIT", + "WOK", + "WON", + "WOO", + "WOW", + "WRY", + "WU", + "YAM", + "YAP", + "YAW", + "YE", + "YEA", + "YES", + "YET", + "YOU", + "ABED", + "ABEL", + "ABET", + "ABLE", + "ABUT", + "ACHE", + "ACID", + "ACME", + "ACRE", + "ACTA", + "ACTS", + "ADAM", + "ADDS", + "ADEN", + "AFAR", + "AFRO", + "AGEE", + "AHEM", + "AHOY", + "AIDA", + "AIDE", + "AIDS", + "AIRY", + "AJAR", + "AKIN", + "ALAN", + "ALEC", + "ALGA", + "ALIA", + "ALLY", + "ALMA", + "ALOE", + "ALSO", + "ALTO", + "ALUM", + "ALVA", + "AMEN", + "AMES", + "AMID", + "AMMO", + "AMOK", + "AMOS", + "AMRA", + "ANDY", + "ANEW", + "ANNA", + "ANNE", + "ANTE", + "ANTI", + "AQUA", + "ARAB", + "ARCH", + "AREA", + "ARGO", + "ARID", + "ARMY", + "ARTS", + "ARTY", + "ASIA", + "ASKS", + "ATOM", + "AUNT", + "AURA", + "AUTO", + "AVER", + "AVID", + "AVIS", + "AVON", + "AVOW", + "AWAY", + "AWRY", + "BABE", + "BABY", + "BACH", + "BACK", + "BADE", + "BAIL", + "BAIT", + "BAKE", + "BALD", + "BALE", + "BALI", + "BALK", + "BALL", + "BALM", + "BAND", + "BANE", + "BANG", + "BANK", + "BARB", + "BARD", + "BARE", + "BARK", + "BARN", + "BARR", + "BASE", + "BASH", + "BASK", + "BASS", + "BATE", + "BATH", + "BAWD", + "BAWL", + "BEAD", + "BEAK", + "BEAM", + "BEAN", + "BEAR", + "BEAT", + "BEAU", + "BECK", + "BEEF", + "BEEN", + "BEER", + "BEET", + "BELA", + "BELL", + "BELT", + "BEND", + "BENT", + "BERG", + "BERN", + "BERT", + "BESS", + "BEST", + "BETA", + "BETH", + "BHOY", + "BIAS", + "BIDE", + "BIEN", + "BILE", + "BILK", + "BILL", + "BIND", + "BING", + "BIRD", + "BITE", + "BITS", + "BLAB", + "BLAT", + "BLED", + "BLEW", + "BLOB", + "BLOC", + "BLOT", + "BLOW", + "BLUE", + "BLUM", + "BLUR", + "BOAR", + "BOAT", + "BOCA", + "BOCK", + "BODE", + "BODY", + "BOGY", + "BOHR", + "BOIL", + "BOLD", + "BOLO", + "BOLT", + "BOMB", + "BONA", + "BOND", + "BONE", + "BONG", + "BONN", + "BONY", + "BOOK", + "BOOM", + "BOON", + "BOOT", + "BORE", + "BORG", + "BORN", + "BOSE", + "BOSS", + "BOTH", + "BOUT", + "BOWL", + "BOYD", + "BRAD", + "BRAE", + "BRAG", + "BRAN", + "BRAY", + "BRED", + "BREW", + "BRIG", + "BRIM", + "BROW", + "BUCK", + "BUDD", + "BUFF", + "BULB", + "BULK", + "BULL", + "BUNK", + "BUNT", + "BUOY", + "BURG", + "BURL", + "BURN", + "BURR", + "BURT", + "BURY", + "BUSH", + "BUSS", + "BUST", + "BUSY", + "BYTE", + "CADY", + "CAFE", + "CAGE", + "CAIN", + "CAKE", + "CALF", + "CALL", + "CALM", + "CAME", + "CANE", + "CANT", + "CARD", + "CARE", + "CARL", + "CARR", + "CART", + "CASE", + "CASH", + "CASK", + "CAST", + "CAVE", + "CEIL", + "CELL", + "CENT", + "CERN", + "CHAD", + "CHAR", + "CHAT", + "CHAW", + "CHEF", + "CHEN", + "CHEW", + "CHIC", + "CHIN", + "CHOU", + "CHOW", + "CHUB", + "CHUG", + "CHUM", + "CITE", + "CITY", + "CLAD", + "CLAM", + "CLAN", + "CLAW", + "CLAY", + "CLOD", + "CLOG", + "CLOT", + "CLUB", + "CLUE", + "COAL", + "COAT", + "COCA", + "COCK", + "COCO", + "CODA", + "CODE", + "CODY", + "COED", + "COIL", + "COIN", + "COKE", + "COLA", + "COLD", + "COLT", + "COMA", + "COMB", + "COME", + "COOK", + "COOL", + "COON", + "COOT", + "CORD", + "CORE", + "CORK", + "CORN", + "COST", + "COVE", + "COWL", + "CRAB", + "CRAG", + "CRAM", + "CRAY", + "CREW", + "CRIB", + "CROW", + "CRUD", + "CUBA", + "CUBE", + "CUFF", + "CULL", + "CULT", + "CUNY", + "CURB", + "CURD", + "CURE", + "CURL", + "CURT", + "CUTS", + "DADE", + "DALE", + "DAME", + "DANA", + "DANE", + "DANG", + "DANK", + "DARE", + "DARK", + "DARN", + "DART", + "DASH", + "DATA", + "DATE", + "DAVE", + "DAVY", + "DAWN", + "DAYS", + "DEAD", + "DEAF", + "DEAL", + "DEAN", + "DEAR", + "DEBT", + "DECK", + "DEED", + "DEEM", + "DEER", + "DEFT", + "DEFY", + "DELL", + "DENT", + "DENY", + "DESK", + "DIAL", + "DICE", + "DIED", + "DIET", + "DIME", + "DINE", + "DING", + "DINT", + "DIRE", + "DIRT", + "DISC", + "DISH", + "DISK", + "DIVE", + "DOCK", + "DOES", + "DOLE", + "DOLL", + "DOLT", + "DOME", + "DONE", + "DOOM", + "DOOR", + "DORA", + "DOSE", + "DOTE", + "DOUG", + "DOUR", + "DOVE", + "DOWN", + "DRAB", + "DRAG", + "DRAM", + "DRAW", + "DREW", + "DRUB", + "DRUG", + "DRUM", + "DUAL", + "DUCK", + "DUCT", + "DUEL", + "DUET", + "DUKE", + "DULL", + "DUMB", + "DUNE", + "DUNK", + "DUSK", + "DUST", + "DUTY", + "EACH", + "EARL", + "EARN", + "EASE", + "EAST", + "EASY", + "EBEN", + "ECHO", + "EDDY", + "EDEN", + "EDGE", + "EDGY", + "EDIT", + "EDNA", + "EGAN", + "ELAN", + "ELBA", + "ELLA", + "ELSE", + "EMIL", + "EMIT", + "EMMA", + "ENDS", + "ERIC", + "EROS", + "EVEN", + "EVER", + "EVIL", + "EYED", + "FACE", + "FACT", + "FADE", + "FAIL", + "FAIN", + "FAIR", + "FAKE", + "FALL", + "FAME", + "FANG", + "FARM", + "FAST", + "FATE", + "FAWN", + "FEAR", + "FEAT", + "FEED", + "FEEL", + "FEET", + "FELL", + "FELT", + "FEND", + "FERN", + "FEST", + "FEUD", + "FIEF", + "FIGS", + "FILE", + "FILL", + "FILM", + "FIND", + "FINE", + "FINK", + "FIRE", + "FIRM", + "FISH", + "FISK", + "FIST", + "FITS", + "FIVE", + "FLAG", + "FLAK", + "FLAM", + "FLAT", + "FLAW", + "FLEA", + "FLED", + "FLEW", + "FLIT", + "FLOC", + "FLOG", + "FLOW", + "FLUB", + "FLUE", + "FOAL", + "FOAM", + "FOGY", + "FOIL", + "FOLD", + "FOLK", + "FOND", + "FONT", + "FOOD", + "FOOL", + "FOOT", + "FORD", + "FORE", + "FORK", + "FORM", + "FORT", + "FOSS", + "FOUL", + "FOUR", + "FOWL", + "FRAU", + "FRAY", + "FRED", + "FREE", + "FRET", + "FREY", + "FROG", + "FROM", + "FUEL", + "FULL", + "FUME", + "FUND", + "FUNK", + "FURY", + "FUSE", + "FUSS", + "GAFF", + "GAGE", + "GAIL", + "GAIN", + "GAIT", + "GALA", + "GALE", + "GALL", + "GALT", + "GAME", + "GANG", + "GARB", + "GARY", + "GASH", + "GATE", + "GAUL", + "GAUR", + "GAVE", + "GAWK", + "GEAR", + "GELD", + "GENE", + "GENT", + "GERM", + "GETS", + "GIBE", + "GIFT", + "GILD", + "GILL", + "GILT", + "GINA", + "GIRD", + "GIRL", + "GIST", + "GIVE", + "GLAD", + "GLEE", + "GLEN", + "GLIB", + "GLOB", + "GLOM", + "GLOW", + "GLUE", + "GLUM", + "GLUT", + "GOAD", + "GOAL", + "GOAT", + "GOER", + "GOES", + "GOLD", + "GOLF", + "GONE", + "GONG", + "GOOD", + "GOOF", + "GORE", + "GORY", + "GOSH", + "GOUT", + "GOWN", + "GRAB", + "GRAD", + "GRAY", + "GREG", + "GREW", + "GREY", + "GRID", + "GRIM", + "GRIN", + "GRIT", + "GROW", + "GRUB", + "GULF", + "GULL", + "GUNK", + "GURU", + "GUSH", + "GUST", + "GWEN", + "GWYN", + "HAAG", + "HAAS", + "HACK", + "HAIL", + "HAIR", + "HALE", + "HALF", + "HALL", + "HALO", + "HALT", + "HAND", + "HANG", + "HANK", + "HANS", + "HARD", + "HARK", + "HARM", + "HART", + "HASH", + "HAST", + "HATE", + "HATH", + "HAUL", + "HAVE", + "HAWK", + "HAYS", + "HEAD", + "HEAL", + "HEAR", + "HEAT", + "HEBE", + "HECK", + "HEED", + "HEEL", + "HEFT", + "HELD", + "HELL", + "HELM", + "HERB", + "HERD", + "HERE", + "HERO", + "HERS", + "HESS", + "HEWN", + "HICK", + "HIDE", + "HIGH", + "HIKE", + "HILL", + "HILT", + "HIND", + "HINT", + "HIRE", + "HISS", + "HIVE", + "HOBO", + "HOCK", + "HOFF", + "HOLD", + "HOLE", + "HOLM", + "HOLT", + "HOME", + "HONE", + "HONK", + "HOOD", + "HOOF", + "HOOK", + "HOOT", + "HORN", + "HOSE", + "HOST", + "HOUR", + "HOVE", + "HOWE", + "HOWL", + "HOYT", + "HUCK", + "HUED", + "HUFF", + "HUGE", + "HUGH", + "HUGO", + "HULK", + "HULL", + "HUNK", + "HUNT", + "HURD", + "HURL", + "HURT", + "HUSH", + "HYDE", + "HYMN", + "IBIS", + "ICON", + "IDEA", + "IDLE", + "IFFY", + "INCA", + "INCH", + "INTO", + "IONS", + "IOTA", + "IOWA", + "IRIS", + "IRMA", + "IRON", + "ISLE", + "ITCH", + "ITEM", + "IVAN", + "JACK", + "JADE", + "JAIL", + "JAKE", + "JANE", + "JAVA", + "JEAN", + "JEFF", + "JERK", + "JESS", + "JEST", + "JIBE", + "JILL", + "JILT", + "JIVE", + "JOAN", + "JOBS", + "JOCK", + "JOEL", + "JOEY", + "JOHN", + "JOIN", + "JOKE", + "JOLT", + "JOVE", + "JUDD", + "JUDE", + "JUDO", + "JUDY", + "JUJU", + "JUKE", + "JULY", + "JUNE", + "JUNK", + "JUNO", + "JURY", + "JUST", + "JUTE", + "KAHN", + "KALE", + "KANE", + "KANT", + "KARL", + "KATE", + "KEEL", + "KEEN", + "KENO", + "KENT", + "KERN", + "KERR", + "KEYS", + "KICK", + "KILL", + "KIND", + "KING", + "KIRK", + "KISS", + "KITE", + "KLAN", + "KNEE", + "KNEW", + "KNIT", + "KNOB", + "KNOT", + "KNOW", + "KOCH", + "KONG", + "KUDO", + "KURD", + "KURT", + "KYLE", + "LACE", + "LACK", + "LACY", + "LADY", + "LAID", + "LAIN", + "LAIR", + "LAKE", + "LAMB", + "LAME", + "LAND", + "LANE", + "LANG", + "LARD", + "LARK", + "LASS", + "LAST", + "LATE", + "LAUD", + "LAVA", + "LAWN", + "LAWS", + "LAYS", + "LEAD", + "LEAF", + "LEAK", + "LEAN", + "LEAR", + "LEEK", + "LEER", + "LEFT", + "LEND", + "LENS", + "LENT", + "LEON", + "LESK", + "LESS", + "LEST", + "LETS", + "LIAR", + "LICE", + "LICK", + "LIED", + "LIEN", + "LIES", + "LIEU", + "LIFE", + "LIFT", + "LIKE", + "LILA", + "LILT", + "LILY", + "LIMA", + "LIMB", + "LIME", + "LIND", + "LINE", + "LINK", + "LINT", + "LION", + "LISA", + "LIST", + "LIVE", + "LOAD", + "LOAF", + "LOAM", + "LOAN", + "LOCK", + "LOFT", + "LOGE", + "LOIS", + "LOLA", + "LONE", + "LONG", + "LOOK", + "LOON", + "LOOT", + "LORD", + "LORE", + "LOSE", + "LOSS", + "LOST", + "LOUD", + "LOVE", + "LOWE", + "LUCK", + "LUCY", + "LUGE", + "LUKE", + "LULU", + "LUND", + "LUNG", + "LURA", + "LURE", + "LURK", + "LUSH", + "LUST", + "LYLE", + "LYNN", + "LYON", + "LYRA", + "MACE", + "MADE", + "MAGI", + "MAID", + "MAIL", + "MAIN", + "MAKE", + "MALE", + "MALI", + "MALL", + "MALT", + "MANA", + "MANN", + "MANY", + "MARC", + "MARE", + "MARK", + "MARS", + "MART", + "MARY", + "MASH", + "MASK", + "MASS", + "MAST", + "MATE", + "MATH", + "MAUL", + "MAYO", + "MEAD", + "MEAL", + "MEAN", + "MEAT", + "MEEK", + "MEET", + "MELD", + "MELT", + "MEMO", + "MEND", + "MENU", + "MERT", + "MESH", + "MESS", + "MICE", + "MIKE", + "MILD", + "MILE", + "MILK", + "MILL", + "MILT", + "MIMI", + "MIND", + "MINE", + "MINI", + "MINK", + "MINT", + "MIRE", + "MISS", + "MIST", + "MITE", + "MITT", + "MOAN", + "MOAT", + "MOCK", + "MODE", + "MOLD", + "MOLE", + "MOLL", + "MOLT", + "MONA", + "MONK", + "MONT", + "MOOD", + "MOON", + "MOOR", + "MOOT", + "MORE", + "MORN", + "MORT", + "MOSS", + "MOST", + "MOTH", + "MOVE", + "MUCH", + "MUCK", + "MUDD", + "MUFF", + "MULE", + "MULL", + "MURK", + "MUSH", + "MUST", + "MUTE", + "MUTT", + "MYRA", + "MYTH", + "NAGY", + "NAIL", + "NAIR", + "NAME", + "NARY", + "NASH", + "NAVE", + "NAVY", + "NEAL", + "NEAR", + "NEAT", + "NECK", + "NEED", + "NEIL", + "NELL", + "NEON", + "NERO", + "NESS", + "NEST", + "NEWS", + "NEWT", + "NIBS", + "NICE", + "NICK", + "NILE", + "NINA", + "NINE", + "NOAH", + "NODE", + "NOEL", + "NOLL", + "NONE", + "NOOK", + "NOON", + "NORM", + "NOSE", + "NOTE", + "NOUN", + "NOVA", + "NUDE", + "NULL", + "NUMB", + "OATH", + "OBEY", + "OBOE", + "ODIN", + "OHIO", + "OILY", + "OINT", + "OKAY", + "OLAF", + "OLDY", + "OLGA", + "OLIN", + "OMAN", + "OMEN", + "OMIT", + "ONCE", + "ONES", + "ONLY", + "ONTO", + "ONUS", + "ORAL", + "ORGY", + "OSLO", + "OTIS", + "OTTO", + "OUCH", + "OUST", + "OUTS", + "OVAL", + "OVEN", + "OVER", + "OWLY", + "OWNS", + "QUAD", + "QUIT", + "QUOD", + "RACE", + "RACK", + "RACY", + "RAFT", + "RAGE", + "RAID", + "RAIL", + "RAIN", + "RAKE", + "RANK", + "RANT", + "RARE", + "RASH", + "RATE", + "RAVE", + "RAYS", + "READ", + "REAL", + "REAM", + "REAR", + "RECK", + "REED", + "REEF", + "REEK", + "REEL", + "REID", + "REIN", + "RENA", + "REND", + "RENT", + "REST", + "RICE", + "RICH", + "RICK", + "RIDE", + "RIFT", + "RILL", + "RIME", + "RING", + "RINK", + "RISE", + "RISK", + "RITE", + "ROAD", + "ROAM", + "ROAR", + "ROBE", + "ROCK", + "RODE", + "ROIL", + "ROLL", + "ROME", + "ROOD", + "ROOF", + "ROOK", + "ROOM", + "ROOT", + "ROSA", + "ROSE", + "ROSS", + "ROSY", + "ROTH", + "ROUT", + "ROVE", + "ROWE", + "ROWS", + "RUBE", + "RUBY", + "RUDE", + "RUDY", + "RUIN", + "RULE", + "RUNG", + "RUNS", + "RUNT", + "RUSE", + "RUSH", + "RUSK", + "RUSS", + "RUST", + "RUTH", + "SACK", + "SAFE", + "SAGE", + "SAID", + "SAIL", + "SALE", + "SALK", + "SALT", + "SAME", + "SAND", + "SANE", + "SANG", + "SANK", + "SARA", + "SAUL", + "SAVE", + "SAYS", + "SCAN", + "SCAR", + "SCAT", + "SCOT", + "SEAL", + "SEAM", + "SEAR", + "SEAT", + "SEED", + "SEEK", + "SEEM", + "SEEN", + "SEES", + "SELF", + "SELL", + "SEND", + "SENT", + "SETS", + "SEWN", + "SHAG", + "SHAM", + "SHAW", + "SHAY", + "SHED", + "SHIM", + "SHIN", + "SHOD", + "SHOE", + "SHOT", + "SHOW", + "SHUN", + "SHUT", + "SICK", + "SIDE", + "SIFT", + "SIGH", + "SIGN", + "SILK", + "SILL", + "SILO", + "SILT", + "SINE", + "SING", + "SINK", + "SIRE", + "SITE", + "SITS", + "SITU", + "SKAT", + "SKEW", + "SKID", + "SKIM", + "SKIN", + "SKIT", + "SLAB", + "SLAM", + "SLAT", + "SLAY", + "SLED", + "SLEW", + "SLID", + "SLIM", + "SLIT", + "SLOB", + "SLOG", + "SLOT", + "SLOW", + "SLUG", + "SLUM", + "SLUR", + "SMOG", + "SMUG", + "SNAG", + "SNOB", + "SNOW", + "SNUB", + "SNUG", + "SOAK", + "SOAR", + "SOCK", + "SODA", + "SOFA", + "SOFT", + "SOIL", + "SOLD", + "SOME", + "SONG", + "SOON", + "SOOT", + "SORE", + "SORT", + "SOUL", + "SOUR", + "SOWN", + "STAB", + "STAG", + "STAN", + "STAR", + "STAY", + "STEM", + "STEW", + "STIR", + "STOW", + "STUB", + "STUN", + "SUCH", + "SUDS", + "SUIT", + "SULK", + "SUMS", + "SUNG", + "SUNK", + "SURE", + "SURF", + "SWAB", + "SWAG", + "SWAM", + "SWAN", + "SWAT", + "SWAY", + "SWIM", + "SWUM", + "TACK", + "TACT", + "TAIL", + "TAKE", + "TALE", + "TALK", + "TALL", + "TANK", + "TASK", + "TATE", + "TAUT", + "TEAL", + "TEAM", + "TEAR", + "TECH", + "TEEM", + "TEEN", + "TEET", + "TELL", + "TEND", + "TENT", + "TERM", + "TERN", + "TESS", + "TEST", + "THAN", + "THAT", + "THEE", + "THEM", + "THEN", + "THEY", + "THIN", + "THIS", + "THUD", + "THUG", + "TICK", + "TIDE", + "TIDY", + "TIED", + "TIER", + "TILE", + "TILL", + "TILT", + "TIME", + "TINA", + "TINE", + "TINT", + "TINY", + "TIRE", + "TOAD", + "TOGO", + "TOIL", + "TOLD", + "TOLL", + "TONE", + "TONG", + "TONY", + "TOOK", + "TOOL", + "TOOT", + "TORE", + "TORN", + "TOTE", + "TOUR", + "TOUT", + "TOWN", + "TRAG", + "TRAM", + "TRAY", + "TREE", + "TREK", + "TRIG", + "TRIM", + "TRIO", + "TROD", + "TROT", + "TROY", + "TRUE", + "TUBA", + "TUBE", + "TUCK", + "TUFT", + "TUNA", + "TUNE", + "TUNG", + "TURF", + "TURN", + "TUSK", + "TWIG", + "TWIN", + "TWIT", + "ULAN", + "UNIT", + "URGE", + "USED", + "USER", + "USES", + "UTAH", + "VAIL", + "VAIN", + "VALE", + "VARY", + "VASE", + "VAST", + "VEAL", + "VEDA", + "VEIL", + "VEIN", + "VEND", + "VENT", + "VERB", + "VERY", + "VETO", + "VICE", + "VIEW", + "VINE", + "VISE", + "VOID", + "VOLT", + "VOTE", + "WACK", + "WADE", + "WAGE", + "WAIL", + "WAIT", + "WAKE", + "WALE", + "WALK", + "WALL", + "WALT", + "WAND", + "WANE", + "WANG", + "WANT", + "WARD", + "WARM", + "WARN", + "WART", + "WASH", + "WAST", + "WATS", + "WATT", + "WAVE", + "WAVY", + "WAYS", + "WEAK", + "WEAL", + "WEAN", + "WEAR", + "WEED", + "WEEK", + "WEIR", + "WELD", + "WELL", + "WELT", + "WENT", + "WERE", + "WERT", + "WEST", + "WHAM", + "WHAT", + "WHEE", + "WHEN", + "WHET", + "WHOA", + "WHOM", + "WICK", + "WIFE", + "WILD", + "WILL", + "WIND", + "WINE", + "WING", + "WINK", + "WINO", + "WIRE", + "WISE", + "WISH", + "WITH", + "WOLF", + "WONT", + "WOOD", + "WOOL", + "WORD", + "WORE", + "WORK", + "WORM", + "WORN", + "WOVE", + "WRIT", + "WYNN", + "YALE", + "YANG", + "YANK", + "YARD", + "YARN", + "YAWL", + "YAWN", + "YEAH", + "YEAR", + "YELL", + "YOGA", + "YOKE" +}; + +/* Encode 8 bytes in 'c' as a string of English words. + * Returns a pointer to a static buffer + */ +char * + btoe (engout, c) + char *c, *engout; +{ + char cp[9]; /* add in room for the parity 2 bits */ + int p, i; + + engout[0] = '\0'; + memcpy (cp, c, 8); + /* compute parity */ + for (p = 0, i = 0; i < 64; i += 2) + p += extract (cp, i, 2); + + cp[8] = (char) p << 6; + + strncat (engout, &Wp[extract (cp, 0, 11)][0], 4); + strcat (engout, " "); + strncat (engout, &Wp[extract (cp, 11, 11)][0], 4); + strcat (engout, " "); + strncat (engout, &Wp[extract (cp, 22, 11)][0], 4); + strcat (engout, " "); + strncat (engout, &Wp[extract (cp, 33, 11)][0], 4); + strcat (engout, " "); + strncat (engout, &Wp[extract (cp, 44, 11)][0], 4); + strcat (engout, " "); + strncat (engout, &Wp[extract (cp, 55, 11)][0], 4); + +#ifdef notdef + printf ("engout is %s\n\r", engout); +#endif + return (engout); +} + +/* convert English to binary + * returns 1 OK - all good words and parity is OK + * 0 word not in data base + * -1 badly formed in put ie > 4 char word + * -2 words OK but parity is wrong + */ +int + etob (out, e) + char *out; + char *e; +{ + char *word; + int i, p, v, l, low, high; + char b[9]; + char input[36]; + + if (e == NULL) + return -1; + + strncpy (input, e, sizeof (input)); + memset (b, 0, sizeof (b)); + memset (out, 0, 8); + for (i = 0, p = 0; i < 6; i++, p += 11) + { + if ((word = strtok (i == 0 ? input : NULL, " ")) == NULL) + return -1; + + l = strlen (word); + if (l > 4 || l < 1) + return -1; + else if (l < 4) + { + low = 0; + high = 570; + } + else + { + low = 571; + high = 2047; + } + standard (word); + + if ((v = wsrch (word, low, high)) < 0) + return 0; + + insert (b, v, p, 11); + } + + /* now check the parity of what we got */ + for (p = 0, i = 0; i < 64; i += 2) + p += extract (b, i, 2); + + if ((p & 3) != extract (b, 64, 2)) + return -2; + + memcpy (out, b, 8); + + return 1; +} + +/* Display 8 bytes as a series of 16-bit hex digits */ +char * + put8 (out, s) + char *out; + char *s; +{ + sprintf (out, "%02X%02X %02X%02X %02X%02X %02X%02X", + s[0] & 0xff, s[1] & 0xff, s[2] & 0xff, + s[3] & 0xff, s[4] & 0xff, s[5] & 0xff, + s[6] & 0xff, s[7] & 0xff); + return out; +} + +#ifdef notdef +/* Encode 8 bytes in 'cp' as stream of ascii letters. + * Provided as a possible alternative to btoe() + */ +char * + btoc (cp) + char *cp; +{ + int i; + static char out[31]; + + /* code out put by characters 6 bits each added to 0x21 (!) */ + for (i = 0; i <= 10; i++) + { + /* last one is only 4 bits not 6 */ + out[i] = '!' + extract (cp, 6 * i, i >= 10 ? 4 : 6); + } + out[i] = '\0'; + return (out); +} + +#endif + +/* Internal subroutines for word encoding/decoding */ + +/* Dictionary binary search */ +static int + wsrch (w, low, high) + char *w; + int low, high; +{ + int i, j; + + for (;;) + { + i = (low + high) / 2; + if ((j = strncmp (w, Wp[i], 4)) == 0) + return i; /* Found it */ + if (high == low + 1) + { + /* Avoid effects of integer truncation in /2 */ + if (strncmp (w, Wp[high], 4) == 0) + return high; + else + return -1; + } + if (low >= high) + return -1; /* I don't *think* this can happen... */ + if (j < 0) + high = i; /* Search lower half */ + else + low = i; /* Search upper half */ + } +} +static void + insert (s, x, start, length) + char *s; + int x; + int start, length; +{ + unsigned char cl; + unsigned char cc; + unsigned char cr; + unsigned long y; + int shift; + + assert (length <= 11); + assert (start >= 0); + assert (length >= 0); + assert (start + length <= 66); + + shift = ((8 - ((start + length) % 8)) % 8); + y = (long) x << shift; + cl = (y >> 16) & 0xff; + cc = (y >> 8) & 0xff; + cr = y & 0xff; + if (shift + length > 16) + { + s[start / 8] |= cl; + s[start / 8 + 1] |= cc; + s[start / 8 + 2] |= cr; + } + else if (shift + length > 8) + { + s[start / 8] |= cc; + s[start / 8 + 1] |= cr; + } + else + { + s[start / 8] |= cr; + } +} + +static void + standard (word) + register char *word; +{ + while (*word) + { + if (!isascii (*word)) + break; + if (islower (*word)) + *word = toupper (*word); + if (*word == '1') + *word = 'L'; + if (*word == '0') + *word = 'O'; + if (*word == '5') + *word = 'S'; + word++; + } +} + +/* Extract 'length' bits from the char array 's' starting with bit 'start' */ +static unsigned long + extract (s, start, length) + char *s; + int start, length; +{ + unsigned char cl; + unsigned char cc; + unsigned char cr; + unsigned long x; + + assert (length <= 11); + assert (start >= 0); + assert (length >= 0); + assert (start + length <= 66); + + cl = s[start / 8]; + cc = s[start / 8 + 1]; + cr = s[start / 8 + 2]; + x = ((long) (cl << 8 | cc) << 8 | cr); + x = x >> (24 - (length + (start % 8))); + x = (x & (0xffff >> (16 - length))); + return (x); +} diff --git a/lib/libskey/shlib_version b/lib/libskey/shlib_version new file mode 100644 index 00000000000..97c9f92d6b8 --- /dev/null +++ b/lib/libskey/shlib_version @@ -0,0 +1,2 @@ +major=0 +minor=0 diff --git a/lib/libskey/skey.h b/lib/libskey/skey.h new file mode 100644 index 00000000000..1cc7c4a4b1c --- /dev/null +++ b/lib/libskey/skey.h @@ -0,0 +1,77 @@ +/* + * S/KEY v1.1b (skey.h) + * + * Authors: + * Neil M. Haller <nmh@thumper.bellcore.com> + * Philip R. Karn <karn@chicago.qualcomm.com> + * John S. Walden <jsw@thumper.bellcore.com> + * + * Modifications: + * Scott Chasin <chasin@crimelab.com> + * + * Main client header + * + * $Id: skey.h,v 1.1 1995/10/18 08:43:11 deraadt Exp $ + */ + +#if defined(__TURBOC__) || defined(__STDC__) || defined(LATTICE) +#define ANSIPROTO 1 +#endif + +#ifndef __ARGS +#ifdef ANSIPROTO +#define __ARGS(x) x +#else +#define __ARGS(x) () +#endif +#endif + +#ifdef SOLARIS +#define setpriority(x,y,z) z +#endif + +/* Server-side data structure for reading keys file during login */ +struct skey +{ + FILE *keyfile; + char buf[256]; + char *logname; + int n; + char *seed; + char *val; + long recstart; /* needed so reread of buffer is efficient */ + + +}; + +/* Client-side structure for scanning data stream for challenge */ +struct mc +{ + char buf[256]; + int skip; + int cnt; +}; + +void f __ARGS ((char *x)); +int keycrunch __ARGS ((char *result, char *seed, char *passwd)); +char *btoe __ARGS ((char *engout, char *c)); +char *put8 __ARGS ((char *out, char *s)); +int etob __ARGS ((char *out, char *e)); +void rip __ARGS ((char *buf)); +int skeychallenge __ARGS ((struct skey * mp, char *name, char *ss)); +int skeylookup __ARGS ((struct skey * mp, char *name)); +int skeyverify __ARGS ((struct skey * mp, char *response)); +void sevenbit __ARGS ((char *s)); +void backspace __ARGS ((char *s)); +char *skipspace __ARGS ((char *s)); +char *readpass __ARGS ((char *buf, int n)); +char *readskey __ARGS ((char *buf, int n)); +int skey_authenticate __ARGS ((char *)); +int skey_passcheck __ARGS ((char *, char *)); +char *skey_keyinfo __ARGS ((char *)); +int skey_haskey __ARGS ((char *)); +int getskeyprompt __ARGS ((struct skey *, char *, char *)); +int atob8 __ARGS((char *, char *)); +int btoa8 __ARGS((char *, char *)); +int htoi __ARGS((char)); + diff --git a/lib/libskey/skeylogin.c b/lib/libskey/skeylogin.c new file mode 100644 index 00000000000..0c7a7feaa6a --- /dev/null +++ b/lib/libskey/skeylogin.c @@ -0,0 +1,366 @@ +/* S/KEY v1.1b (skeylogin.c) + * + * Authors: + * Neil M. Haller <nmh@thumper.bellcore.com> + * Philip R. Karn <karn@chicago.qualcomm.com> + * John S. Walden <jsw@thumper.bellcore.com> + * Scott Chasin <chasin@crimelab.com> + * + * S/KEY verification check, lookups, and authentication. + * + * $Id: skeylogin.c,v 1.1 1995/10/18 08:43:11 deraadt Exp $ + */ + +#include <sys/param.h> +#ifdef QUOTA +#include <sys/quota.h> +#endif +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/resource.h> + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <errno.h> + +#include "skey.h" + +#define _PATH_KEYFILE "/etc/skeykeys" + +char *skipspace __ARGS((char *)); +int skeylookup __ARGS((struct skey *, char *)); + +/* Issue a skey challenge for user 'name'. If successful, + * fill in the caller's skey structure and return 0. If unsuccessful + * (e.g., if name is unknown) return -1. + * + * The file read/write pointer is left at the start of the + * record. + */ +int +getskeyprompt(mp,name,prompt) + struct skey *mp; + char *name; + char *prompt; +{ + int rval; + + sevenbit(name); + rval = skeylookup(mp,name); + strcpy(prompt,"s/key 55 latour1\n"); + switch (rval) { + case -1: /* File error */ + return -1; + case 0: /* Lookup succeeded, return challenge */ + sprintf(prompt,"s/key %d %s\n",mp->n - 1,mp->seed); + return 0; + case 1: /* User not found */ + fclose(mp->keyfile); + return -1; + } + return -1; /* Can't happen */ +} + +/* Return a skey challenge string for user 'name'. If successful, + * fill in the caller's skey structure and return 0. If unsuccessful + * (e.g., if name is unknown) return -1. + * + * The file read/write pointer is left at the start of the + * record. + */ +int +skeychallenge(mp,name, ss) + struct skey *mp; + char *name; + char *ss; +{ + int rval; + + rval = skeylookup(mp,name); + switch(rval){ + case -1: /* File error */ + return -1; + case 0: /* Lookup succeeded, issue challenge */ + sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed); + return 0; + case 1: /* User not found */ + fclose(mp->keyfile); + return -1; + } + return -1; /* Can't happen */ +} + +/* Find an entry in the One-time Password database. + * Return codes: + * -1: error in opening database + * 0: entry found, file R/W pointer positioned at beginning of record + * 1: entry not found, file R/W pointer positioned at EOF + */ +int +skeylookup(mp,name) + struct skey *mp; + char *name; +{ + int found; + int len; + long recstart; + char *cp; + struct stat statbuf; + + /* See if the _PATH_KEYFILE exists, and create it if not */ + + if (stat(_PATH_KEYFILE,&statbuf) == -1 && errno == ENOENT) { + mp->keyfile = fopen(_PATH_KEYFILE,"w+"); + if (mp->keyfile) + chmod(_PATH_KEYFILE, 0644); + } else { + /* Otherwise open normally for update */ + mp->keyfile = fopen(_PATH_KEYFILE,"r+"); + } + if (mp->keyfile == NULL) + return -1; + + /* Look up user name in database */ + len = strlen(name); + if( len > 8 ) len = 8; /* Added 8/2/91 - nmh */ + found = 0; + while (!feof(mp->keyfile)) { + recstart = ftell(mp->keyfile); + mp->recstart = recstart; + if (fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf) { + break; + } + rip(mp->buf); + if (mp->buf[0] == '#') + continue; /* Comment */ + if ((mp->logname = strtok(mp->buf," \t")) == NULL) + continue; + if ((cp = strtok(NULL," \t")) == NULL) + continue; + mp->n = atoi(cp); + if ((mp->seed = strtok(NULL," \t")) == NULL) + continue; + if ((mp->val = strtok(NULL," \t")) == NULL) + continue; + if (strlen(mp->logname) == len + && strncmp(mp->logname,name,len) == 0){ + found = 1; + break; + } + } + if (found) { + fseek(mp->keyfile,recstart,0); + return 0; + } else + return 1; +} +/* Verify response to a s/key challenge. + * + * Return codes: + * -1: Error of some sort; database unchanged + * 0: Verify successful, database updated + * 1: Verify failed, database unchanged + * + * The database file is always closed by this call. + */ +int +skeyverify(mp,response) + struct skey *mp; + char *response; +{ + char key[8]; + char fkey[8]; + char filekey[8]; + time_t now; + struct tm *tm; + char tbuf[27]; + char *cp; + + time(&now); + tm = localtime(&now); + strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm); + + if (response == NULL) { + fclose(mp->keyfile); + return -1; + } + rip(response); + + /* Convert response to binary */ + if (etob(key, response) != 1 && atob8(key, response) != 0) { + /* Neither english words or ascii hex */ + fclose(mp->keyfile); + return -1; + } + + /* Compute fkey = f(key) */ + memcpy(fkey,key,sizeof(key)); + fflush (stdout); + + f(fkey); + /* + * in order to make the window of update as short as possible + * we must do the comparison here and if OK write it back + * other wise the same password can be used twice to get in + * to the system + */ + + setpriority(PRIO_PROCESS, 0, -4); + + /* reread the file record NOW*/ + + fseek(mp->keyfile,mp->recstart,0); + if (fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){ + setpriority(PRIO_PROCESS, 0, 0); + fclose(mp->keyfile); + return -1; + } + rip(mp->buf); + mp->logname = strtok(mp->buf," \t"); + cp = strtok(NULL," \t") ; + mp->seed = strtok(NULL," \t"); + mp->val = strtok(NULL," \t"); + /* And convert file value to hex for comparison */ + atob8(filekey,mp->val); + + /* Do actual comparison */ + fflush (stdout); + + if (memcmp(filekey,fkey,8) != 0){ + /* Wrong response */ + setpriority(PRIO_PROCESS, 0, 0); + fclose(mp->keyfile); + return 1; + } + + /* + * Update key in database by overwriting entire record. Note + * that we must write exactly the same number of bytes as in + * the original record (note fixed width field for N) + */ + btoa8(mp->val,key); + mp->n--; + fseek(mp->keyfile,mp->recstart,0); + fprintf(mp->keyfile, "%s %04d %-16s %s %-21s\n", + mp->logname,mp->n,mp->seed, mp->val, tbuf); + + fclose(mp->keyfile); + + setpriority(PRIO_PROCESS, 0, 0); + return 0; +} + + +/* + * skey_haskey () + * + * Returns: 1 user doesnt exist, -1 fle error, 0 user exists. + * + */ + +int +skey_haskey (username) + char *username; +{ + int i; + struct skey skey; + + return (skeylookup (&skey, username)); +} + +/* + * skey_keyinfo () + * + * Returns the current sequence number and + * seed for the passed user. + * + */ +char * +skey_keyinfo (username) + char *username; +{ + int i; + static char str [50]; + struct skey skey; + + i = skeychallenge (&skey, username, str); + if (i == -1) + return 0; + + return str; +} + +/* + * skey_passcheck () + * + * Check to see if answer is the correct one to the current + * challenge. + * + * Returns: 0 success, -1 failure + * + */ + +int +skey_passcheck (username, passwd) + char *username, *passwd; +{ + int i; + struct skey skey; + + i = skeylookup (&skey, username); + if (i == -1 || i == 1) + return -1; + + if (skeyverify (&skey, passwd) == 0) + return skey.n; + + return -1; +} + +/* + * skey_authenticate () + * + * Used when calling program will allow input of the user's + * response to the challenge. + * + * Returns: 0 success, -1 failure + * + */ + +int +skey_authenticate (username) + char *username; +{ + int i; + char pbuf[256], skeyprompt[50]; + struct skey skey; + + /* Attempt a S/Key challenge */ + i = skeychallenge (&skey, username, skeyprompt); + + if (i == -2) + return 0; + + printf("[%s]\n", skeyprompt); + fflush(stdout); + + printf("Response: "); + readskey(pbuf, sizeof (pbuf)); + rip(pbuf); + + /* Is it a valid response? */ + if (i == 0 && skeyverify (&skey, pbuf) == 0) { + if (skey.n < 5) { + printf ("\nWarning! Key initialization needed soon. "); + printf ("(%d logins left)\n", skey.n); + } + return 0; + } + return -1; +} diff --git a/lib/libskey/skeysubr.c b/lib/libskey/skeysubr.c new file mode 100644 index 00000000000..232927a1ed5 --- /dev/null +++ b/lib/libskey/skeysubr.c @@ -0,0 +1,317 @@ +/* S/KEY v1.1b (skeysubr.c) + * + * Authors: + * Neil M. Haller <nmh@thumper.bellcore.com> + * Philip R. Karn <karn@chicago.qualcomm.com> + * John S. Walden <jsw@thumper.bellcore.com> + * + * Modifications: + * Scott Chasin <chasin@crimelab.com> + * + * S/KEY misc routines. + * + * $Id: skeysubr.c,v 1.1 1995/10/18 08:43:11 deraadt Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <termios.h> + +#include "md4.h" +#include "skey.h" + +struct termios newtty; +struct termios oldtty; + +static void trapped __ARGS((int sig)); +static void set_term __ARGS((void)); +static void unset_term __ARGS((void)); +static void echo_off __ARGS((void)); + +/* Crunch a key: + * concatenate the seed and the password, run through MD4 and + * collapse to 64 bits. This is defined as the user's starting key. + */ +int +keycrunch(result,seed,passwd) +char *result; /* 8-byte result */ +char *seed; /* Seed, any length */ +char *passwd; /* Password, any length */ +{ + char *buf; + MDstruct md; + unsigned int buflen; + int i; + register long tmp; + + buflen = strlen(seed) + strlen(passwd); + if ((buf = (char *)malloc(buflen+1)) == NULL) + return -1; + strcpy(buf,seed); + strcat(buf,passwd); + + /* Crunch the key through MD4 */ + sevenbit(buf); + MDbegin(&md); + MDupdate(&md,(unsigned char *)buf,8*buflen); + + free(buf); + + /* Fold result from 128 to 64 bits */ + md.buffer[0] ^= md.buffer[2]; + md.buffer[1] ^= md.buffer[3]; + + /* Default (but slow) code that will convert to + * little-endian byte ordering on any machine + */ + for (i=0; i<2; i++) { + tmp = md.buffer[i]; + *result++ = tmp; + tmp >>= 8; + *result++ = tmp; + tmp >>= 8; + *result++ = tmp; + tmp >>= 8; + *result++ = tmp; + } + + return 0; +} + +/* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */ +void +f(x) + char *x; +{ + MDstruct md; + register long tmp; + + MDbegin(&md); + MDupdate(&md,(unsigned char *)x,64); + + /* Fold 128 to 64 bits */ + md.buffer[0] ^= md.buffer[2]; + md.buffer[1] ^= md.buffer[3]; + + /* Default (but slow) code that will convert to + * little-endian byte ordering on any machine + */ + tmp = md.buffer[0]; + *x++ = tmp; + tmp >>= 8; + *x++ = tmp; + tmp >>= 8; + *x++ = tmp; + tmp >>= 8; + *x++ = tmp; + + tmp = md.buffer[1]; + *x++ = tmp; + tmp >>= 8; + *x++ = tmp; + tmp >>= 8; + *x++ = tmp; + tmp >>= 8; + *x = tmp; +} + +/* Strip trailing cr/lf from a line of text */ +void +rip(buf) + char *buf; +{ + char *cp; + + if ((cp = strchr(buf,'\r')) != NULL) + *cp = '\0'; + + if ((cp = strchr(buf,'\n')) != NULL) + *cp = '\0'; +} + +char * +readpass (buf,n) + char *buf; + int n; +{ + set_term(); + echo_off(); + + fgets(buf, n, stdin); + + rip(buf); + printf("\n"); + + sevenbit(buf); + + unset_term(); + return buf; +} + +char * +readskey(buf, n) + char *buf; + int n; +{ + fgets (buf, n, stdin); + + rip(buf); + printf ("\n"); + + sevenbit (buf); + + return buf; +} + +static void +set_term() +{ + fflush(stdout); + tcgetattr(fileno(stdin), &newtty); + tcgetattr(fileno(stdin), &oldtty); + + signal (SIGINT, trapped); +} + +static void +echo_off() +{ + newtty.c_lflag &= ~(ICANON | ECHO | ECHONL); + newtty.c_cc[VMIN] = 1; + newtty.c_cc[VTIME] = 0; + newtty.c_cc[VINTR] = 3; + + tcsetattr(fileno(stdin), TCSADRAIN, &newtty); +} + +static void +unset_term() +{ + tcsetattr(fileno(stdin), TCSADRAIN, &oldtty); +} + +static void +trapped(sig) + int sig; +{ + signal(SIGINT, trapped); + printf("^C\n"); + unset_term(); + exit(-1); +} + +/* Convert 8-byte hex-ascii string to binary array + * Returns 0 on success, -1 on error + */ +int +atob8(out, in) + register char *out, *in; +{ + register int i; + register int val; + + if (in == NULL || out == NULL) + return -1; + + for (i=0; i<8; i++) { + if ((in = skipspace(in)) == NULL) + return -1; + if ((val = htoi(*in++)) == -1) + return -1; + *out = val << 4; + + if ((in = skipspace(in)) == NULL) + return -1; + if ((val = htoi(*in++)) == -1) + return -1; + *out++ |= val; + } + return 0; +} + +/* Convert 8-byte binary array to hex-ascii string */ +int +btoa8(out, in) + register char *out, *in; +{ + register int i; + + if (in == NULL || out == NULL) + return -1; + + for (i=0;i<8;i++) { + sprintf(out,"%02x",*in++ & 0xff); + out += 2; + } + return 0; +} + + +/* Convert hex digit to binary integer */ +int +htoi(c) + register char c; +{ + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return 10 + c - 'a'; + if ('A' <= c && c <= 'F') + return 10 + c - 'A'; + return -1; +} + +char * +skipspace(cp) + register char *cp; +{ + while (*cp == ' ' || *cp == '\t') + cp++; + + if (*cp == '\0') + return NULL; + else + return cp; +} + +/* removebackspaced over charaters from the string */ +void +backspace(buf) +char *buf; +{ + char bs = 0x8; + char *cp = buf; + char *out = buf; + + while (*cp) { + if (*cp == bs) { + if (out == buf) { + cp++; + continue; + } + else { + cp++; + out--; + } + } else { + *out++ = *cp++; + } + + } + *out = '\0'; +} + +/* sevenbit () + * + * Make sure line is all seven bits. + */ + +void +sevenbit(s) + char *s; +{ + while (*s) + *s++ &= 0x7f; +} |