/* Chalace v0.10 (c) 1994 Julian Assange (proff@suburbia.apana.org.au), * All Rights Reserved. * * This program maybe freely distributed in its original state provided no * profit is made from its use or distribution. * * To compile the client: cc -o -DCLIENT chalace chalace.c md5.c words.c * To compile the server: cc -o -DSERVER chalace chalace.c md5.c words.c * */ #include "conf.h" #ifdef HIDLEHO # define SERVER #endif #if !defined(CLIENT) && !defined(SERVER) # error "You must have CLIENT or SERVER or HIDLEHO!" #endif #if !defined(UNIX) && defined(SERVER) # error "The Chalace server currently only runs under UNIX" #endif #include #include #include #include #ifdef SERVER /* server currntly runs only under unix */ # include # include # include # include # include #endif #include "md5.h" #ifdef NOSTRCASECMP # define strcasecmp strcmp #endif #ifndef TRUE # define TRUE 1 # define FALSE 0 #endif #ifndef SERVER # define SECPATH "secret" #endif extern char *wl[2048]; /* wordlist array from word.c */ #ifdef HIDLEHO extern int err (char *,...); #endif #ifdef SERVER jmp_buf jmp; #endif char * genwords (unsigned long d) /* generate three words from 32 bit number */ { static char words[40]; /* now select from a 1024 * 1024 * 1024 virtual matrix */ /* first and second word share a bit. */ sprintf (words, "%s %s %s", wl[d >> 21 & 0x7ff], wl[d >> 11 & 0x7ff], wl[d & 0x7ff]); return words; } #ifndef NOBSEARCH int bscomp (char **p1, char **p2) { return strcasecmp (*p1, *p2); } #endif unsigned int findword (char *word) /* obtain entry # of word = 11 bits of data */ { #ifndef NOBSEARCH char *p; p = bsearch (&word, wl, 2048, sizeof (char *), bscomp); if (p == NULL) return 0; return (p - (char *) wl) / sizeof (char *); #else /* linear */ int n; for (n = 0; wl[n]; n++) if (!strcasecmp (word, wl[n])) return n; #endif } unsigned long decodewords (char *words) /* three words -> 32 bits of data */ { char word1[10], word2[10], word3[10]; if (!words || (sscanf (words, "%s %s %s", word1, word2, word3) != 3)) return 0; return (findword (word1) << 21) | (findword (word2) << 11) | findword (word3); } unsigned char * shiftint (unsigned long i) /* move 32 bits -> 4 chars */ { static unsigned char c[4]; c[0] = i & 0xff; c[1] = i >> 8 & 0xff; c[2] = i >> 16 & 0xff; c[3] = i >> 24 & 0xff; return c; } unsigned long shiftchar (char *d) /* move 4 chars -> 32bits */ { unsigned long r = 0; r = d[3]; r <<= 8; r |= d[2] & 0xff; r <<= 8; r |= d[1] & 0xff; r <<= 8; r |= d[0] & 0xff; return r; } #ifdef SERVER unsigned long genseed () /* generate cryptographically secure seed */ { MD5_CTX md5_ctx; struct timeval tv, tvo; struct rusage ru; unsigned char d[16]; int n; long *lp; MD5Init (&md5_ctx); MD5Update (&md5_ctx, shiftint (getpid ()), 4); gettimeofday (&tvo, NULL); for (n = 0; !(tv.tv_sec - tvo.tv_sec) || (n < 20); n++) { gettimeofday (&tv, NULL); MD5Update (&md5_ctx, shiftint (tv.tv_sec), 4); MD5Update (&md5_ctx, shiftint (tv.tv_usec), 4); getrusage (getpid (), &ru); MD5Update (&md5_ctx, shiftint (ru.ru_utime.tv_sec), 4); MD5Update (&md5_ctx, shiftint (ru.ru_utime.tv_usec), 4); MD5Update (&md5_ctx, shiftint (ru.ru_stime.tv_sec), 4); MD5Update (&md5_ctx, shiftint (ru.ru_stime.tv_usec), 4); MD5Update (&md5_ctx, shiftint (ru.ru_majflt), 4); MD5Update (&md5_ctx, shiftint (ru.ru_inblock), 4); MD5Update (&md5_ctx, shiftint (ru.ru_oublock), 4); MD5Update (&md5_ctx, shiftint (ru.ru_msgsnd), 4); MD5Update (&md5_ctx, shiftint (ru.ru_msgrcv), 4); MD5Update (&md5_ctx, shiftint (ru.ru_nsignals), 4); } MD5Final (d, &md5_ctx); d[0] ^= d[4] ^ d[8] ^ d[12]; d[1] ^= d[5] ^ d[9] ^ d[13]; d[2] ^= d[6] ^ d[10] ^ d[14]; d[3] ^= d[7] ^ d[11] ^ d[15]; lp = (long *) d; /* 16 chars -> 4 chars -> 32bits */ return (*lp) & 0xffffffffL; } #endif /* one-way-hash secret string with 32bit key */ unsigned long challenge_v (char *secret, unsigned long key) { MD5_CTX md5_ctx; unsigned char d[16]; unsigned long t; MD5Init (&md5_ctx); MD5Update (&md5_ctx, shiftint (key & 0xffffffffL), 4); MD5Update (&md5_ctx, secret, strlen (secret)); MD5Final (d, &md5_ctx); d[0] ^= d[4] ^ d[8] ^ d[12]; d[1] ^= d[5] ^ d[9] ^ d[13]; d[2] ^= d[6] ^ d[10] ^ d[14]; d[3] ^= d[7] ^ d[11] ^ d[15]; t = shiftchar (d); /* we leave with 32 bits of hash */ return t & 0xffffffffL; } char * getsecret (char *fname) /* pull secret out of file */ { static unsigned char sec[80] = ""; FILE *fh; if ((fh = fopen (fname, "r")) == NULL) { #ifdef HIDLEHO err ("Couldn't open secret %s: %m", fname); return NULL; #else perror (fname); exit (1); #endif } fgets (sec, sizeof (sec), fh); if (!sec[0]) { #ifdef HIDLEHO err ("NULL secret from %s: %m", fname); return NULL; #else perror (fname); exit (1); #endif } sec[strlen (sec) - 1] = 0; /* remove line-feed */ return sec; } #ifdef SERVER int do_chalace (char *fname, unsigned long seed) /* main loop */ { unsigned long res; char wb[100]; char *secret; printf ("Challenge = %s\n", genwords (seed)); fflush (stdout); printf ("Enter responce: "); fflush (stdout); fgets (wb, sizeof (wb), stdin); res = decodewords (wb); #ifdef DEBUG printf ("Res = %s\n", genwords (res)); #endif secret = getsecret (fname); if (res == challenge_v (secret, seed)) return TRUE; /* valid */ return FALSE; /* invalid */ } void cha_alrm () { longjmp (jmp, 1); } int chalace (char *fname) { unsigned long seed; int n; static volatile void *oldsig; alarm (0L); oldsig = signal (SIGALRM, cha_alrm); if (setjmp (jmp)) { signal (SIGALRM, oldsig); return -TRUE; } alarm (5 * 60); seed = genseed (); for (n = 0; n < 4; n++) if (do_chalace (fname, seed) == TRUE) return TRUE; alarm (0L); signal (SIGALRM, oldsig); return FALSE; } #ifndef HIDLEHO int main () { int ret; ret = chalace (".secret"); switch (ret) { case TRUE: printf ("valid.\n"); break; case -TRUE: printf ("timeout.\n"); break; case FALSE: printf ("invalid.\n"); break; } exit (ret); } #endif #else /* CLIENT */ int main (int argc, char **argv) { char wb[100] = ""; char sec[100] = ""; char *secret; unsigned long seed, res; if ((argc > 2) || ((argc == 2) && (argv[1][0] == '-'))) { printf ("usage: %s [secret_file]\n", argv[0]); exit (1); } if (argc == 2) { secret = getsecret (argv[1]); } else { printf ("Enter secret: "); fgets (sec, sizeof (sec), stdin); if (!sec[0]) exit (1); sec[strlen (sec) - 1] = '\0'; secret = sec; } while (1) { printf ("Enter challenge: "); fflush (stdout); fgets (wb, sizeof (wb), stdin); if (!wb[0]) exit (0); seed = decodewords (wb); res = challenge_v (secret, seed); printf ("Responce = %s\n", genwords (res)); } } #endif