md5cryptc.tcl

Go to the documentation of this file.
00001 /*  md5cryptc.tcl - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>*/
00002 /* */
00003 /*  This is a critcl-based wrapper to provide a Tcl implementation of the md5crypt*/
00004 /*  function. The C code here is based upon the OpenBSD source, which is in turn*/
00005 /*  derived from the original implementation by Poul-Henning Kamp*/
00006 /* */
00007 /*  The original C source license reads:*/
00008 /* /**/
00009 /*  * ----------------------------------------------------------------------------*/
00010 /*  * "THE BEER-WARE LICENSE" (Revision 42):*/
00011 /*  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you*/
00012 /*  * can do whatever you want with this stuff. If we meet some day, and you think*/
00013 /*  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp*/
00014 /*  * ----------------------------------------------------------------------------*/
00015 /*  */*/
00016 /* */
00017 /*  -------------------------------------------------------------------------*/
00018 /*  See the file "license.terms" for information on usage and redistribution*/
00019 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00020 /*  -------------------------------------------------------------------------*/
00021 
00022 
00023 package require critcl
00024 package provide md5cryptc 1.0
00025 
00026 critcl::cheaders ../md5/md5.h
00027 /* critcl::csources ../md5/md5.c*/
00028 
00029 namespace ::md5crypt {
00030     critcl::ccode {
00031 /* include "md5.h"*/
00032 /* ifdef _MSC_VER*/
00033 /* define snprintf _snprintf*/
00034 /* endif*/
00035         static unsigned char itoa64[] =
00036             "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
00037         
00038         static void to64(char *s, unsigned int v, int n)
00039         {
00040             while (--n >= 0) {
00041                 *s++ = itoa64[v&0x3f];
00042                 v >>= 6;
00043             }
00044         }
00045         
00046         static void dump(const char *s, unsigned int len) 
00047         {
00048             unsigned int i;
00049             for (i = 0; i < len; i++)
00050                 printf("%02X", s[i]&0xFF);
00051             putchar('\n');
00052         }
00053         
00054         static char * md5crypt(const char *pw,
00055                                const char *salt,
00056                                const char *magic)
00057         {
00058             static char     passwd[120], *p;
00059             static const unsigned char *sp,*ep;
00060             unsigned char   final[16];
00061             int sl,pl,i;
00062             MD5_CTX ctx,ctx1;
00063             unsigned long l;
00064             
00065             /* Refine the Salt first */
00066             sp = (const unsigned char *)salt;
00067             
00068             /* If it starts with the magic string, then skip that */
00069             if(!strncmp((const char *)sp,(const char *)magic,strlen((const char *)magic)))
00070                 sp += strlen((const char *)magic);
00071             
00072             /* It stops at the first '$', max 8 chars */
00073             for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
00074                 continue;
00075             
00076             /* get the length of the true salt */
00077             sl = ep - sp;
00078             
00079             MD5Init(&ctx);
00080             
00081             /* The password first, since that is what is most unknown */
00082             MD5Update(&ctx,(const unsigned char *)pw,strlen(pw));
00083             
00084             /* Then our magic string */
00085             MD5Update(&ctx,magic,strlen((const char *)magic));
00086             
00087             /* Then the raw salt */
00088             MD5Update(&ctx,sp,sl);
00089             
00090             /* Then just as many characters of the MD5(pw,salt,pw) */
00091             MD5Init(&ctx1);
00092             MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
00093             MD5Update(&ctx1,sp,sl);
00094             MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
00095             MD5Final(final,&ctx1);
00096             
00097             for(pl = strlen(pw); pl > 0; pl -= 16) {
00098                 int tl = pl > 16 ? 16 : pl;
00099                 MD5Update(&ctx,final,pl>16 ? 16 : pl);
00100             }
00101             
00102             /* Don't leave anything around in vm they could use. */
00103             mem(final = ,0,sizeof final);
00104             
00105             /* Then something really weird... */
00106             for (i = strlen(pw); i ; i >>= 1) {
00107                 if(i&1)
00108                     MD5Update(&ctx, final, 1);
00109                 else
00110                     MD5Update(&ctx, (const unsigned char *)pw, 1);
00111             }
00112             
00113             /* Now make the output string */
00114             snprintf(passwd, sizeof(passwd), "%s%.*s$", (char *)magic,
00115                     sl, (const char *)sp);
00116             
00117             MD5Final(final,&ctx);
00118             
00119             /*
00120              * and now, just to make sure things don't run too fast
00121              * On a 60 Mhz Pentium this takes 34 msec, so you would
00122              * need 30 seconds to build a 1000 entry dictionary...
00123              */
00124             for(i=0;i<1000;i++) {
00125                 MD5Init(&ctx1);
00126                 if(i & 1)
00127                     MD5Update(&ctx1,(const unsigned char *)pw,strlen(pw));
00128                 else
00129                     MD5Update(&ctx1,final,16);
00130                 
00131                 if(i % 3)
00132                     MD5Update(&ctx1,sp,sl);
00133                 
00134                 if(i % 7)
00135                     MD5Update(&ctx1,pw,strlen(pw));
00136                 
00137                 if(i & 1)
00138                     MD5Update(&ctx1,final,16);
00139                 else
00140                     MD5Update(&ctx1,pw,strlen(pw));
00141                 MD5Final(final,&ctx1);
00142             }
00143 
00144             p = passwd + strlen(passwd);
00145             
00146             l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
00147             l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
00148             l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
00149             l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
00150             l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
00151             l =            final[11]        ; to64(p,l,2); p += 2;
00152             *p = '\0';
00153             
00154             /* Don't leave anything around in vm they could use. */
00155             mem(final = ,0,sizeof final);
00156             
00157             return passwd;
00158         }            
00159     }
00160     critcl::cret  to64_c (type Tcl_, type Interp* , type interp , type int , type v , type int , type n) ok {
00161         char s[5];
00162         to64(s, (unsigned int)v, n); 
00163         Tcl_SetStringObj(Tcl_GetObjResult(interp), s, n);
00164         return TCL_OK;
00165     }
00166 
00167     critcl::cret  md5crypt_c (type Tcl_, type Interp* , type interp , type char* , type magic , type char* , type pw , type char* , type salt) ok {
00168         char* s = md5crypt(pw, salt, magic);
00169         Tcl_SetStringObj(Tcl_GetObjResult(interp), s, strlen(s));
00170         return TCL_OK;
00171     }
00172 }
00173 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1