1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Stig Bakken <ssb@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Rasmus Lerdorf <rasmus@php.net> |
18 | Pierre Joye <pierre@php.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 #include <stdlib.h>
23
24 #include "php.h"
25
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #if PHP_USE_PHP_CRYPT_R
30 # include "php_crypt_r.h"
31 # include "crypt_freesec.h"
32 #else
33 # if HAVE_CRYPT_H
34 # if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE)
35 # define _GNU_SOURCE
36 # endif
37 # include <crypt.h>
38 # endif
39 #endif
40 #if TM_IN_SYS_TIME
41 #include <sys/time.h>
42 #else
43 #include <time.h>
44 #endif
45 #if HAVE_STRING_H
46 #include <string.h>
47 #else
48 #include <strings.h>
49 #endif
50
51 #ifdef PHP_WIN32
52 #include <process.h>
53 #endif
54
55 #include "php_crypt.h"
56 #include "php_random.h"
57
58 /* sha512 crypt has the maximal salt length of 123 characters */
59 #define PHP_MAX_SALT_LEN 123
60
61 /* Used to check DES salts to ensure that they contain only valid characters */
62 #define IS_VALID_SALT_CHARACTER(c) (((c) >= '.' && (c) <= '9') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
63
64 #define DES_INVALID_SALT_ERROR "Supplied salt is not valid for DES. Possible bug in provided salt format."
65
66
PHP_MINIT_FUNCTION(crypt)67 PHP_MINIT_FUNCTION(crypt) /* {{{ */
68 {
69 REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_CS | CONST_PERSISTENT);
70 REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_CS | CONST_PERSISTENT);
71 REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_CS | CONST_PERSISTENT);
72 REGISTER_LONG_CONSTANT("CRYPT_MD5", 1, CONST_CS | CONST_PERSISTENT);
73 REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", 1, CONST_CS | CONST_PERSISTENT);
74 REGISTER_LONG_CONSTANT("CRYPT_SHA256", 1, CONST_CS | CONST_PERSISTENT);
75 REGISTER_LONG_CONSTANT("CRYPT_SHA512", 1, CONST_CS | CONST_PERSISTENT);
76
77 #if PHP_USE_PHP_CRYPT_R
78 php_init_crypt_r();
79 #endif
80
81 return SUCCESS;
82 }
83 /* }}} */
84
PHP_MSHUTDOWN_FUNCTION(crypt)85 PHP_MSHUTDOWN_FUNCTION(crypt) /* {{{ */
86 {
87 #if PHP_USE_PHP_CRYPT_R
88 php_shutdown_crypt_r();
89 #endif
90
91 return SUCCESS;
92 }
93 /* }}} */
94
95 static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
96
php_to64(char * s,int n)97 static void php_to64(char *s, int n) /* {{{ */
98 {
99 while (--n >= 0) {
100 *s = itoa64[*s & 0x3f];
101 s++;
102 }
103 }
104 /* }}} */
105
php_crypt(const char * password,const int pass_len,const char * salt,int salt_len,zend_bool quiet)106 PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const char *salt, int salt_len, zend_bool quiet)
107 {
108 char *crypt_res;
109 zend_string *result;
110 /* Windows (win32/crypt) has a stripped down version of libxcrypt and
111 a CryptoApi md5_crypt implementation */
112 #if PHP_USE_PHP_CRYPT_R
113 {
114 struct php_crypt_extended_data buffer;
115
116 if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') {
117 char output[MD5_HASH_MAX_LEN], *out;
118
119 out = php_md5_crypt_r(password, salt, output);
120 if (out) {
121 return zend_string_init(out, strlen(out), 0);
122 }
123 return NULL;
124 } else if (salt[0]=='$' && salt[1]=='6' && salt[2]=='$') {
125 char *output;
126 output = emalloc(PHP_MAX_SALT_LEN);
127
128 crypt_res = php_sha512_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
129 if (!crypt_res) {
130 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
131 efree(output);
132 return NULL;
133 } else {
134 result = zend_string_init(output, strlen(output), 0);
135 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
136 efree(output);
137 return result;
138 }
139 } else if (salt[0]=='$' && salt[1]=='5' && salt[2]=='$') {
140 char *output;
141 output = emalloc(PHP_MAX_SALT_LEN);
142
143 crypt_res = php_sha256_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
144 if (!crypt_res) {
145 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
146 efree(output);
147 return NULL;
148 } else {
149 result = zend_string_init(output, strlen(output), 0);
150 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
151 efree(output);
152 return result;
153 }
154 } else if (
155 salt[0] == '$' &&
156 salt[1] == '2' &&
157 salt[3] == '$') {
158 char output[PHP_MAX_SALT_LEN + 1];
159
160 memset(output, 0, PHP_MAX_SALT_LEN + 1);
161
162 crypt_res = php_crypt_blowfish_rn(password, salt, output, sizeof(output));
163 if (!crypt_res) {
164 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
165 return NULL;
166 } else {
167 result = zend_string_init(output, strlen(output), 0);
168 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
169 return result;
170 }
171 } else if (salt[0] == '*' && (salt[1] == '0' || salt[1] == '1')) {
172 return NULL;
173 } else {
174 /* DES Fallback */
175
176 /* Only check the salt if it's not EXT_DES */
177 if (salt[0] != '_') {
178 /* DES style hashes */
179 if (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1])) {
180 if (!quiet) {
181 /* error consistently about invalid DES fallbacks */
182 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
183 }
184 }
185 }
186
187 memset(&buffer, 0, sizeof(buffer));
188 _crypt_extended_init_r();
189
190 crypt_res = _crypt_extended_r(password, salt, &buffer);
191 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
192 return NULL;
193 } else {
194 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
195 return result;
196 }
197 }
198 }
199 #else
200
201 if (salt[0] != '$' && salt[0] != '_' && (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1]))) {
202 if (!quiet) {
203 /* error consistently about invalid DES fallbacks */
204 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
205 }
206 }
207
208 # if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE))
209 {
210 # if defined(CRYPT_R_STRUCT_CRYPT_DATA)
211 struct crypt_data buffer;
212 memset(&buffer, 0, sizeof(buffer));
213 # elif defined(CRYPT_R_CRYPTD)
214 CRYPTD buffer;
215 # else
216 # error Data struct used by crypt_r() is unknown. Please report.
217 # endif
218 crypt_res = crypt_r(password, salt, &buffer);
219 }
220 # elif defined(HAVE_CRYPT)
221 crypt_res = crypt(password, salt);
222 # else
223 # error No crypt() implementation
224 # endif
225 #endif
226
227 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
228 return NULL;
229 } else {
230 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
231 return result;
232 }
233 }
234 /* }}} */
235
236
237 /* {{{ proto string crypt(string str [, string salt])
238 Hash a string */
PHP_FUNCTION(crypt)239 PHP_FUNCTION(crypt)
240 {
241 char salt[PHP_MAX_SALT_LEN + 1];
242 char *str, *salt_in = NULL;
243 size_t str_len, salt_in_len = 0;
244 zend_string *result;
245
246 ZEND_PARSE_PARAMETERS_START(1, 2)
247 Z_PARAM_STRING(str, str_len)
248 Z_PARAM_OPTIONAL
249 Z_PARAM_STRING(salt_in, salt_in_len)
250 ZEND_PARSE_PARAMETERS_END();
251
252 salt[0] = salt[PHP_MAX_SALT_LEN] = '\0';
253
254 /* This will produce suitable results if people depend on DES-encryption
255 * available (passing always 2-character salt). At least for glibc6.1 */
256 memset(&salt[1], '$', PHP_MAX_SALT_LEN - 1);
257
258 if (salt_in) {
259 memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len));
260 } else {
261 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.");
262 }
263
264 /* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */
265 if (!*salt) {
266 strncpy(salt, "$1$", 3);
267 php_random_bytes_throw(&salt[3], 8);
268 php_to64(&salt[3], 8);
269 strncpy(&salt[11], "$", PHP_MAX_SALT_LEN - 11);
270 salt_in_len = strlen(salt);
271 } else {
272 salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len);
273 }
274 salt[salt_in_len] = '\0';
275
276 if ((result = php_crypt(str, (int)str_len, salt, (int)salt_in_len, 0)) == NULL) {
277 if (salt[0] == '*' && salt[1] == '0') {
278 RETURN_STRING("*1");
279 } else {
280 RETURN_STRING("*0");
281 }
282 }
283 RETURN_STR(result);
284 }
285 /* }}} */
286
287 /*
288 * Local variables:
289 * tab-width: 4
290 * c-basic-offset: 4
291 * End:
292 * vim600: sw=4 ts=4 fdm=marker
293 * vim<600: sw=4 ts=4
294 */
295