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