crypt-md5.c revision 54751
151462Smarkm/* 251462Smarkm * ---------------------------------------------------------------------------- 351462Smarkm * "THE BEER-WARE LICENSE" (Revision 42): 451462Smarkm * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 551462Smarkm * can do whatever you want with this stuff. If we meet some day, and you think 651462Smarkm * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 751462Smarkm * ---------------------------------------------------------------------------- 851462Smarkm * 951462Smarkm * $FreeBSD: head/lib/libcrypt/crypt-md5.c 54751 1999-12-17 20:04:01Z peter $ 1051462Smarkm * 1151462Smarkm */ 1251462Smarkm 1351462Smarkm#if defined(LIBC_SCCS) && !defined(lint) 1454751Speterstatic const char rcsid[] = \ 1554751Speter"$FreeBSD: head/lib/libcrypt/crypt-md5.c 54751 1999-12-17 20:04:01Z peter $"; 1651462Smarkm#endif /* LIBC_SCCS and not lint */ 1751462Smarkm 1851462Smarkm#include <unistd.h> 1951462Smarkm#include <stdio.h> 2051462Smarkm#include <string.h> 2151462Smarkm#include <md5.h> 2254751Speter#include <err.h> 2351462Smarkm#include "crypt.h" 2451462Smarkm 2554751Speter#ifdef __PIC__ 2654751Speter#include <dlfcn.h> 2754751Speter 2854751Speter#define MD5Init(ctx) dl_MD5Init(ctx) 2954751Speter#define MD5Update(ctx, data, len) dl_MD5Update(ctx, data, len) 3054751Speter#define MD5Final(dgst, ctx) dl_MD5Final(dgst, ctx) 3154751Speter 3254751Speterstatic void (*dl_MD5Init)(MD5_CTX *); 3354751Speterstatic void (*dl_MD5Update)(MD5_CTX *, const unsigned char *, unsigned int); 3454751Speterstatic void (*dl_MD5Final)(unsigned char digest[16], MD5_CTX *); 3554751Speter#endif 3654751Speter 3751462Smarkm/* 3851462Smarkm * UNIX password 3951462Smarkm */ 4051462Smarkm 4151462Smarkmchar * 4251462Smarkmcrypt_md5(pw, salt) 4351462Smarkm const char *pw; 4451462Smarkm const char *salt; 4551462Smarkm{ 4651462Smarkm static char *magic = "$1$"; /* 4751462Smarkm * This string is magic for 4851462Smarkm * this algorithm. Having 4951462Smarkm * it this way, we can get 5051462Smarkm * get better later on 5151462Smarkm */ 5251462Smarkm static char passwd[120], *p; 5351462Smarkm static const char *sp,*ep; 5451462Smarkm unsigned char final[MD5_SIZE]; 5551462Smarkm int sl,pl,i; 5651462Smarkm MD5_CTX ctx,ctx1; 5751462Smarkm unsigned long l; 5854751Speter#ifdef __PIC__ 5954751Speter void *libmd; 6054751Speter#endif 6151462Smarkm 6251462Smarkm /* Refine the Salt first */ 6351462Smarkm sp = salt; 6451462Smarkm 6551462Smarkm /* If it starts with the magic string, then skip that */ 6651462Smarkm if(!strncmp(sp,magic,strlen(magic))) 6751462Smarkm sp += strlen(magic); 6851462Smarkm 6951462Smarkm /* It stops at the first '$', max 8 chars */ 7051462Smarkm for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) 7151462Smarkm continue; 7251462Smarkm 7351462Smarkm /* get the length of the true salt */ 7451462Smarkm sl = ep - sp; 7551462Smarkm 7654751Speter#ifdef __PIC__ 7754751Speter libmd = dlopen("libmd.so", RTLD_NOW); 7854751Speter if (libmd == NULL) 7954751Speter return NULL; 8054751Speter dl_MD5Init = dlsym(libmd, "MD5Init"); 8154751Speter if (dl_MD5Init == NULL) { 8254751Speter warnx("libcrypt-md5: looking for MD5Init: %s\n", dlerror()); 8354751Speter dlclose(libmd); 8454751Speter return NULL; 8554751Speter } 8654751Speter dl_MD5Update = dlsym(libmd, "MD5Update"); 8754751Speter if (dl_MD5Update == NULL) { 8854751Speter warnx("libcrypt-md5: looking for MD5Update: %s\n", dlerror()); 8954751Speter dlclose(libmd); 9054751Speter return NULL; 9154751Speter } 9254751Speter dl_MD5Final = dlsym(libmd, "MD5Final"); 9354751Speter if (dl_MD5Final == NULL) { 9454751Speter warnx("libcrypt-md5: looking for MD5Final: %s\n", dlerror()); 9554751Speter dlclose(libmd); 9654751Speter return NULL; 9754751Speter } 9854751Speter#endif 9951462Smarkm MD5Init(&ctx); 10051462Smarkm 10151462Smarkm /* The password first, since that is what is most unknown */ 10251462Smarkm MD5Update(&ctx,pw,strlen(pw)); 10351462Smarkm 10451462Smarkm /* Then our magic string */ 10551462Smarkm MD5Update(&ctx,magic,strlen(magic)); 10651462Smarkm 10751462Smarkm /* Then the raw salt */ 10851462Smarkm MD5Update(&ctx,sp,sl); 10951462Smarkm 11051462Smarkm /* Then just as many characters of the MD5(pw,salt,pw) */ 11151462Smarkm MD5Init(&ctx1); 11251462Smarkm MD5Update(&ctx1,pw,strlen(pw)); 11351462Smarkm MD5Update(&ctx1,sp,sl); 11451462Smarkm MD5Update(&ctx1,pw,strlen(pw)); 11551462Smarkm MD5Final(final,&ctx1); 11651462Smarkm for(pl = strlen(pw); pl > 0; pl -= MD5_SIZE) 11751462Smarkm MD5Update(&ctx,final,pl>MD5_SIZE ? MD5_SIZE : pl); 11851462Smarkm 11951462Smarkm /* Don't leave anything around in vm they could use. */ 12051462Smarkm memset(final,0,sizeof final); 12151462Smarkm 12251462Smarkm /* Then something really weird... */ 12351462Smarkm for (i = strlen(pw); i ; i >>= 1) 12451462Smarkm if(i&1) 12551462Smarkm MD5Update(&ctx, final, 1); 12651462Smarkm else 12751462Smarkm MD5Update(&ctx, pw, 1); 12851462Smarkm 12951462Smarkm /* Now make the output string */ 13051462Smarkm strcpy(passwd,magic); 13151462Smarkm strncat(passwd,sp,sl); 13251462Smarkm strcat(passwd,"$"); 13351462Smarkm 13451462Smarkm MD5Final(final,&ctx); 13551462Smarkm 13651462Smarkm /* 13751462Smarkm * and now, just to make sure things don't run too fast 13851462Smarkm * On a 60 Mhz Pentium this takes 34 msec, so you would 13951462Smarkm * need 30 seconds to build a 1000 entry dictionary... 14051462Smarkm */ 14151462Smarkm for(i=0;i<1000;i++) { 14251462Smarkm MD5Init(&ctx1); 14351462Smarkm if(i & 1) 14451462Smarkm MD5Update(&ctx1,pw,strlen(pw)); 14551462Smarkm else 14651462Smarkm MD5Update(&ctx1,final,MD5_SIZE); 14751462Smarkm 14851462Smarkm if(i % 3) 14951462Smarkm MD5Update(&ctx1,sp,sl); 15051462Smarkm 15151462Smarkm if(i % 7) 15251462Smarkm MD5Update(&ctx1,pw,strlen(pw)); 15351462Smarkm 15451462Smarkm if(i & 1) 15551462Smarkm MD5Update(&ctx1,final,MD5_SIZE); 15651462Smarkm else 15751462Smarkm MD5Update(&ctx1,pw,strlen(pw)); 15851462Smarkm MD5Final(final,&ctx1); 15951462Smarkm } 16051462Smarkm 16154751Speter#ifdef __PIC__ 16254751Speter dlclose(libmd); 16354751Speter#endif 16451462Smarkm p = passwd + strlen(passwd); 16551462Smarkm 16651462Smarkm l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; 16751462Smarkm _crypt_to64(p,l,4); p += 4; 16851462Smarkm l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; 16951462Smarkm _crypt_to64(p,l,4); p += 4; 17051462Smarkm l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; 17151462Smarkm _crypt_to64(p,l,4); p += 4; 17251462Smarkm l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; 17351462Smarkm _crypt_to64(p,l,4); p += 4; 17451462Smarkm l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; 17551462Smarkm _crypt_to64(p,l,4); p += 4; 17651462Smarkm l = final[11] ; 17751462Smarkm _crypt_to64(p,l,2); p += 2; 17851462Smarkm *p = '\0'; 17951462Smarkm 18051462Smarkm /* Don't leave anything around in vm they could use. */ 18151462Smarkm memset(final,0,sizeof final); 18251462Smarkm 18351462Smarkm return passwd; 18451462Smarkm} 18551462Smarkm 186