crypt-md5.c revision 83551
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 */
9
10#include <sys/cdefs.h>
11__FBSDID("$FreeBSD: head/lib/libcrypt/crypt-md5.c 83551 2001-09-16 21:35:07Z dillon $");
12
13#include <unistd.h>
14#include <stdio.h>
15#include <string.h>
16#include <md5.h>
17#include <err.h>
18#include "crypt.h"
19
20/*
21 * UNIX password
22 */
23
24char *
25crypt_md5(pw, salt)
26	const char *pw;
27	const char *salt;
28{
29	static char	*magic = "$1$";	/*
30					 * This string is magic for
31					 * this algorithm.  Having
32					 * it this way, we can get
33					 * get better later on
34					 */
35	static char     passwd[120], *p;
36	static const char *sp,*ep;
37	unsigned char	final[MD5_SIZE];
38	int sl,pl,i;
39	MD5_CTX	ctx,ctx1;
40	unsigned long l;
41
42	/* Refine the Salt first */
43	sp = salt;
44
45	/* If it starts with the magic string, then skip that */
46	if(!strncmp(sp,magic,strlen(magic)))
47		sp += strlen(magic);
48
49	/* It stops at the first '$', max 8 chars */
50	for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
51		continue;
52
53	/* get the length of the true salt */
54	sl = ep - sp;
55
56	MD5Init(&ctx);
57
58	/* The password first, since that is what is most unknown */
59	MD5Update(&ctx,pw,strlen(pw));
60
61	/* Then our magic string */
62	MD5Update(&ctx,magic,strlen(magic));
63
64	/* Then the raw salt */
65	MD5Update(&ctx,sp,sl);
66
67	/* Then just as many characters of the MD5(pw,salt,pw) */
68	MD5Init(&ctx1);
69	MD5Update(&ctx1,pw,strlen(pw));
70	MD5Update(&ctx1,sp,sl);
71	MD5Update(&ctx1,pw,strlen(pw));
72	MD5Final(final,&ctx1);
73	for(pl = strlen(pw); pl > 0; pl -= MD5_SIZE)
74		MD5Update(&ctx,final,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, final, 1);
83		else
84		    MD5Update(&ctx, pw, 1);
85
86	/* Now make the output string */
87	strcpy(passwd,magic);
88	strncat(passwd,sp,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,pw,strlen(pw));
102		else
103			MD5Update(&ctx1,final,MD5_SIZE);
104
105		if(i % 3)
106			MD5Update(&ctx1,sp,sl);
107
108		if(i % 7)
109			MD5Update(&ctx1,pw,strlen(pw));
110
111		if(i & 1)
112			MD5Update(&ctx1,final,MD5_SIZE);
113		else
114			MD5Update(&ctx1,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