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 * $FreeBSD$ 10 * 11 */ 12 13 #if defined(LIBC_SCCS) && !defined(lint) 14 static const char rcsid[] = \ 15 "$FreeBSD$"; 16 #endif /* LIBC_SCCS and not lint */ 17 18 #include <unistd.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <md5.h> 22 #include <err.h> 23 #include "crypt.h" 24 25 #ifdef __PIC__ 26 #include <dlfcn.h> 27 28 #define MD5Init(ctx) dl_MD5Init(ctx) 29 #define MD5Update(ctx, data, len) dl_MD5Update(ctx, data, len) 30 #define MD5Final(dgst, ctx) dl_MD5Final(dgst, ctx) 31 32 static void (*dl_MD5Init)(MD5_CTX *); 33 static void (*dl_MD5Update)(MD5_CTX *, const unsigned char *, unsigned int); 34 static void (*dl_MD5Final)(unsigned char digest[16], MD5_CTX *); 35 #endif 36 37 /* 38 * UNIX password 39 */ 40 41 char * 42 crypt_md5(pw, salt) 43 const char *pw; 44 const char *salt; 45 { 46 static char *magic = "$1$"; /* 47 * This string is magic for 48 * this algorithm. Having 49 * it this way, we can get 50 * get better later on 51 */ 52 static char passwd[120], *p; 53 static const char *sp,*ep; 54 unsigned char final[MD5_SIZE]; 55 int sl,pl,i; 56 MD5_CTX ctx,ctx1; 57 unsigned long l; 58 #ifdef __PIC__ 59 void *libmd; 60 #endif 61 62 /* Refine the Salt first */ 63 sp = salt; 64 65 /* If it starts with the magic string, then skip that */ 66 if(!strncmp(sp,magic,strlen(magic))) 67 sp += strlen(magic); 68 69 /* It stops at the first '$', max 8 chars */ 70 for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) 71 continue; 72 73 /* get the length of the true salt */ 74 sl = ep - sp; 75 76 #ifdef __PIC__ 77 libmd = dlopen("libmd.so", RTLD_NOW); 78 if (libmd == NULL) { 79 warnx("libcrypt-md5: dlopen(libmd.so): %s\n", dlerror()); 80 return NULL; 81 } 82 dl_MD5Init = dlsym(libmd, "MD5Init"); 83 if (dl_MD5Init == NULL) { 84 warnx("libcrypt-md5: looking for MD5Init: %s\n", dlerror()); 85 dlclose(libmd); 86 return NULL; 87 } 88 dl_MD5Update = dlsym(libmd, "MD5Update"); 89 if (dl_MD5Update == NULL) { 90 warnx("libcrypt-md5: looking for MD5Update: %s\n", dlerror()); 91 dlclose(libmd); 92 return NULL; 93 } 94 dl_MD5Final = dlsym(libmd, "MD5Final"); 95 if (dl_MD5Final == NULL) { 96 warnx("libcrypt-md5: looking for MD5Final: %s\n", dlerror()); 97 dlclose(libmd); 98 return NULL; 99 } 100 #endif 101 MD5Init(&ctx); 102 103 /* The password first, since that is what is most unknown */ 104 MD5Update(&ctx,pw,strlen(pw)); 105 106 /* Then our magic string */ 107 MD5Update(&ctx,magic,strlen(magic)); 108 109 /* Then the raw salt */ 110 MD5Update(&ctx,sp,sl); 111 112 /* Then just as many characters of the MD5(pw,salt,pw) */ 113 MD5Init(&ctx1); 114 MD5Update(&ctx1,pw,strlen(pw)); 115 MD5Update(&ctx1,sp,sl); 116 MD5Update(&ctx1,pw,strlen(pw)); 117 MD5Final(final,&ctx1); 118 for(pl = strlen(pw); pl > 0; pl -= MD5_SIZE) 119 MD5Update(&ctx,final,pl>MD5_SIZE ? MD5_SIZE : pl); 120 121 /* Don't leave anything around in vm they could use. */ 122 memset(final,0,sizeof final); 123 124 /* Then something really weird... */ 125 for (i = strlen(pw); i ; i >>= 1) 126 if(i&1) 127 MD5Update(&ctx, final, 1); 128 else 129 MD5Update(&ctx, pw, 1); 130 131 /* Now make the output string */ 132 strcpy(passwd,magic); 133 strncat(passwd,sp,sl); 134 strcat(passwd,"$"); 135 136 MD5Final(final,&ctx); 137 138 /* 139 * and now, just to make sure things don't run too fast 140 * On a 60 Mhz Pentium this takes 34 msec, so you would 141 * need 30 seconds to build a 1000 entry dictionary... 142 */ 143 for(i=0;i<1000;i++) { 144 MD5Init(&ctx1); 145 if(i & 1) 146 MD5Update(&ctx1,pw,strlen(pw)); 147 else 148 MD5Update(&ctx1,final,MD5_SIZE); 149 150 if(i % 3) 151 MD5Update(&ctx1,sp,sl); 152 153 if(i % 7) 154 MD5Update(&ctx1,pw,strlen(pw)); 155 156 if(i & 1) 157 MD5Update(&ctx1,final,MD5_SIZE); 158 else 159 MD5Update(&ctx1,pw,strlen(pw)); 160 MD5Final(final,&ctx1); 161 } 162 163 #ifdef __PIC__ 164 dlclose(libmd); 165 #endif 166 p = passwd + strlen(passwd); 167 168 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; 169 _crypt_to64(p,l,4); p += 4; 170 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; 171 _crypt_to64(p,l,4); p += 4; 172 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; 173 _crypt_to64(p,l,4); p += 4; 174 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; 175 _crypt_to64(p,l,4); p += 4; 176 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; 177 _crypt_to64(p,l,4); p += 4; 178 l = final[11] ; 179 _crypt_to64(p,l,2); p += 2; 180 *p = '\0'; 181 182 /* Don't leave anything around in vm they could use. */ 183 memset(final,0,sizeof final); 184 185 return passwd; 186 } 187 188