1 /* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * $Id$ 10 * 11 */ 12 13 #if defined(LIBC_SCCS) && !defined(lint) 14 static char rcsid[] = "$Header$"; 15 #endif /* LIBC_SCCS and not lint */ 16 17 #include <unistd.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include <md5.h> 21 #include <string.h> 22 23 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 24 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 25 26 static void to64 __P((char *, unsigned long, int)); 27 28 static void 29 to64(s, v, n) 30 char *s; 31 unsigned long v; 32 int n; 33 { 34 static void to64 __P((char *, unsigned long, int)); 35 36 while (--n >= 0) { 37 *s++ = itoa64[v&0x3f]; 38 v >>= 6; 39 } 40 } 41 42 /* 43 * UNIX password 44 * 45 * Use MD5 for what it is best at... 46 */ 47 48 char * 49 crypt(pw, salt) 50 register const char *pw; 51 register const char *salt; 52 { 53 static char *magic = "$1$"; /* 54 * This string is magic for 55 * this algorithm. Having 56 * it this way, we can get 57 * get better later on 58 */ 59 static char passwd[120], *p; 60 static const char *sp,*ep; 61 unsigned char final[16]; 62 int sl,pl,i,j; 63 MD5_CTX ctx,ctx1; 64 unsigned long l; 65 66 /* Refine the Salt first */ 67 sp = salt; 68 69 /* If it starts with the magic string, then skip that */ 70 if(!strncmp(sp,magic,strlen(magic))) 71 sp += strlen(magic); 72 73 /* It stops at the first '$', max 8 chars */ 74 for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) 75 continue; 76 77 /* get the length of the true salt */ 78 sl = ep - sp; 79 80 MD5Init(&ctx); 81 82 /* The password first, since that is what is most unknown */ 83 MD5Update(&ctx,pw,strlen(pw)); 84 85 /* Then our magic string */ 86 MD5Update(&ctx,magic,strlen(magic)); 87 88 /* Then the raw salt */ 89 MD5Update(&ctx,sp,sl); 90 91 /* Then just as many characters of the MD5(pw,salt,pw) */ 92 MD5Init(&ctx1); 93 MD5Update(&ctx1,pw,strlen(pw)); 94 MD5Update(&ctx1,sp,sl); 95 MD5Update(&ctx1,pw,strlen(pw)); 96 MD5Final(final,&ctx1); 97 for(pl = strlen(pw); pl > 0; pl -= 16) 98 MD5Update(&ctx,final,pl>16 ? 16 : pl); 99 100 /* Don't leave anything around in vm they could use. */ 101 memset(final,0,sizeof final); 102 103 /* Then something really weird... */ 104 for (i = strlen(pw); i ; i >>= 1) 105 if(i&1) 106 MD5Update(&ctx, final, 1); 107 else 108 MD5Update(&ctx, pw, 1); 109 110 /* Now make the output string */ 111 strcpy(passwd,magic); 112 strncat(passwd,sp,sl); 113 strcat(passwd,"$"); 114 115 MD5Final(final,&ctx); 116 117 /* 118 * and now, just to make sure things don't run too fast 119 * On a 60 Mhz Pentium this takes 34 msec, so you would 120 * need 30 seconds to build a 1000 entry dictionary... 121 */ 122 for(i=0;i<1000;i++) { 123 MD5Init(&ctx1); 124 if(i & 1) 125 MD5Update(&ctx1,pw,strlen(pw)); 126 else 127 MD5Update(&ctx1,final,16); 128 129 if(i % 3) 130 MD5Update(&ctx1,sp,sl); 131 132 if(i % 7) 133 MD5Update(&ctx1,pw,strlen(pw)); 134 135 if(i & 1) 136 MD5Update(&ctx1,final,16); 137 else 138 MD5Update(&ctx1,pw,strlen(pw)); 139 MD5Final(final,&ctx1); 140 } 141 142 p = passwd + strlen(passwd); 143 144 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; 145 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; 146 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; 147 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; 148 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; 149 l = final[11] ; to64(p,l,2); p += 2; 150 *p = '\0'; 151 152 /* Don't leave anything around in vm they could use. */ 153 memset(final,0,sizeof final); 154 155 return passwd; 156 } 157 158