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