crypt-md5.c revision 91795
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
1083551Sdillon#include <sys/cdefs.h>
1183551Sdillon__FBSDID("$FreeBSD: head/lib/libcrypt/crypt-md5.c 91795 2002-03-07 10:41:11Z markm $");
1251462Smarkm
1351462Smarkm#include <unistd.h>
1451462Smarkm#include <stdio.h>
1551462Smarkm#include <string.h>
1651462Smarkm#include <md5.h>
1754751Speter#include <err.h>
1851462Smarkm#include "crypt.h"
1951462Smarkm
2051462Smarkm/*
2151462Smarkm * UNIX password
2251462Smarkm */
2351462Smarkm
2451462Smarkmchar *
2591754Smarkmcrypt_md5(const char *pw, const char *salt)
2651462Smarkm{
2751462Smarkm	MD5_CTX	ctx,ctx1;
2851462Smarkm	unsigned long l;
2991795Smarkm	int sl, pl;
3091795Smarkm	u_int i;
3191754Smarkm	u_char final[MD5_SIZE];
3291754Smarkm	static const char *sp, *ep;
3391754Smarkm	static char passwd[120], *p;
3491754Smarkm	static const char *magic = "$1$";	/*
3591754Smarkm						 * This string is magic for
3691754Smarkm						 * this algorithm.  Having
3791754Smarkm						 * it this way, we can get
3891754Smarkm						 * get better later on
3991754Smarkm						 */
4051462Smarkm
4151462Smarkm	/* Refine the Salt first */
4251462Smarkm	sp = salt;
4351462Smarkm
4451462Smarkm	/* If it starts with the magic string, then skip that */
4591754Smarkm	if(!strncmp(sp, magic, strlen(magic)))
4651462Smarkm		sp += strlen(magic);
4751462Smarkm
4851462Smarkm	/* It stops at the first '$', max 8 chars */
4991754Smarkm	for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
5051462Smarkm		continue;
5151462Smarkm
5251462Smarkm	/* get the length of the true salt */
5351462Smarkm	sl = ep - sp;
5451462Smarkm
5551462Smarkm	MD5Init(&ctx);
5651462Smarkm
5751462Smarkm	/* The password first, since that is what is most unknown */
5891754Smarkm	MD5Update(&ctx, (const u_char *)pw, strlen(pw));
5951462Smarkm
6051462Smarkm	/* Then our magic string */
6191754Smarkm	MD5Update(&ctx, (const u_char *)magic, strlen(magic));
6251462Smarkm
6351462Smarkm	/* Then the raw salt */
6491754Smarkm	MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
6551462Smarkm
6651462Smarkm	/* Then just as many characters of the MD5(pw,salt,pw) */
6751462Smarkm	MD5Init(&ctx1);
6891754Smarkm	MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
6991754Smarkm	MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
7091754Smarkm	MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
7191754Smarkm	MD5Final(final, &ctx1);
7291795Smarkm	for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
7391754Smarkm		MD5Update(&ctx, (const u_char *)final,
7491795Smarkm		    (u_int)(pl > MD5_SIZE ? MD5_SIZE : pl));
7551462Smarkm
7651462Smarkm	/* Don't leave anything around in vm they could use. */
7791754Smarkm	memset(final, 0, sizeof(final));
7851462Smarkm
7951462Smarkm	/* Then something really weird... */
8091754Smarkm	for (i = strlen(pw); i; i >>= 1)
8191754Smarkm		if(i & 1)
8291754Smarkm		    MD5Update(&ctx, (const u_char *)final, 1);
8351462Smarkm		else
8491754Smarkm		    MD5Update(&ctx, (const u_char *)pw, 1);
8551462Smarkm
8651462Smarkm	/* Now make the output string */
8791754Smarkm	strcpy(passwd, magic);
8891754Smarkm	strncat(passwd, sp, (u_int)sl);
8991754Smarkm	strcat(passwd, "$");
9051462Smarkm
9191754Smarkm	MD5Final(final, &ctx);
9251462Smarkm
9351462Smarkm	/*
9451462Smarkm	 * and now, just to make sure things don't run too fast
9551462Smarkm	 * On a 60 Mhz Pentium this takes 34 msec, so you would
9651462Smarkm	 * need 30 seconds to build a 1000 entry dictionary...
9751462Smarkm	 */
9891754Smarkm	for(i = 0; i < 1000; i++) {
9951462Smarkm		MD5Init(&ctx1);
10051462Smarkm		if(i & 1)
10191754Smarkm			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
10251462Smarkm		else
10391754Smarkm			MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
10451462Smarkm
10551462Smarkm		if(i % 3)
10691754Smarkm			MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
10751462Smarkm
10851462Smarkm		if(i % 7)
10991754Smarkm			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
11051462Smarkm
11151462Smarkm		if(i & 1)
11291754Smarkm			MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
11351462Smarkm		else
11491754Smarkm			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
11591754Smarkm		MD5Final(final, &ctx1);
11651462Smarkm	}
11751462Smarkm
11851462Smarkm	p = passwd + strlen(passwd);
11951462Smarkm
12051462Smarkm	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
12191754Smarkm	_crypt_to64(p, l, 4); p += 4;
12251462Smarkm	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
12391754Smarkm	_crypt_to64(p, l, 4); p += 4;
12451462Smarkm	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
12591754Smarkm	_crypt_to64(p, l, 4); p += 4;
12651462Smarkm	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
12791754Smarkm	_crypt_to64(p, l, 4); p += 4;
12851462Smarkm	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
12991754Smarkm	_crypt_to64(p, l, 4); p += 4;
13051462Smarkm	l =                    final[11]                ;
13191754Smarkm	_crypt_to64(p, l, 2); p += 2;
13251462Smarkm	*p = '\0';
13351462Smarkm
13451462Smarkm	/* Don't leave anything around in vm they could use. */
13591754Smarkm	memset(final, 0, sizeof(final));
13651462Smarkm
13751462Smarkm	return passwd;
13851462Smarkm}
13951462Smarkm
140