1115733Smarkm/*-
2115733Smarkm * Copyright (c) 2003 Poul-Henning Kamp
3115733Smarkm * All rights reserved.
4115733Smarkm *
5115733Smarkm * Redistribution and use in source and binary forms, with or without
6115733Smarkm * modification, are permitted provided that the following conditions
7115733Smarkm * are met:
8115733Smarkm * 1. Redistributions of source code must retain the above copyright
9115733Smarkm *    notice, this list of conditions and the following disclaimer.
10115733Smarkm * 2. Redistributions in binary form must reproduce the above copyright
11115733Smarkm *    notice, this list of conditions and the following disclaimer in the
12115733Smarkm *    documentation and/or other materials provided with the distribution.
13115733Smarkm *
14115733Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15115733Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16115733Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17115733Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18115733Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19115733Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20115733Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21115733Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22115733Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23115733Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24115733Smarkm * SUCH DAMAGE.
2551462Smarkm */
2651462Smarkm
2783551Sdillon#include <sys/cdefs.h>
2883551Sdillon__FBSDID("$FreeBSD$");
2951462Smarkm
30115733Smarkm#include <sys/types.h>
31115733Smarkm
32115733Smarkm#include <err.h>
33115733Smarkm#include <md5.h>
3451462Smarkm#include <stdio.h>
3551462Smarkm#include <string.h>
36115733Smarkm#include <unistd.h>
37115733Smarkm
3851462Smarkm#include "crypt.h"
3951462Smarkm
4051462Smarkm/*
4151462Smarkm * UNIX password
4251462Smarkm */
4351462Smarkm
4451462Smarkmchar *
4591754Smarkmcrypt_md5(const char *pw, const char *salt)
4651462Smarkm{
4751462Smarkm	MD5_CTX	ctx,ctx1;
4851462Smarkm	unsigned long l;
4991795Smarkm	int sl, pl;
5091795Smarkm	u_int i;
5191754Smarkm	u_char final[MD5_SIZE];
5291754Smarkm	static const char *sp, *ep;
5391754Smarkm	static char passwd[120], *p;
54115733Smarkm	static const char *magic = "$1$";
5551462Smarkm
5651462Smarkm	/* Refine the Salt first */
5751462Smarkm	sp = salt;
5851462Smarkm
5951462Smarkm	/* If it starts with the magic string, then skip that */
6091754Smarkm	if(!strncmp(sp, magic, strlen(magic)))
6151462Smarkm		sp += strlen(magic);
6251462Smarkm
6351462Smarkm	/* It stops at the first '$', max 8 chars */
6491754Smarkm	for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
6551462Smarkm		continue;
6651462Smarkm
6751462Smarkm	/* get the length of the true salt */
6851462Smarkm	sl = ep - sp;
6951462Smarkm
7051462Smarkm	MD5Init(&ctx);
7151462Smarkm
7251462Smarkm	/* The password first, since that is what is most unknown */
7391754Smarkm	MD5Update(&ctx, (const u_char *)pw, strlen(pw));
7451462Smarkm
7551462Smarkm	/* Then our magic string */
7691754Smarkm	MD5Update(&ctx, (const u_char *)magic, strlen(magic));
7751462Smarkm
7851462Smarkm	/* Then the raw salt */
7991754Smarkm	MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
8051462Smarkm
8151462Smarkm	/* Then just as many characters of the MD5(pw,salt,pw) */
8251462Smarkm	MD5Init(&ctx1);
8391754Smarkm	MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
8491754Smarkm	MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
8591754Smarkm	MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
8691754Smarkm	MD5Final(final, &ctx1);
8791795Smarkm	for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
8891754Smarkm		MD5Update(&ctx, (const u_char *)final,
8991795Smarkm		    (u_int)(pl > MD5_SIZE ? MD5_SIZE : pl));
9051462Smarkm
9151462Smarkm	/* Don't leave anything around in vm they could use. */
9291754Smarkm	memset(final, 0, sizeof(final));
9351462Smarkm
9451462Smarkm	/* Then something really weird... */
9591754Smarkm	for (i = strlen(pw); i; i >>= 1)
9691754Smarkm		if(i & 1)
9791754Smarkm		    MD5Update(&ctx, (const u_char *)final, 1);
9851462Smarkm		else
9991754Smarkm		    MD5Update(&ctx, (const u_char *)pw, 1);
10051462Smarkm
10151462Smarkm	/* Now make the output string */
10291754Smarkm	strcpy(passwd, magic);
10391754Smarkm	strncat(passwd, sp, (u_int)sl);
10491754Smarkm	strcat(passwd, "$");
10551462Smarkm
10691754Smarkm	MD5Final(final, &ctx);
10751462Smarkm
10851462Smarkm	/*
10951462Smarkm	 * and now, just to make sure things don't run too fast
11051462Smarkm	 * On a 60 Mhz Pentium this takes 34 msec, so you would
11151462Smarkm	 * need 30 seconds to build a 1000 entry dictionary...
11251462Smarkm	 */
11391754Smarkm	for(i = 0; i < 1000; i++) {
11451462Smarkm		MD5Init(&ctx1);
11551462Smarkm		if(i & 1)
11691754Smarkm			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
11751462Smarkm		else
11891754Smarkm			MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
11951462Smarkm
12051462Smarkm		if(i % 3)
12191754Smarkm			MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
12251462Smarkm
12351462Smarkm		if(i % 7)
12491754Smarkm			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
12551462Smarkm
12651462Smarkm		if(i & 1)
12791754Smarkm			MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
12851462Smarkm		else
12991754Smarkm			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
13091754Smarkm		MD5Final(final, &ctx1);
13151462Smarkm	}
13251462Smarkm
13351462Smarkm	p = passwd + strlen(passwd);
13451462Smarkm
13551462Smarkm	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
13691754Smarkm	_crypt_to64(p, l, 4); p += 4;
13751462Smarkm	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
13891754Smarkm	_crypt_to64(p, l, 4); p += 4;
13951462Smarkm	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
14091754Smarkm	_crypt_to64(p, l, 4); p += 4;
14151462Smarkm	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
14291754Smarkm	_crypt_to64(p, l, 4); p += 4;
14351462Smarkm	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
14491754Smarkm	_crypt_to64(p, l, 4); p += 4;
145115733Smarkm	l = final[11];
14691754Smarkm	_crypt_to64(p, l, 2); p += 2;
14751462Smarkm	*p = '\0';
14851462Smarkm
14951462Smarkm	/* Don't leave anything around in vm they could use. */
15091754Smarkm	memset(final, 0, sizeof(final));
15151462Smarkm
152115733Smarkm	return (passwd);
15351462Smarkm}
154