crypt.c revision 17141
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 *
917141Sjkh * $Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp $
101984Scsgr *
111984Scsgr */
121984Scsgr
131984Scsgr#if defined(LIBC_SCCS) && !defined(lint)
1417141Sjkhstatic char rcsid[] = "$Header: /home/ncvs/src/lib/libcrypt/crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp $";
151984Scsgr#endif /* LIBC_SCCS and not lint */
161984Scsgr
171984Scsgr#include <unistd.h>
181984Scsgr#include <stdio.h>
1917141Sjkh#include <string.h>
204246Sphk#include <md5.h>
211984Scsgr
224246Sphkstatic unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
234246Sphk	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
244246Sphk
254246Sphkstatic void
264246Sphkto64(s, v, n)
274246Sphk	char *s;
284246Sphk	unsigned long v;
294246Sphk	int n;
304246Sphk{
314246Sphk	while (--n >= 0) {
324246Sphk		*s++ = itoa64[v&0x3f];
334246Sphk		v >>= 6;
344246Sphk	}
354246Sphk}
364246Sphk
371984Scsgr/*
381984Scsgr * UNIX password
398870Srgrimes *
404246Sphk * Use MD5 for what it is best at...
411984Scsgr */
421984Scsgr
431984Scsgrchar *
441984Scsgrcrypt(pw, salt)
451984Scsgr	register const char *pw;
461984Scsgr	register const char *salt;
471984Scsgr{
484246Sphk	static char	*magic = "$1$";	/*
494246Sphk						 * This string is magic for
504246Sphk						 * this algorithm.  Having
514246Sphk						 * it this way, we can get
524246Sphk						 * get better later on
534246Sphk						 */
544246Sphk	static char     passwd[120], *p;
554246Sphk	static const char *sp,*ep;
564246Sphk	unsigned char	final[16];
574246Sphk	int sl,pl,i,j;
584246Sphk	MD5_CTX	ctx,ctx1;
594246Sphk	unsigned long l;
601984Scsgr
614246Sphk	/* Refine the Salt first */
624246Sphk	sp = salt;
631984Scsgr
644246Sphk	/* If it starts with the magic string, then skip that */
654246Sphk	if(!strncmp(sp,magic,strlen(magic)))
664246Sphk		sp += strlen(magic);
671984Scsgr
684246Sphk	/* It stops at the first '$', max 8 chars */
694246Sphk	for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
704246Sphk		continue;
714246Sphk
724246Sphk	/* get the length of the true salt */
734246Sphk	sl = ep - sp;
744246Sphk
754246Sphk	MD5Init(&ctx);
764246Sphk
774246Sphk	/* The password first, since that is what is most unknown */
784246Sphk	MD5Update(&ctx,pw,strlen(pw));
794246Sphk
804246Sphk	/* Then our magic string */
814246Sphk	MD5Update(&ctx,magic,strlen(magic));
824246Sphk
834246Sphk	/* Then the raw salt */
844246Sphk	MD5Update(&ctx,sp,sl);
854246Sphk
864246Sphk	/* Then just as many characters of the MD5(pw,salt,pw) */
874246Sphk	MD5Init(&ctx1);
884246Sphk	MD5Update(&ctx1,pw,strlen(pw));
894246Sphk	MD5Update(&ctx1,sp,sl);
904246Sphk	MD5Update(&ctx1,pw,strlen(pw));
914246Sphk	MD5Final(final,&ctx1);
928870Srgrimes	for(pl = strlen(pw); pl > 0; pl -= 16)
934246Sphk		MD5Update(&ctx,final,pl>16 ? 16 : pl);
944246Sphk
954246Sphk	/* Don't leave anything around in vm they could use. */
964246Sphk	memset(final,0,sizeof final);
974246Sphk
984246Sphk	/* Then something really weird... */
994246Sphk	for (j=0,i = strlen(pw); i ; i >>= 1)
1004246Sphk		if(i&1)
1014246Sphk		    MD5Update(&ctx, final+j, 1);
1021984Scsgr		else
1034246Sphk		    MD5Update(&ctx, pw+j, 1);
1041984Scsgr
1054246Sphk	/* Now make the output string */
1064246Sphk	strcpy(passwd,magic);
1074246Sphk	strncat(passwd,sp,sl);
1084246Sphk	strcat(passwd,"$");
1091984Scsgr
1104246Sphk	MD5Final(final,&ctx);
1114246Sphk
1128870Srgrimes	/*
1138870Srgrimes	 * and now, just to make sure things don't run too fast
1144246Sphk	 * On a 60 Mhz Pentium this takes 34 msec, so you would
1154246Sphk	 * need 30 seconds to build a 1000 entry dictionary...
1164246Sphk	 */
1174246Sphk	for(i=0;i<1000;i++) {
1184246Sphk		MD5Init(&ctx1);
1194246Sphk		if(i & 1)
1204246Sphk			MD5Update(&ctx1,pw,strlen(pw));
1211984Scsgr		else
1224246Sphk			MD5Update(&ctx1,final,16);
1231984Scsgr
1244246Sphk		if(i % 3)
1254246Sphk			MD5Update(&ctx1,sp,sl);
1261984Scsgr
1274246Sphk		if(i % 7)
1284246Sphk			MD5Update(&ctx1,pw,strlen(pw));
1294246Sphk
1304246Sphk		if(i & 1)
1314246Sphk			MD5Update(&ctx1,final,16);
1324246Sphk		else
1334246Sphk			MD5Update(&ctx1,pw,strlen(pw));
1344246Sphk		MD5Final(final,&ctx1);
1351984Scsgr	}
1361984Scsgr
1374246Sphk	p = passwd + strlen(passwd);
1388870Srgrimes
1394246Sphk	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
1404246Sphk	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
1414246Sphk	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
1424246Sphk	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
1434246Sphk	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
1444246Sphk	l =                    final[11]                ; to64(p,l,2); p += 2;
1454246Sphk	*p = '\0';
1464246Sphk
1474246Sphk	/* Don't leave anything around in vm they could use. */
1484246Sphk	memset(final,0,sizeof final);
1494246Sphk
1504246Sphk	return passwd;
1511984Scsgr}
1521984Scsgr
153