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_
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_