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