8,10d7
< *
< * $Id$
< *
13,15c10,15
< #if defined(LIBC_SCCS) && !defined(lint)
< static char rcsid[] = "$Header: /home/ncvs/src/lib/libcrypt/crypt.c,v 1.6 1997/01/14 06:09:00 jkh Exp $";
< #endif /* LIBC_SCCS and not lint */
---
> /*
> * 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.
> */
16a17,41
> /*
> * 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").
> */
>
18a44
> #include <stdlib.h>
20,21c46
< #include <md5.h>
< #include <string.h>
---
> #include <ctype.h>
23,24c48
< static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
< "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
---
> #define _CRYPT_C_
26c50
< static void to64 __P((char *, unsigned long, int));
---
> #include "crypt.h"
28c52,67
< static void
---
> #ifndef TRUE
> #define TRUE 1
> #endif
>
> #ifndef FALSE
> #define FALSE 0
> #endif
>
> /*
> * commonly used througout all algorithms
> */
>
> static unsigned char ascii64[] = /* 0 ... 63 => ascii - 64 */
> "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
>
> void
34,35d72
< static void to64 __P((char *, unsigned long, int));
<
37c74
< *s++ = itoa64[v&0x3f];
---
> *s++ = ascii64[v&0x3f];
42,51c79,82
< /*
< * UNIX password
< *
< * Use MD5 for what it is best at...
< */
<
< char *
< crypt(pw, salt)
< register const char *pw;
< register const char *salt;
---
> static char * hash_word(password, salt, output)
> const char *password;
> const char *salt;
> char *output;
53,64c84,89
< 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;
---
> 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;
66,67c91,97
< /* Refine the Salt first */
< sp = salt;
---
> 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);
69,71c99,119
< /* If it starts with the magic string, then skip that */
< if(!strncmp(sp,magic,strlen(magic)))
< sp += strlen(magic);
---
> /* 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++;
> }
> }
73,75c121,123
< /* It stops at the first '$', max 8 chars */
< for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
< continue;
---
> /* Refine the salt. Go to the end, it stops at the first '$' or NULL */
> for (ep=sp; *ep && *ep != '$'; ep++)
> continue;
77,78c125,131
< /* get the length of the true salt */
< sl = ep - sp;
---
> /* 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;
> }
80c133,149
< MD5Init(&ctx);
---
> 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$");
> }
> }
82,83c151,156
< /* The password first, since that is what is most unknown */
< MD5Update(&ctx,pw,strlen(pw));
---
> char *
> crypt(password, salt)
> const char *password;
> const char *salt;
> {
> static char output[_CRYPT_OUTPUT_SIZE];
85,86c158,159
< /* Then our magic string */
< MD5Update(&ctx,magic,strlen(magic));
---
> return hash_word(password, salt, output);
> }
88,89c161,166
< /* Then the raw salt */
< MD5Update(&ctx,sp,sl);
---
> char *
> malloc_crypt(password, salt)
> const char *password;
> const char *salt;
> {
> char * output;
91,98c168,170
< /* 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);
---
> output = (char *) malloc(sizeof(char) * _CRYPT_OUTPUT_SIZE);
> return hash_word(password, salt, output);
> }
100,101c172,178
< /* Don't leave anything around in vm they could use. */
< memset(final,0,sizeof final);
---
> int
> match_crypted(possible, crypted)
> const char * possible,
> * crypted;
> {
> char * pc;
> int match;
103,108c180
< /* Then something really weird... */
< for (i = strlen(pw); i ; i >>= 1)
< if(i&1)
< MD5Update(&ctx, final, 1);
< else
< MD5Update(&ctx, pw, 1);
---
> pc = malloc_crypt(possible, crypted);
110,113c182
< /* Now make the output string */
< strcpy(passwd,magic);
< strncat(passwd,sp,sl);
< strcat(passwd,"$");
---
> match = !strcmp(pc, crypted);
115c184
< MD5Final(final,&ctx);
---
> free(pc);
117,155c186
< /*
< * 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);
< }
<
< p = passwd + strlen(passwd);
<
< 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';
<
< /* Don't leave anything around in vm they could use. */
< memset(final,0,sizeof final);
<
< return passwd;
---
> return match;
157a189
> #undef _CRYPT_C_
< *
< * $Id$
< *
13,15c10,15
< #if defined(LIBC_SCCS) && !defined(lint)
< static char rcsid[] = "$Header: /home/ncvs/src/lib/libcrypt/crypt.c,v 1.6 1997/01/14 06:09:00 jkh Exp $";
< #endif /* LIBC_SCCS and not lint */
---
> /*
> * 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.
> */
16a17,41
> /*
> * 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").
> */
>
18a44
> #include <stdlib.h>
20,21c46
< #include <md5.h>
< #include <string.h>
---
> #include <ctype.h>
23,24c48
< static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
< "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
---
> #define _CRYPT_C_
26c50
< static void to64 __P((char *, unsigned long, int));
---
> #include "crypt.h"
28c52,67
< static void
---
> #ifndef TRUE
> #define TRUE 1
> #endif
>
> #ifndef FALSE
> #define FALSE 0
> #endif
>
> /*
> * commonly used througout all algorithms
> */
>
> static unsigned char ascii64[] = /* 0 ... 63 => ascii - 64 */
> "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
>
> void
34,35d72
< static void to64 __P((char *, unsigned long, int));
<
37c74
< *s++ = itoa64[v&0x3f];
---
> *s++ = ascii64[v&0x3f];
42,51c79,82
< /*
< * UNIX password
< *
< * Use MD5 for what it is best at...
< */
<
< char *
< crypt(pw, salt)
< register const char *pw;
< register const char *salt;
---
> static char * hash_word(password, salt, output)
> const char *password;
> const char *salt;
> char *output;
53,64c84,89
< 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;
---
> 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;
66,67c91,97
< /* Refine the Salt first */
< sp = salt;
---
> 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);
69,71c99,119
< /* If it starts with the magic string, then skip that */
< if(!strncmp(sp,magic,strlen(magic)))
< sp += strlen(magic);
---
> /* 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++;
> }
> }
73,75c121,123
< /* It stops at the first '$', max 8 chars */
< for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
< continue;
---
> /* Refine the salt. Go to the end, it stops at the first '$' or NULL */
> for (ep=sp; *ep && *ep != '$'; ep++)
> continue;
77,78c125,131
< /* get the length of the true salt */
< sl = ep - sp;
---
> /* 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;
> }
80c133,149
< MD5Init(&ctx);
---
> 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$");
> }
> }
82,83c151,156
< /* The password first, since that is what is most unknown */
< MD5Update(&ctx,pw,strlen(pw));
---
> char *
> crypt(password, salt)
> const char *password;
> const char *salt;
> {
> static char output[_CRYPT_OUTPUT_SIZE];
85,86c158,159
< /* Then our magic string */
< MD5Update(&ctx,magic,strlen(magic));
---
> return hash_word(password, salt, output);
> }
88,89c161,166
< /* Then the raw salt */
< MD5Update(&ctx,sp,sl);
---
> char *
> malloc_crypt(password, salt)
> const char *password;
> const char *salt;
> {
> char * output;
91,98c168,170
< /* 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);
---
> output = (char *) malloc(sizeof(char) * _CRYPT_OUTPUT_SIZE);
> return hash_word(password, salt, output);
> }
100,101c172,178
< /* Don't leave anything around in vm they could use. */
< memset(final,0,sizeof final);
---
> int
> match_crypted(possible, crypted)
> const char * possible,
> * crypted;
> {
> char * pc;
> int match;
103,108c180
< /* Then something really weird... */
< for (i = strlen(pw); i ; i >>= 1)
< if(i&1)
< MD5Update(&ctx, final, 1);
< else
< MD5Update(&ctx, pw, 1);
---
> pc = malloc_crypt(possible, crypted);
110,113c182
< /* Now make the output string */
< strcpy(passwd,magic);
< strncat(passwd,sp,sl);
< strcat(passwd,"$");
---
> match = !strcmp(pc, crypted);
115c184
< MD5Final(final,&ctx);
---
> free(pc);
117,155c186
< /*
< * 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);
< }
<
< p = passwd + strlen(passwd);
<
< 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';
<
< /* Don't leave anything around in vm they could use. */
< memset(final,0,sizeof final);
<
< return passwd;
---
> return match;
157a189
> #undef _CRYPT_C_