crypt.c revision 8870
11984Scsgr/*
24246Sphk * ----------------------------------------------------------------------------
34246Sphk * "THE BEER-WARE LICENSE" (Revision 42):
44246Sphk * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
54246Sphk * can do whatever you want with this stuff. If we meet some day, and you think
64246Sphk * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
74246Sphk * ----------------------------------------------------------------------------
81984Scsgr *
98870Srgrimes * $Id: crypt.c,v 1.2 1994/11/07 21:07:09 phk Exp $
101984Scsgr *
111984Scsgr */
121984Scsgr
131984Scsgr#if defined(LIBC_SCCS) && !defined(lint)
148870Srgrimesstatic char rcsid[] = "$Header: /home/ncvs/src/lib/libcrypt/crypt.c,v 1.2 1994/11/07 21:07:09 phk Exp $";
151984Scsgr#endif /* LIBC_SCCS and not lint */
161984Scsgr
171984Scsgr#include <unistd.h>
181984Scsgr#include <stdio.h>
194246Sphk#include <md5.h>
201984Scsgr
214246Sphkstatic unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
224246Sphk	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
234246Sphk
244246Sphkstatic void
254246Sphkto64(s, v, n)
264246Sphk	char *s;
274246Sphk	unsigned long v;
284246Sphk	int n;
294246Sphk{
304246Sphk	while (--n >= 0) {
314246Sphk		*s++ = itoa64[v&0x3f];
324246Sphk		v >>= 6;
334246Sphk	}
344246Sphk}
354246Sphk
361984Scsgr/*
371984Scsgr * UNIX password
388870Srgrimes *
394246Sphk * Use MD5 for what it is best at...
401984Scsgr */
411984Scsgr
421984Scsgrchar *
431984Scsgrcrypt(pw, salt)
441984Scsgr	register const char *pw;
451984Scsgr	register const char *salt;
461984Scsgr{
474246Sphk	static char	*magic = "$1$";	/*
484246Sphk						 * This string is magic for
494246Sphk						 * this algorithm.  Having
504246Sphk						 * it this way, we can get
514246Sphk						 * get better later on
524246Sphk						 */
534246Sphk	static char     passwd[120], *p;
544246Sphk	static const char *sp,*ep;
554246Sphk	unsigned char	final[16];
564246Sphk	int sl,pl,i,j;
574246Sphk	MD5_CTX	ctx,ctx1;
584246Sphk	unsigned long l;
591984Scsgr
604246Sphk	/* Refine the Salt first */
614246Sphk	sp = salt;
621984Scsgr
634246Sphk	/* If it starts with the magic string, then skip that */
644246Sphk	if(!strncmp(sp,magic,strlen(magic)))
654246Sphk		sp += strlen(magic);
661984Scsgr
674246Sphk	/* It stops at the first '$', max 8 chars */
684246Sphk	for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
694246Sphk		continue;
704246Sphk
714246Sphk	/* get the length of the true salt */
724246Sphk	sl = ep - sp;
734246Sphk
744246Sphk	MD5Init(&ctx);
754246Sphk
764246Sphk	/* The password first, since that is what is most unknown */
774246Sphk	MD5Update(&ctx,pw,strlen(pw));
784246Sphk
794246Sphk	/* Then our magic string */
804246Sphk	MD5Update(&ctx,magic,strlen(magic));
814246Sphk
824246Sphk	/* Then the raw salt */
834246Sphk	MD5Update(&ctx,sp,sl);
844246Sphk
854246Sphk	/* Then just as many characters of the MD5(pw,salt,pw) */
864246Sphk	MD5Init(&ctx1);
874246Sphk	MD5Update(&ctx1,pw,strlen(pw));
884246Sphk	MD5Update(&ctx1,sp,sl);
894246Sphk	MD5Update(&ctx1,pw,strlen(pw));
904246Sphk	MD5Final(final,&ctx1);
918870Srgrimes	for(pl = strlen(pw); pl > 0; pl -= 16)
924246Sphk		MD5Update(&ctx,final,pl>16 ? 16 : pl);
934246Sphk
944246Sphk	/* Don't leave anything around in vm they could use. */
954246Sphk	memset(final,0,sizeof final);
964246Sphk
974246Sphk	/* Then something really weird... */
984246Sphk	for (j=0,i = strlen(pw); i ; i >>= 1)
994246Sphk		if(i&1)
1004246Sphk		    MD5Update(&ctx, final+j, 1);
1011984Scsgr		else
1024246Sphk		    MD5Update(&ctx, pw+j, 1);
1031984Scsgr
1044246Sphk	/* Now make the output string */
1054246Sphk	strcpy(passwd,magic);
1064246Sphk	strncat(passwd,sp,sl);
1074246Sphk	strcat(passwd,"$");
1081984Scsgr
1094246Sphk	MD5Final(final,&ctx);
1104246Sphk
1118870Srgrimes	/*
1128870Srgrimes	 * and now, just to make sure things don't run too fast
1134246Sphk	 * On a 60 Mhz Pentium this takes 34 msec, so you would
1144246Sphk	 * need 30 seconds to build a 1000 entry dictionary...
1154246Sphk	 */
1164246Sphk	for(i=0;i<1000;i++) {
1174246Sphk		MD5Init(&ctx1);
1184246Sphk		if(i & 1)
1194246Sphk			MD5Update(&ctx1,pw,strlen(pw));
1201984Scsgr		else
1214246Sphk			MD5Update(&ctx1,final,16);
1221984Scsgr
1234246Sphk		if(i % 3)
1244246Sphk			MD5Update(&ctx1,sp,sl);
1251984Scsgr
1264246Sphk		if(i % 7)
1274246Sphk			MD5Update(&ctx1,pw,strlen(pw));
1284246Sphk
1294246Sphk		if(i & 1)
1304246Sphk			MD5Update(&ctx1,final,16);
1314246Sphk		else
1324246Sphk			MD5Update(&ctx1,pw,strlen(pw));
1334246Sphk		MD5Final(final,&ctx1);
1341984Scsgr	}
1351984Scsgr
1364246Sphk	p = passwd + strlen(passwd);
1378870Srgrimes
1384246Sphk	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
1394246Sphk	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
1404246Sphk	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
1414246Sphk	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
1424246Sphk	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
1434246Sphk	l =                    final[11]                ; to64(p,l,2); p += 2;
1444246Sphk	*p = '\0';
1454246Sphk
1464246Sphk	/* Don't leave anything around in vm they could use. */
1474246Sphk	memset(final,0,sizeof final);
1484246Sphk
1494246Sphk	return passwd;
1501984Scsgr}
1511984Scsgr
152