Home | History | Annotate | Download | only in sshd
      1 /*
      2  * ----------------------------------------------------------------------------
      3  * "THE BEER-WARE LICENSE" (Revision 42):
      4  * <phk (at) 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 /*
     11  * Ported from FreeBSD to Linux, only minimal changes.  --marekm
     12  */
     13 
     14 /*
     15  * Adapted from shadow-19990607 by Tudor Bosman, tudorb (at) jm.nu
     16  */
     17 
     18 #include "includes.h"
     19 
     20 RCSID("$Id: md5crypt.c,v 1.5 2001/02/09 01:55:36 djm Exp $");
     21 
     22 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     23 
     24 #if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
     25 
     26 #include <openssl/md5.h>
     27 
     28 static unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
     29 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     30 
     31 static char	*magic = "$1$";	/*
     32 				 * This string is magic for
     33 				 * this algorithm.  Having
     34 				 * it this way, we can get
     35 				 * get better later on
     36 				 */
     37 
     38 static void
     39 to64(char *s, unsigned long v, int n)
     40 {
     41 	while (--n >= 0) {
     42 		*s++ = itoa64[v&0x3f];
     43 		v >>= 6;
     44 	}
     45 }
     46 
     47 int
     48 is_md5_salt(const char *salt)
     49 {
     50 	return (!strncmp(salt, magic, strlen(magic)));
     51 }
     52 
     53 /*
     54  * UNIX password
     55  *
     56  * Use MD5 for what it is best at...
     57  */
     58 
     59 char *
     60 md5_crypt(const char *pw, const char *salt)
     61 {
     62 	static char     passwd[120], *p;
     63 	static const char *sp,*ep;
     64 	unsigned char	final[16];
     65 	int sl,pl,i,j;
     66 	MD5_CTX	ctx,ctx1;
     67 	unsigned long l;
     68 
     69 	/* Refine the Salt first */
     70 	sp = salt;
     71 
     72 	/* If it starts with the magic string, then skip that */
     73 	if(!strncmp(sp,magic,strlen(magic)))
     74 		sp += strlen(magic);
     75 
     76 	/* It stops at the first '$', max 8 chars */
     77 	for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
     78 		continue;
     79 
     80 	/* get the length of the true salt */
     81 	sl = ep - sp;
     82 
     83 	MD5_Init(&ctx);
     84 
     85 	/* The password first, since that is what is most unknown */
     86 	MD5_Update(&ctx,pw,strlen(pw));
     87 
     88 	/* Then our magic string */
     89 	MD5_Update(&ctx,magic,strlen(magic));
     90 
     91 	/* Then the raw salt */
     92 	MD5_Update(&ctx,sp,sl);
     93 
     94 	/* Then just as many characters of the MD5(pw,salt,pw) */
     95 	MD5_Init(&ctx1);
     96 	MD5_Update(&ctx1,pw,strlen(pw));
     97 	MD5_Update(&ctx1,sp,sl);
     98 	MD5_Update(&ctx1,pw,strlen(pw));
     99 	MD5_Final(final,&ctx1);
    100 	for(pl = strlen(pw); pl > 0; pl -= 16)
    101 		MD5_Update(&ctx,final,pl>16 ? 16 : pl);
    102 
    103 	/* Don't leave anything around in vm they could use. */
    104 	memset(final,0,sizeof final);
    105 
    106 	/* Then something really weird... */
    107 	for (j=0,i = strlen(pw); i ; i >>= 1)
    108 		if(i&1)
    109 		    MD5_Update(&ctx, final+j, 1);
    110 		else
    111 		    MD5_Update(&ctx, pw+j, 1);
    112 
    113 	/* Now make the output string */
    114 	strcpy(passwd,magic);
    115 	strncat(passwd,sp,sl);
    116 	strcat(passwd,"$");
    117 
    118 	MD5_Final(final,&ctx);
    119 
    120 	/*
    121 	 * and now, just to make sure things don't run too fast
    122 	 * On a 60 Mhz Pentium this takes 34 msec, so you would
    123 	 * need 30 seconds to build a 1000 entry dictionary...
    124 	 */
    125 	for(i=0;i<1000;i++) {
    126 		MD5_Init(&ctx1);
    127 		if(i & 1)
    128 			MD5_Update(&ctx1,pw,strlen(pw));
    129 		else
    130 			MD5_Update(&ctx1,final,16);
    131 
    132 		if(i % 3)
    133 			MD5_Update(&ctx1,sp,sl);
    134 
    135 		if(i % 7)
    136 			MD5_Update(&ctx1,pw,strlen(pw));
    137 
    138 		if(i & 1)
    139 			MD5_Update(&ctx1,final,16);
    140 		else
    141 			MD5_Update(&ctx1,pw,strlen(pw));
    142 		MD5_Final(final,&ctx1);
    143 	}
    144 
    145 	p = passwd + strlen(passwd);
    146 
    147 	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
    148 	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
    149 	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
    150 	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
    151 	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
    152 	l =                    final[11]                ; to64(p,l,2); p += 2;
    153 	*p = '\0';
    154 
    155 	/* Don't leave anything around in vm they could use. */
    156 	memset(final,0,sizeof final);
    157 
    158 	return passwd;
    159 }
    160 
    161 #endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
    162