/* * Copyright (c) 1996-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ static char RcsId[] = ""; #include #include #include #include #include "global.h" #include "md5.h" /* This is the client side MD5 authenticator. it's derived from an SNK-based "softsnk" which is non-exportable since it uses DES. The SNK version stores the user's secret key codes in an encrypted file on the laptop (encrypted with DES and an encrypted checksum to verify that the user has unlocked it correctly). Softsnk does an SNK-style challenge/response once the file has been unlocked and the key decoded correctly. The MD5 version asks the user for a password, which is hashed into an MD5 value used as a seed for an MD5 checksum. There is an option that can be used to spit out the octets of the checksum seed, which is stored in the authentication database. *WARNING* -- this is example code; it uses getpass() to read the user's passphrase. On some systems, getpass() truncates at 8 chars, which is truly lame. If you have a system that does such a thing, you should make sure to replace/enhance your getpass() routine if you plan to use this code in production. */ extern char *getpass(); typedef unsigned char md5_key_schedule[8]; typedef unsigned char md5_cblock[8]; char kbuf[512]; char challbuf[512]; /* given a decoded key, do a SNK-style challenge/response using MD5 */ static int md5reply(chall,dflg,kbloc) char *chall; int dflg; md5_cblock kbloc; { MD5_CTX keysched; unsigned char digest[16]; char buf[12]; char cbuf[12]; int i; int j; unsigned long kval = 0; /* zeroize the entire buffer */ for(i = 0; i < 9; i++) buf[i] = '\0'; strncpy(buf,chall,8); /* begin MD5 specific code */ MD5Init(&keysched); /* set the "key" (initializer) into MD5 */ MD5Update(&keysched,kbloc,8); /* push response through the rotating knives */ MD5Update(&keysched,buf,8); /* wrap up MD5 into digest */ MD5Final(digest,&keysched); /* emulate DES by pulling 8 bytes into cbuf */ bcopy(digest,cbuf,8); /* done MD5 specific code */ /* pull some bits out of the ciphertext into a long */ for(i=0; i<4; i++) for(j = 0; j < 8; j++) kval = (kval << 1) | ((cbuf[i] >> (7 - j)) & 1); snprintf(buf,sizeof(buf),"%08lx",kval); if(!dflg) { printf("Response: %s\n",buf); return(0); } for(i=0; buf[i]; i++) if(buf[i] == 'a' || buf[i] == 'b' || buf[i] == 'c') buf[i] = '2'; else if(buf[i] == 'd' || buf[i] == 'e' || buf[i] == 'f') buf[i] = '3'; printf("Response: %s\n",buf); return(0); } main(ac,av) int ac; char *av[]; { int x; char *challenge = (char *)0; char *key = (char *)0; int iflg = 0; int dflg = 1; md5_cblock kbloc; for(x = 1; x < ac; x++) { if(av[x][0] == '-') { switch(av[x][1]) { case 'h': dflg = 0; break; case 'c': challenge = av[x+1]; break; case 'k': key = av[x+1]; break; case 'I': iflg = 1; break; default: exit(usage()); } } } /* this uses getpass() which is truly lame, since it truncates to 8 chars. if you have a decent library with a good getpass or getpass compatible routine, it is suggested you replace it here. */ /* if not given key, ask for it */ if(key == (char *)0) { char *pp; if((pp = getpass("Enter key:")) == (char *)0) { fprintf(stderr,"Invalid password\n"); exit(1); } if(iflg) { char b1[512]; strlcpy(b1,pp,512); if((pp = getpass("Repeat key:")) == (char *)0) { fprintf(stderr,"Invalid password\n"); exit(1); } if(strcmp(pp,b1)) { fprintf(stderr,"Passwords do not match\n"); exit(1); } } strlcpy(kbuf,pp,512); key = kbuf; } /* decode user's DES key - MD5 version hashes it into a kblock instead of decrypting the kblock from a file */ if(decode_key(key,kbloc)) exit(1); /* initialize password mode */ if(iflg) exit(initkey(key,kbloc)); /* dropping into challenge/password mode */ if(!iflg && challenge == (char *)0) { fprintf(stderr,"Challenge: "); fflush(stderr); if((challenge = gets(challbuf)) == (char *)0) exit(1); } md5reply(challenge,dflg,kbloc); exit(0); } decode_key(key,kbloc) char *key; md5_cblock kbloc; { MD5_CTX keysched; unsigned char digest[16]; int x; MD5Init(&keysched); MD5Update(&keysched,key,strlen(key)); MD5Final(digest,&keysched); bcopy(digest,kbloc,8); return(0); } initkey(key,kbloc) char *key; md5_cblock kbloc; { int x; printf("Key \"%s\" hashkey = {\n",key); for(x = 0; x < 8; x++) printf("\t%3.3o\n",kbloc[x]); printf("}\n"); } usage() { fprintf(stderr,"usage: softmd5: [-c challenge] [-k key] [-I](initialize)\n"); return(1); }