diff options
author | markm <markm@FreeBSD.org> | 1999-01-23 08:27:46 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 1999-01-23 08:27:46 +0000 |
commit | a0f20ba4fc91853c1b11d690f3fc4eccf3a9a8a3 (patch) | |
tree | 54e18fd1a40f0d109fa3c2656ca6cb3da498dbe1 /lib/libcrypt/crypt.c | |
parent | 41b93516e8ae0af9615f64c660b6568e39d00860 (diff) | |
download | FreeBSD-src-a0f20ba4fc91853c1b11d690f3fc4eccf3a9a8a3.zip FreeBSD-src-a0f20ba4fc91853c1b11d690f3fc4eccf3a9a8a3.tar.gz |
The new crypt code broke "make world". Back it out.
Diffstat (limited to 'lib/libcrypt/crypt.c')
-rw-r--r-- | lib/libcrypt/crypt.c | 276 |
1 files changed, 122 insertions, 154 deletions
diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c index 3d001a4..cdd4bbc 100644 --- a/lib/libcrypt/crypt.c +++ b/lib/libcrypt/crypt.c @@ -5,185 +5,153 @@ * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- - */ - -/* - * It has since been changed by Brandon Gillespie, the end result is not - * too clean, but it is clear and modular; there is no need for crypt() - * to be optimized (and actually a desire for the opposite) so I am not - * overly concerned. - */ - -/* - * Assumptions made with the format of passwords: * - * + Any password beginning with a dollar-sign is assumed to be in - * the Modular Crypt Format (MCF), namely: $tag$salt$hash. Any - * algorithms added will also use this format. Other MCF assumptions: - * + The algorithm tag (field 1) will be less than five characters - * long (yay, arbitrary limits). Anything longer is ignored. - * New algorithm names are not allowed to be fully numeric as - * anything fully numeric is mapped from other OS's not following - * our standard, and from older versions of this standard (such as - * $1$ for MD5 passwords, rather than $MD5$). - * + The salt can be up to 16 characters in length (more arbitrary - * limits). - * + An invalid or unrecognized algorithm tag will default to use the - * 'best' encryption method--whatever that may be at the time. - * + If the MCF is not specified, use the 'best' method, unless DES - * is installed--then use DES. - * + Any password beginning with an underscore '_' is assumed to be - * the Extended DES Format, which has its own salt requirements, - * and is not the same as the MCF. - * + Salt must be limited to the same ascii64 character set the hash - * is encoded in (namely "./0-9A-Za-z"). + * $Id$ + * */ +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Header$"; +#endif /* LIBC_SCCS and not lint */ + #include <unistd.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> -#include <ctype.h> - -#define _CRYPT_C_ - -#include "crypt.h" - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif +#include <md5.h> +#include <string.h> -/* - * commonly used througout all algorithms - */ +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -static unsigned char ascii64[] = /* 0 ... 63 => ascii - 64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static void to64 __P((char *, unsigned long, int)); -void +static void to64(s, v, n) char *s; unsigned long v; int n; { +static void to64 __P((char *, unsigned long, int)); + while (--n >= 0) { - *s++ = ascii64[v&0x3f]; + *s++ = itoa64[v&0x3f]; v >>= 6; } } -static char * hash_word(password, salt, output) - const char *password; - const char *salt; - char *output; -{ - unsigned char spbuf[_CRYPT_MAX_SALT_LEN+1], - pwbuf[_CRYPT_OUTPUT_SIZE+1], - * ep, * sp, * pw; - unsigned int sl, pl, - tag = _CRYPT_DEFAULT_VERSION, - mcf = FALSE; - - memset(spbuf, 0, _CRYPT_MAX_SALT_LEN+1); - memset(pwbuf, 0, _CRYPT_MAX_SALT_LEN+1); - strncpy((char *) spbuf, (unsigned char *) salt, _CRYPT_MAX_SALT_LEN); - strncpy((char *) pwbuf, (unsigned char *) password, _CRYPT_OUTPUT_SIZE); - sp = &spbuf[0]; - pw = &pwbuf[0]; - pl = strlen((char *) pw); - - /* figure out what type of crypt is wanted */ - if (sp && sp[0] == '$') { - mcf = TRUE; - sp++; - if (strncasecmp((char *) sp, "MD5$", 4)==0) { - tag = _MD5_CRYPT; - sp += 4; - } else if (strncasecmp((char *) sp, "1$", 2)==0) { - tag = _MD5_CRYPT_OLD; - sp += 2; - } else if (strncasecmp((char *) sp, "SHA1$", 5)==0) { - tag = _SHS_CRYPT; - sp += 5; - } else { - tag = _CRYPT_DEFAULT_VERSION; - while (*sp && *sp != '$') - sp++; - if (*sp == '$') - sp++; - } - } - - /* Refine the salt. Go to the end, it stops at the first '$' or NULL */ - for (ep=sp; *ep && *ep != '$'; ep++) - continue; - - /* we have to do this so we dont overflow _PASSWORD_LEN */ - if ((ep - sp) > 16) { - sl = 16; - sp[16] = (char) NULL; - } else { - sl = ep - sp; - } - - switch (tag) { - case _MD5_CRYPT_OLD: - return crypt_md5(pw, pl, sp, sl, output, "$1$"); - case _MD5_CRYPT: - return crypt_md5(pw, pl, sp, sl, output, "$MD5$"); -#ifdef DES_CRYPT - case _DES_CRYPT: - return crypt_des(pw, pl, sp, sl, output, ""); -#endif - /* dropping a DES password through will likely cause problems, - but at least crypt() will return as it says it will (we cannot - return an error condition) */ - case _SHS_CRYPT: - default: - return crypt_shs(pw, pl, sp, sl, output, "$SHA1$"); - } -} - -char * -crypt(password, salt) - const char *password; - const char *salt; -{ - static char output[_CRYPT_OUTPUT_SIZE]; - - return hash_word(password, salt, output); -} +/* + * UNIX password + * + * Use MD5 for what it is best at... + */ char * -malloc_crypt(password, salt) - const char *password; - const char *salt; +crypt(pw, salt) + register const char *pw; + register const char *salt; { - char * output; - - output = (char *) malloc(sizeof(char) * _CRYPT_OUTPUT_SIZE); - return hash_word(password, salt, output); -} - -int -match_crypted(possible, crypted) - const char * possible, - * crypted; -{ - char * pc; - int match; + static char *magic = "$1$"; /* + * This string is magic for + * this algorithm. Having + * it this way, we can get + * get better later on + */ + static char passwd[120], *p; + static const char *sp,*ep; + unsigned char final[16]; + int sl,pl,i,j; + MD5_CTX ctx,ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if(!strncmp(sp,magic,strlen(magic))) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + MD5Init(&ctx); + + /* The password first, since that is what is most unknown */ + MD5Update(&ctx,pw,strlen(pw)); + + /* Then our magic string */ + MD5Update(&ctx,magic,strlen(magic)); + + /* Then the raw salt */ + MD5Update(&ctx,sp,sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + MD5Init(&ctx1); + MD5Update(&ctx1,pw,strlen(pw)); + MD5Update(&ctx1,sp,sl); + MD5Update(&ctx1,pw,strlen(pw)); + MD5Final(final,&ctx1); + for(pl = strlen(pw); pl > 0; pl -= 16) + MD5Update(&ctx,final,pl>16 ? 16 : pl); + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + /* Then something really weird... */ + for (i = strlen(pw); i ; i >>= 1) + if(i&1) + MD5Update(&ctx, final, 1); + else + MD5Update(&ctx, pw, 1); + + /* Now make the output string */ + strcpy(passwd,magic); + strncat(passwd,sp,sl); + strcat(passwd,"$"); + + MD5Final(final,&ctx); + + /* + * and now, just to make sure things don't run too fast + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for(i=0;i<1000;i++) { + MD5Init(&ctx1); + if(i & 1) + MD5Update(&ctx1,pw,strlen(pw)); + else + MD5Update(&ctx1,final,16); + + if(i % 3) + MD5Update(&ctx1,sp,sl); + + if(i % 7) + MD5Update(&ctx1,pw,strlen(pw)); + + if(i & 1) + MD5Update(&ctx1,final,16); + else + MD5Update(&ctx1,pw,strlen(pw)); + MD5Final(final,&ctx1); + } - pc = malloc_crypt(possible, crypted); + p = passwd + strlen(passwd); - match = !strcmp(pc, crypted); + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; + l = final[11] ; to64(p,l,2); p += 2; + *p = '\0'; - free(pc); + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); - return match; + return passwd; } -#undef _CRYPT_C_ |