1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@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 * ----------------------------------------------------------------------------
| 1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@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 * $Id$ 10 *
| |
11 */ 12
| 8 */ 9
|
13#if defined(LIBC_SCCS) && !defined(lint) 14static char rcsid[] = "$Header: /home/ncvs/src/lib/libcrypt/crypt.c,v 1.6 1997/01/14 06:09:00 jkh Exp $"; 15#endif /* LIBC_SCCS and not lint */
| 10/* 11 * It has since been changed by Brandon Gillespie, the end result is not 12 * too clean, but it is clear and modular; there is no need for crypt() 13 * to be optimized (and actually a desire for the opposite) so I am not 14 * overly concerned. 15 */
|
16
| 16
|
| 17/* 18 * Assumptions made with the format of passwords: 19 * 20 * + Any password beginning with a dollar-sign is assumed to be in 21 * the Modular Crypt Format (MCF), namely: $tag$salt$hash. Any 22 * algorithms added will also use this format. Other MCF assumptions: 23 * + The algorithm tag (field 1) will be less than five characters 24 * long (yay, arbitrary limits). Anything longer is ignored. 25 * New algorithm names are not allowed to be fully numeric as 26 * anything fully numeric is mapped from other OS's not following 27 * our standard, and from older versions of this standard (such as 28 * $1$ for MD5 passwords, rather than $MD5$). 29 * + The salt can be up to 16 characters in length (more arbitrary 30 * limits). 31 * + An invalid or unrecognized algorithm tag will default to use the 32 * 'best' encryption method--whatever that may be at the time. 33 * + If the MCF is not specified, use the 'best' method, unless DES 34 * is installed--then use DES. 35 * + Any password beginning with an underscore '_' is assumed to be 36 * the Extended DES Format, which has its own salt requirements, 37 * and is not the same as the MCF. 38 * + Salt must be limited to the same ascii64 character set the hash 39 * is encoded in (namely "./0-9A-Za-z"). 40 */ 41
|
17#include <unistd.h> 18#include <stdio.h>
| 42#include <unistd.h> 43#include <stdio.h>
|
| 44#include <stdlib.h>
|
19#include <string.h>
| 45#include <string.h>
|
20#include <md5.h> 21#include <string.h>
| 46#include <ctype.h>
|
22
| 47
|
23static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 24 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
| 48#define _CRYPT_C_
|
25
| 49
|
26static void to64 __P((char *, unsigned long, int));
| 50#include "crypt.h"
|
27
| 51
|
28static void
| 52#ifndef TRUE 53#define TRUE 1 54#endif 55 56#ifndef FALSE 57#define FALSE 0 58#endif 59 60/* 61 * commonly used througout all algorithms 62 */ 63 64static unsigned char ascii64[] = /* 0 ... 63 => ascii - 64 */ 65 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 66 67void
|
29to64(s, v, n) 30 char *s; 31 unsigned long v; 32 int n; 33{
| 68to64(s, v, n) 69 char *s; 70 unsigned long v; 71 int n; 72{
|
34static void to64 __P((char *, unsigned long, int)); 35
| |
36 while (--n >= 0) {
| 73 while (--n >= 0) {
|
37 *s++ = itoa64[v&0x3f];
| 74 *s++ = ascii64[v&0x3f];
|
38 v >>= 6; 39 } 40} 41
| 75 v >>= 6; 76 } 77} 78
|
42/* 43 * UNIX password 44 * 45 * Use MD5 for what it is best at... 46 */ 47 48char * 49crypt(pw, salt) 50 register const char *pw; 51 register const char *salt;
| 79static char * hash_word(password, salt, output) 80 const char *password; 81 const char *salt; 82 char *output;
|
52{
| 83{
|
53 static char *magic = "$1$"; /* 54 * This string is magic for 55 * this algorithm. Having 56 * it this way, we can get 57 * get better later on 58 */ 59 static char passwd[120], *p; 60 static const char *sp,*ep; 61 unsigned char final[16]; 62 int sl,pl,i,j; 63 MD5_CTX ctx,ctx1; 64 unsigned long l;
| 84 unsigned char spbuf[_CRYPT_MAX_SALT_LEN+1], 85 pwbuf[_CRYPT_OUTPUT_SIZE+1], 86 * ep, * sp, * pw; 87 unsigned int sl, pl, 88 tag = _CRYPT_DEFAULT_VERSION, 89 mcf = FALSE;
|
65
| 90
|
66 /* Refine the Salt first */ 67 sp = salt;
| 91 memset(spbuf, 0, _CRYPT_MAX_SALT_LEN+1); 92 memset(pwbuf, 0, _CRYPT_MAX_SALT_LEN+1); 93 strncpy((char *) spbuf, (unsigned char *) salt, _CRYPT_MAX_SALT_LEN); 94 strncpy((char *) pwbuf, (unsigned char *) password, _CRYPT_OUTPUT_SIZE); 95 sp = &spbuf[0]; 96 pw = &pwbuf[0]; 97 pl = strlen((char *) pw);
|
68
| 98
|
69 /* If it starts with the magic string, then skip that */ 70 if(!strncmp(sp,magic,strlen(magic))) 71 sp += strlen(magic);
| 99 /* figure out what type of crypt is wanted */ 100 if (sp && sp[0] == '$') { 101 mcf = TRUE; 102 sp++; 103 if (strncasecmp((char *) sp, "MD5$", 4)==0) { 104 tag = _MD5_CRYPT; 105 sp += 4; 106 } else if (strncasecmp((char *) sp, "1$", 2)==0) { 107 tag = _MD5_CRYPT_OLD; 108 sp += 2; 109 } else if (strncasecmp((char *) sp, "SHA1$", 5)==0) { 110 tag = _SHS_CRYPT; 111 sp += 5; 112 } else { 113 tag = _CRYPT_DEFAULT_VERSION; 114 while (*sp && *sp != '$') 115 sp++; 116 if (*sp == '$') 117 sp++; 118 } 119 }
|
72
| 120
|
73 /* It stops at the first '$', max 8 chars */ 74 for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) 75 continue;
| 121 /* Refine the salt. Go to the end, it stops at the first '$' or NULL */ 122 for (ep=sp; *ep && *ep != '$'; ep++) 123 continue;
|
76
| 124
|
77 /* get the length of the true salt */ 78 sl = ep - sp;
| 125 /* we have to do this so we dont overflow _PASSWORD_LEN */ 126 if ((ep - sp) > 16) { 127 sl = 16; 128 sp[16] = (char) NULL; 129 } else { 130 sl = ep - sp; 131 }
|
79
| 132
|
80 MD5Init(&ctx);
| 133 switch (tag) { 134 case _MD5_CRYPT_OLD: 135 return crypt_md5(pw, pl, sp, sl, output, "$1$"); 136 case _MD5_CRYPT: 137 return crypt_md5(pw, pl, sp, sl, output, "$MD5$"); 138#ifdef DES_CRYPT 139 case _DES_CRYPT: 140 return crypt_des(pw, pl, sp, sl, output, ""); 141#endif 142 /* dropping a DES password through will likely cause problems, 143 but at least crypt() will return as it says it will (we cannot 144 return an error condition) */ 145 case _SHS_CRYPT: 146 default: 147 return crypt_shs(pw, pl, sp, sl, output, "$SHA1$"); 148 } 149}
|
81
| 150
|
82 /* The password first, since that is what is most unknown */ 83 MD5Update(&ctx,pw,strlen(pw));
| 151char * 152crypt(password, salt) 153 const char *password; 154 const char *salt; 155{ 156 static char output[_CRYPT_OUTPUT_SIZE];
|
84
| 157
|
85 /* Then our magic string */ 86 MD5Update(&ctx,magic,strlen(magic));
| 158 return hash_word(password, salt, output); 159}
|
87
| 160
|
88 /* Then the raw salt */ 89 MD5Update(&ctx,sp,sl);
| 161char * 162malloc_crypt(password, salt) 163 const char *password; 164 const char *salt; 165{ 166 char * output;
|
90
| 167
|
91 /* Then just as many characters of the MD5(pw,salt,pw) */ 92 MD5Init(&ctx1); 93 MD5Update(&ctx1,pw,strlen(pw)); 94 MD5Update(&ctx1,sp,sl); 95 MD5Update(&ctx1,pw,strlen(pw)); 96 MD5Final(final,&ctx1); 97 for(pl = strlen(pw); pl > 0; pl -= 16) 98 MD5Update(&ctx,final,pl>16 ? 16 : pl);
| 168 output = (char *) malloc(sizeof(char) * _CRYPT_OUTPUT_SIZE); 169 return hash_word(password, salt, output); 170}
|
99
| 171
|
100 /* Don't leave anything around in vm they could use. */ 101 memset(final,0,sizeof final);
| 172int 173match_crypted(possible, crypted) 174 const char * possible, 175 * crypted; 176{ 177 char * pc; 178 int match;
|
102
| 179
|
103 /* Then something really weird... */ 104 for (i = strlen(pw); i ; i >>= 1) 105 if(i&1) 106 MD5Update(&ctx, final, 1); 107 else 108 MD5Update(&ctx, pw, 1);
| 180 pc = malloc_crypt(possible, crypted);
|
109
| 181
|
110 /* Now make the output string */ 111 strcpy(passwd,magic); 112 strncat(passwd,sp,sl); 113 strcat(passwd,"$");
| 182 match = !strcmp(pc, crypted);
|
114
| 183
|
115 MD5Final(final,&ctx);
| 184 free(pc);
|
116
| 185
|
117 /* 118 * and now, just to make sure things don't run too fast 119 * On a 60 Mhz Pentium this takes 34 msec, so you would 120 * need 30 seconds to build a 1000 entry dictionary... 121 */ 122 for(i=0;i<1000;i++) { 123 MD5Init(&ctx1); 124 if(i & 1) 125 MD5Update(&ctx1,pw,strlen(pw)); 126 else 127 MD5Update(&ctx1,final,16); 128 129 if(i % 3) 130 MD5Update(&ctx1,sp,sl); 131 132 if(i % 7) 133 MD5Update(&ctx1,pw,strlen(pw)); 134 135 if(i & 1) 136 MD5Update(&ctx1,final,16); 137 else 138 MD5Update(&ctx1,pw,strlen(pw)); 139 MD5Final(final,&ctx1); 140 } 141 142 p = passwd + strlen(passwd); 143 144 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; 145 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; 146 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; 147 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; 148 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; 149 l = final[11] ; to64(p,l,2); p += 2; 150 *p = '\0'; 151 152 /* Don't leave anything around in vm they could use. */ 153 memset(final,0,sizeof final); 154 155 return passwd;
| 186 return match;
|
156} 157
| 187} 188
|
| 189#undef _CRYPT_C_
|
| |