crypt.c revision 42981
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
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
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
42#include <unistd.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <ctype.h>
47
48#define _CRYPT_C_
49
50#include "crypt.h"
51
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
68to64(s, v, n)
69	char *s;
70	unsigned long v;
71	int n;
72{
73	while (--n >= 0) {
74		*s++ = ascii64[v&0x3f];
75		v >>= 6;
76	}
77}
78
79static char * hash_word(password, salt, output)
80	const char *password;
81	const char *salt;
82        char *output;
83{
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;
90
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);
98
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    }
120
121    /* Refine the salt. Go to the end, it stops at the first '$' or NULL */
122    for (ep=sp; *ep && *ep != '$'; ep++)
123        continue;
124
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    }
132
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}
150
151char *
152crypt(password, salt)
153	const char *password;
154	const char *salt;
155{
156    static char output[_CRYPT_OUTPUT_SIZE];
157
158    return hash_word(password, salt, output);
159}
160
161char *
162malloc_crypt(password, salt)
163	const char *password;
164	const char *salt;
165{
166    char * output;
167
168    output = (char *) malloc(sizeof(char) * _CRYPT_OUTPUT_SIZE);
169    return hash_word(password, salt, output);
170}
171
172int
173match_crypted(possible, crypted)
174    const char * possible,
175               * crypted;
176{
177    char * pc;
178    int    match;
179
180    pc = malloc_crypt(possible, crypted);
181
182    match = !strcmp(pc, crypted);
183
184    free(pc);
185
186    return match;
187}
188
189#undef _CRYPT_C_
190