Home | History | Annotate | Download | only in openssh
      1 /*
      2  * ----------------------------------------------------------------------------
      3  * "THE BEER-WARE LICENSE" (Revision 42):
      4  * <phk (at) login.dknet.dk> wrote this file.  As long as you retain this
      5  * notice you can do whatever you want with this stuff. If we meet some
      6  * day, and you think this stuff is worth it, you can buy me a beer in
      7  * return.   Poul-Henning Kamp
      8  * ----------------------------------------------------------------------------
      9  */
     10 
     11 #include "includes.h"
     12 
     13 #if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
     14 #include <sys/types.h>
     15 
     16 #include <string.h>
     17 
     18 #include <openssl/md5.h>
     19 
     20 /* 0 ... 63 => ascii - 64 */
     21 static unsigned char itoa64[] =
     22     "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     23 
     24 static char *magic = "$1$";
     25 
     26 static char *
     27 to64(unsigned long v, int n)
     28 {
     29 	static char buf[5];
     30 	char *s = buf;
     31 
     32 	if (n > 4)
     33 		return (NULL);
     34 
     35 	memset(buf, '\0', sizeof(buf));
     36 	while (--n >= 0) {
     37 		*s++ = itoa64[v&0x3f];
     38 		v >>= 6;
     39 	}
     40 
     41 	return (buf);
     42 }
     43 
     44 int
     45 is_md5_salt(const char *salt)
     46 {
     47 	return (strncmp(salt, magic, strlen(magic)) == 0);
     48 }
     49 
     50 char *
     51 md5_crypt(const char *pw, const char *salt)
     52 {
     53 	static char passwd[120], salt_copy[9], *p;
     54 	static const char *sp, *ep;
     55 	unsigned char final[16];
     56 	int sl, pl, i, j;
     57 	MD5_CTX	ctx, ctx1;
     58 	unsigned long l;
     59 
     60 	/* Refine the Salt first */
     61 	sp = salt;
     62 
     63 	/* If it starts with the magic string, then skip that */
     64 	if(strncmp(sp, magic, strlen(magic)) == 0)
     65 		sp += strlen(magic);
     66 
     67 	/* It stops at the first '$', max 8 chars */
     68 	for (ep = sp; *ep != '$'; ep++) {
     69 		if (*ep == '\0' || ep >= (sp + 8))
     70 			return (NULL);
     71 	}
     72 
     73 	/* get the length of the true salt */
     74 	sl = ep - sp;
     75 
     76 	/* Stash the salt */
     77 	memcpy(salt_copy, sp, sl);
     78 	salt_copy[sl] = '\0';
     79 
     80 	MD5_Init(&ctx);
     81 
     82 	/* The password first, since that is what is most unknown */
     83 	MD5_Update(&ctx, pw, strlen(pw));
     84 
     85 	/* Then our magic string */
     86 	MD5_Update(&ctx, magic, strlen(magic));
     87 
     88 	/* Then the raw salt */
     89 	MD5_Update(&ctx, sp, sl);
     90 
     91 	/* Then just as many characters of the MD5(pw, salt, pw) */
     92 	MD5_Init(&ctx1);
     93 	MD5_Update(&ctx1, pw, strlen(pw));
     94 	MD5_Update(&ctx1, sp, sl);
     95 	MD5_Update(&ctx1, pw, strlen(pw));
     96 	MD5_Final(final, &ctx1);
     97 
     98 	for(pl = strlen(pw); pl > 0; pl -= 16)
     99 		MD5_Update(&ctx, final, pl > 16 ? 16 : pl);
    100 
    101 	/* Don't leave anything around in vm they could use. */
    102 	memset(final, '\0', sizeof final);
    103 
    104 	/* Then something really weird... */
    105 	for (j = 0, i = strlen(pw); i != 0; i >>= 1)
    106 		if (i & 1)
    107 			MD5_Update(&ctx, final + j, 1);
    108 		else
    109 			MD5_Update(&ctx, pw + j, 1);
    110 
    111 	/* Now make the output string */
    112 	snprintf(passwd, sizeof(passwd), "%s%s$", magic, salt_copy);
    113 
    114 	MD5_Final(final, &ctx);
    115 
    116 	/*
    117 	 * and now, just to make sure things don't run too fast
    118 	 * On a 60 Mhz Pentium this takes 34 msec, so you would
    119 	 * need 30 seconds to build a 1000 entry dictionary...
    120 	 */
    121 	for(i = 0; i < 1000; i++) {
    122 		MD5_Init(&ctx1);
    123 		if (i & 1)
    124 			MD5_Update(&ctx1, pw, strlen(pw));
    125 		else
    126 			MD5_Update(&ctx1, final, 16);
    127 
    128 		if (i % 3)
    129 			MD5_Update(&ctx1, sp, sl);
    130 
    131 		if (i % 7)
    132 			MD5_Update(&ctx1, pw, strlen(pw));
    133 
    134 		if (i & 1)
    135 			MD5_Update(&ctx1, final, 16);
    136 		else
    137 			MD5_Update(&ctx1, pw, strlen(pw));
    138 
    139 		MD5_Final(final, &ctx1);
    140 	}
    141 
    142 	p = passwd + strlen(passwd);
    143 
    144 	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
    145 	strlcat(passwd, to64(l, 4), sizeof(passwd));
    146 	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
    147 	strlcat(passwd, to64(l, 4), sizeof(passwd));
    148 	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
    149 	strlcat(passwd, to64(l, 4), sizeof(passwd));
    150 	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
    151 	strlcat(passwd, to64(l, 4), sizeof(passwd));
    152 	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
    153 	strlcat(passwd, to64(l, 4), sizeof(passwd));
    154 	l =                    final[11]                ;
    155 	strlcat(passwd, to64(l, 2), sizeof(passwd));
    156 
    157 	/* Don't leave anything around in vm they could use. */
    158 	memset(final, 0, sizeof(final));
    159 	memset(salt_copy, 0, sizeof(salt_copy));
    160 	memset(&ctx, 0, sizeof(ctx));
    161 	memset(&ctx1, 0, sizeof(ctx1));
    162 	(void)to64(0, 4);
    163 
    164 	return (passwd);
    165 }
    166 
    167 #endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
    168