This source file includes following definitions.
- PHP_MINIT_FUNCTION
- PHP_MSHUTDOWN_FUNCTION
- php_to64
- php_crypt
- PHP_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #include <stdlib.h>
25
26 #include "php.h"
27 #if HAVE_CRYPT
28
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #if PHP_USE_PHP_CRYPT_R
33 # include "php_crypt_r.h"
34 # include "crypt_freesec.h"
35 #else
36 # if HAVE_CRYPT_H
37 # if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE)
38 # define _GNU_SOURCE
39 # endif
40 # include <crypt.h>
41 # endif
42 #endif
43 #if TM_IN_SYS_TIME
44 #include <sys/time.h>
45 #else
46 #include <time.h>
47 #endif
48 #if HAVE_STRING_H
49 #include <string.h>
50 #else
51 #include <strings.h>
52 #endif
53
54 #ifdef PHP_WIN32
55 #include <process.h>
56 #endif
57
58 #include "php_lcg.h"
59 #include "php_crypt.h"
60 #include "php_rand.h"
61
62
63
64
65
66
67 #if PHP_STD_DES_CRYPT
68 #define PHP_MAX_SALT_LEN 2
69 #endif
70
71 #if PHP_EXT_DES_CRYPT
72 #undef PHP_MAX_SALT_LEN
73 #define PHP_MAX_SALT_LEN 9
74 #endif
75
76 #if PHP_MD5_CRYPT
77 #undef PHP_MAX_SALT_LEN
78 #define PHP_MAX_SALT_LEN 12
79 #endif
80
81 #if PHP_BLOWFISH_CRYPT
82 #undef PHP_MAX_SALT_LEN
83 #define PHP_MAX_SALT_LEN 60
84 #endif
85
86 #if PHP_SHA512_CRYPT
87 #undef PHP_MAX_SALT_LEN
88 #define PHP_MAX_SALT_LEN 123
89 #endif
90
91
92
93
94
95 #ifndef PHP_MAX_SALT_LEN
96 #define PHP_MAX_SALT_LEN 2
97 #undef PHP_STD_DES_CRYPT
98 #define PHP_STD_DES_CRYPT 1
99 #endif
100
101 #define PHP_CRYPT_RAND php_rand()
102
103
104 #define IS_VALID_SALT_CHARACTER(c) (((c) >= '.' && (c) <= '9') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
105
106 #define DES_INVALID_SALT_ERROR "Supplied salt is not valid for DES. Possible bug in provided salt format."
107
108
109 PHP_MINIT_FUNCTION(crypt)
110 {
111 REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_CS | CONST_PERSISTENT);
112 REGISTER_LONG_CONSTANT("CRYPT_STD_DES", PHP_STD_DES_CRYPT, CONST_CS | CONST_PERSISTENT);
113 REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", PHP_EXT_DES_CRYPT, CONST_CS | CONST_PERSISTENT);
114 REGISTER_LONG_CONSTANT("CRYPT_MD5", PHP_MD5_CRYPT, CONST_CS | CONST_PERSISTENT);
115 REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", PHP_BLOWFISH_CRYPT, CONST_CS | CONST_PERSISTENT);
116
117 #ifdef PHP_SHA256_CRYPT
118 REGISTER_LONG_CONSTANT("CRYPT_SHA256", PHP_SHA256_CRYPT, CONST_CS | CONST_PERSISTENT);
119 #endif
120
121 #ifdef PHP_SHA512_CRYPT
122 REGISTER_LONG_CONSTANT("CRYPT_SHA512", PHP_SHA512_CRYPT, CONST_CS | CONST_PERSISTENT);
123 #endif
124
125 #if PHP_USE_PHP_CRYPT_R
126 php_init_crypt_r();
127 #endif
128
129 return SUCCESS;
130 }
131
132
133 PHP_MSHUTDOWN_FUNCTION(crypt)
134 {
135 #if PHP_USE_PHP_CRYPT_R
136 php_shutdown_crypt_r();
137 #endif
138
139 return SUCCESS;
140 }
141
142
143 static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
144
145 static void php_to64(char *s, zend_long v, int n)
146 {
147 while (--n >= 0) {
148 *s++ = itoa64[v&0x3f];
149 v >>= 6;
150 }
151 }
152
153
154 PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const char *salt, int salt_len, zend_bool quiet)
155 {
156 char *crypt_res;
157 zend_string *result;
158
159
160 #if PHP_USE_PHP_CRYPT_R
161 {
162 struct php_crypt_extended_data buffer;
163
164 if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') {
165 char output[MD5_HASH_MAX_LEN], *out;
166
167 out = php_md5_crypt_r(password, salt, output);
168 if (out) {
169 return zend_string_init(out, strlen(out), 0);
170 }
171 return NULL;
172 } else if (salt[0]=='$' && salt[1]=='6' && salt[2]=='$') {
173 char *output;
174 output = emalloc(PHP_MAX_SALT_LEN);
175
176 crypt_res = php_sha512_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
177 if (!crypt_res) {
178 memset(output, 0, PHP_MAX_SALT_LEN);
179 efree(output);
180 return NULL;
181 } else {
182 result = zend_string_init(output, strlen(output), 0);
183 memset(output, 0, PHP_MAX_SALT_LEN);
184 efree(output);
185 return result;
186 }
187 } else if (salt[0]=='$' && salt[1]=='5' && salt[2]=='$') {
188 char *output;
189 output = emalloc(PHP_MAX_SALT_LEN);
190
191 crypt_res = php_sha256_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
192 if (!crypt_res) {
193 memset(output, 0, PHP_MAX_SALT_LEN);
194 efree(output);
195 return NULL;
196 } else {
197 result = zend_string_init(output, strlen(output), 0);
198 memset(output, 0, PHP_MAX_SALT_LEN);
199 efree(output);
200 return result;
201 }
202 } else if (
203 salt[0] == '$' &&
204 salt[1] == '2' &&
205 salt[3] == '$') {
206 char output[PHP_MAX_SALT_LEN + 1];
207
208 memset(output, 0, PHP_MAX_SALT_LEN + 1);
209
210 crypt_res = php_crypt_blowfish_rn(password, salt, output, sizeof(output));
211 if (!crypt_res) {
212 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
213 return NULL;
214 } else {
215 result = zend_string_init(output, strlen(output), 0);
216 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
217 return result;
218 }
219 } else if (salt[0] == '*' && (salt[1] == '0' || salt[1] == '1')) {
220 return NULL;
221 } else {
222
223
224
225 if (salt[0] != '_') {
226
227 if (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1])) {
228 if (!quiet) {
229
230 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
231 }
232 }
233 }
234
235 memset(&buffer, 0, sizeof(buffer));
236 _crypt_extended_init_r();
237
238 crypt_res = _crypt_extended_r(password, salt, &buffer);
239 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
240 return NULL;
241 } else {
242 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
243 return result;
244 }
245 }
246 }
247 #else
248
249 # if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE))
250 {
251 # if defined(CRYPT_R_STRUCT_CRYPT_DATA)
252 struct crypt_data buffer;
253 memset(&buffer, 0, sizeof(buffer));
254 # elif defined(CRYPT_R_CRYPTD)
255 CRYPTD buffer;
256 # else
257 # error Data struct used by crypt_r() is unknown. Please report.
258 # endif
259 if (salt[0] != '$' && salt[0] != '_' && (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1]))) {
260 if (!quiet) {
261
262 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
263 }
264 }
265 crypt_res = crypt_r(password, salt, &buffer);
266 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
267 return NULL;
268 } else {
269 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
270 return result;
271 }
272 }
273 # endif
274 #endif
275 }
276
277
278
279
280
281 PHP_FUNCTION(crypt)
282 {
283 char salt[PHP_MAX_SALT_LEN + 1];
284 char *str, *salt_in = NULL;
285 size_t str_len, salt_in_len = 0;
286 zend_string *result;
287
288 salt[0] = salt[PHP_MAX_SALT_LEN] = '\0';
289
290
291
292 memset(&salt[1], '$', PHP_MAX_SALT_LEN - 1);
293
294 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &str, &str_len, &salt_in, &salt_in_len) == FAILURE) {
295 return;
296 }
297
298 if (salt_in) {
299 memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len));
300 } else {
301 php_error_docref(NULL, E_NOTICE, "No salt parameter was specified. You must use a randomly generated salt and a strong hash function to produce a secure hash.");
302 }
303
304
305 if (!*salt) {
306 #if PHP_MD5_CRYPT
307 strncpy(salt, "$1$", PHP_MAX_SALT_LEN);
308 php_to64(&salt[3], PHP_CRYPT_RAND, 4);
309 php_to64(&salt[7], PHP_CRYPT_RAND, 4);
310 strncpy(&salt[11], "$", PHP_MAX_SALT_LEN - 11);
311 #elif PHP_STD_DES_CRYPT
312 php_to64(&salt[0], PHP_CRYPT_RAND, 2);
313 salt[2] = '\0';
314 #endif
315 salt_in_len = strlen(salt);
316 } else {
317 salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len);
318 }
319 salt[salt_in_len] = '\0';
320
321 if ((result = php_crypt(str, (int)str_len, salt, (int)salt_in_len, 0)) == NULL) {
322 if (salt[0] == '*' && salt[1] == '0') {
323 RETURN_STRING("*1");
324 } else {
325 RETURN_STRING("*0");
326 }
327 }
328 RETURN_STR(result);
329 }
330
331 #endif
332
333
334
335
336
337
338
339
340