crypt-md5.c revision 91754
121240Swosch/*
221240Swosch * ----------------------------------------------------------------------------
321240Swosch * "THE BEER-WARE LICENSE" (Revision 42):
421240Swosch * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
521240Swosch * can do whatever you want with this stuff. If we meet some day, and you think
621240Swosch * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
721240Swosch * ----------------------------------------------------------------------------
821240Swosch */
921240Swosch
1021240Swosch#include <sys/cdefs.h>
1121240Swosch__FBSDID("$FreeBSD: head/lib/libcrypt/crypt-md5.c 91754 2002-03-06 17:18:09Z markm $");
1221240Swosch
1321240Swosch#include <unistd.h>
1421240Swosch#include <stdio.h>
1521240Swosch#include <string.h>
1621240Swosch#include <md5.h>
1721240Swosch#include <err.h>
1821240Swosch#include "crypt.h"
1921240Swosch
2021240Swosch/*
2121240Swosch * UNIX password
2221240Swosch */
2321240Swosch
2421240Swoschchar *
25crypt_md5(const char *pw, const char *salt)
26{
27	MD5_CTX	ctx,ctx1;
28	unsigned long l;
29	int sl;
30	u_int pl, i;
31	u_char final[MD5_SIZE];
32	static const char *sp, *ep;
33	static char passwd[120], *p;
34	static const char *magic = "$1$";	/*
35						 * This string is magic for
36						 * this algorithm.  Having
37						 * it this way, we can get
38						 * get better later on
39						 */
40
41	/* Refine the Salt first */
42	sp = salt;
43
44	/* If it starts with the magic string, then skip that */
45	if(!strncmp(sp, magic, strlen(magic)))
46		sp += strlen(magic);
47
48	/* It stops at the first '$', max 8 chars */
49	for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
50		continue;
51
52	/* get the length of the true salt */
53	sl = ep - sp;
54
55	MD5Init(&ctx);
56
57	/* The password first, since that is what is most unknown */
58	MD5Update(&ctx, (const u_char *)pw, strlen(pw));
59
60	/* Then our magic string */
61	MD5Update(&ctx, (const u_char *)magic, strlen(magic));
62
63	/* Then the raw salt */
64	MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
65
66	/* Then just as many characters of the MD5(pw,salt,pw) */
67	MD5Init(&ctx1);
68	MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
69	MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
70	MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
71	MD5Final(final, &ctx1);
72	for(pl = strlen(pw); pl > 0; pl -= MD5_SIZE)
73		MD5Update(&ctx, (const u_char *)final,
74		    pl > MD5_SIZE ? MD5_SIZE : pl);
75
76	/* Don't leave anything around in vm they could use. */
77	memset(final, 0, sizeof(final));
78
79	/* Then something really weird... */
80	for (i = strlen(pw); i; i >>= 1)
81		if(i & 1)
82		    MD5Update(&ctx, (const u_char *)final, 1);
83		else
84		    MD5Update(&ctx, (const u_char *)pw, 1);
85
86	/* Now make the output string */
87	strcpy(passwd, magic);
88	strncat(passwd, sp, (u_int)sl);
89	strcat(passwd, "$");
90
91	MD5Final(final, &ctx);
92
93	/*
94	 * and now, just to make sure things don't run too fast
95	 * On a 60 Mhz Pentium this takes 34 msec, so you would
96	 * need 30 seconds to build a 1000 entry dictionary...
97	 */
98	for(i = 0; i < 1000; i++) {
99		MD5Init(&ctx1);
100		if(i & 1)
101			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
102		else
103			MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
104
105		if(i % 3)
106			MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
107
108		if(i % 7)
109			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
110
111		if(i & 1)
112			MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
113		else
114			MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
115		MD5Final(final, &ctx1);
116	}
117
118	p = passwd + strlen(passwd);
119
120	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
121	_crypt_to64(p, l, 4); p += 4;
122	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
123	_crypt_to64(p, l, 4); p += 4;
124	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
125	_crypt_to64(p, l, 4); p += 4;
126	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
127	_crypt_to64(p, l, 4); p += 4;
128	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
129	_crypt_to64(p, l, 4); p += 4;
130	l =                    final[11]                ;
131	_crypt_to64(p, l, 2); p += 2;
132	*p = '\0';
133
134	/* Don't leave anything around in vm they could use. */
135	memset(final, 0, sizeof(final));
136
137	return passwd;
138}
139
140