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