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@zend.com> |
17 | Rasmus Lerdorf <rasmus@php.net> |
18 | Pierre Joye <pierre@php.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 /* $Id$ */
23
24 #include <stdlib.h>
25
26 #include "php.h"
27
28 #if HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #if PHP_USE_PHP_CRYPT_R
32 # include "php_crypt_r.h"
33 # include "crypt_freesec.h"
34 #else
35 # if HAVE_CRYPT_H
36 # if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE)
37 # define _GNU_SOURCE
38 # endif
39 # include <crypt.h>
40 # endif
41 #endif
42 #if TM_IN_SYS_TIME
43 #include <sys/time.h>
44 #else
45 #include <time.h>
46 #endif
47 #if HAVE_STRING_H
48 #include <string.h>
49 #else
50 #include <strings.h>
51 #endif
52
53 #ifdef PHP_WIN32
54 #include <process.h>
55 #endif
56
57 #include "php_crypt.h"
58 #include "php_random.h"
59
60 /* sha512 crypt has the maximal salt length of 123 characters */
61 #define PHP_MAX_SALT_LEN 123
62
63 /* Used to check DES salts to ensure that they contain only valid characters */
64 #define IS_VALID_SALT_CHARACTER(c) (((c) >= '.' && (c) <= '9') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
65
66 #define DES_INVALID_SALT_ERROR "Supplied salt is not valid for DES. Possible bug in provided salt format."
67
68
PHP_MINIT_FUNCTION(crypt)69 PHP_MINIT_FUNCTION(crypt) /* {{{ */
70 {
71 REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_CS | CONST_PERSISTENT);
72 REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_CS | CONST_PERSISTENT);
73 REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_CS | CONST_PERSISTENT);
74 REGISTER_LONG_CONSTANT("CRYPT_MD5", 1, CONST_CS | CONST_PERSISTENT);
75 REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", 1, CONST_CS | CONST_PERSISTENT);
76 REGISTER_LONG_CONSTANT("CRYPT_SHA256", 1, CONST_CS | CONST_PERSISTENT);
77 REGISTER_LONG_CONSTANT("CRYPT_SHA512", 1, CONST_CS | CONST_PERSISTENT);
78
79 #if PHP_USE_PHP_CRYPT_R
80 php_init_crypt_r();
81 #endif
82
83 return SUCCESS;
84 }
85 /* }}} */
86
PHP_MSHUTDOWN_FUNCTION(crypt)87 PHP_MSHUTDOWN_FUNCTION(crypt) /* {{{ */
88 {
89 #if PHP_USE_PHP_CRYPT_R
90 php_shutdown_crypt_r();
91 #endif
92
93 return SUCCESS;
94 }
95 /* }}} */
96
97 static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
98
php_to64(char * s,int n)99 static void php_to64(char *s, int n) /* {{{ */
100 {
101 while (--n >= 0) {
102 *s = itoa64[*s & 0x3f];
103 s++;
104 }
105 }
106 /* }}} */
107
php_crypt(const char * password,const int pass_len,const char * salt,int salt_len,zend_bool quiet)108 PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const char *salt, int salt_len, zend_bool quiet)
109 {
110 char *crypt_res;
111 zend_string *result;
112 /* Windows (win32/crypt) has a stripped down version of libxcrypt and
113 a CryptoApi md5_crypt implementation */
114 #if PHP_USE_PHP_CRYPT_R
115 {
116 struct php_crypt_extended_data buffer;
117
118 if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') {
119 char output[MD5_HASH_MAX_LEN], *out;
120
121 out = php_md5_crypt_r(password, salt, output);
122 if (out) {
123 return zend_string_init(out, strlen(out), 0);
124 }
125 return NULL;
126 } else if (salt[0]=='$' && salt[1]=='6' && salt[2]=='$') {
127 char *output;
128 output = emalloc(PHP_MAX_SALT_LEN);
129
130 crypt_res = php_sha512_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
131 if (!crypt_res) {
132 memset(output, 0, PHP_MAX_SALT_LEN);
133 efree(output);
134 return NULL;
135 } else {
136 result = zend_string_init(output, strlen(output), 0);
137 memset(output, 0, PHP_MAX_SALT_LEN);
138 efree(output);
139 return result;
140 }
141 } else if (salt[0]=='$' && salt[1]=='5' && salt[2]=='$') {
142 char *output;
143 output = emalloc(PHP_MAX_SALT_LEN);
144
145 crypt_res = php_sha256_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
146 if (!crypt_res) {
147 memset(output, 0, PHP_MAX_SALT_LEN);
148 efree(output);
149 return NULL;
150 } else {
151 result = zend_string_init(output, strlen(output), 0);
152 memset(output, 0, PHP_MAX_SALT_LEN);
153 efree(output);
154 return result;
155 }
156 } else if (
157 salt[0] == '$' &&
158 salt[1] == '2' &&
159 salt[3] == '$') {
160 char output[PHP_MAX_SALT_LEN + 1];
161
162 memset(output, 0, PHP_MAX_SALT_LEN + 1);
163
164 crypt_res = php_crypt_blowfish_rn(password, salt, output, sizeof(output));
165 if (!crypt_res) {
166 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
167 return NULL;
168 } else {
169 result = zend_string_init(output, strlen(output), 0);
170 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
171 return result;
172 }
173 } else if (salt[0] == '*' && (salt[1] == '0' || salt[1] == '1')) {
174 return NULL;
175 } else {
176 /* DES Fallback */
177
178 /* Only check the salt if it's not EXT_DES */
179 if (salt[0] != '_') {
180 /* DES style hashes */
181 if (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1])) {
182 if (!quiet) {
183 /* error consistently about invalid DES fallbacks */
184 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
185 }
186 }
187 }
188
189 memset(&buffer, 0, sizeof(buffer));
190 _crypt_extended_init_r();
191
192 crypt_res = _crypt_extended_r(password, salt, &buffer);
193 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
194 return NULL;
195 } else {
196 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
197 return result;
198 }
199 }
200 }
201 #else
202
203 if (salt[0] != '$' && salt[0] != '_' && (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1]))) {
204 if (!quiet) {
205 /* error consistently about invalid DES fallbacks */
206 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
207 }
208 }
209
210 # if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE))
211 {
212 # if defined(CRYPT_R_STRUCT_CRYPT_DATA)
213 struct crypt_data buffer;
214 memset(&buffer, 0, sizeof(buffer));
215 # elif defined(CRYPT_R_CRYPTD)
216 CRYPTD buffer;
217 # else
218 # error Data struct used by crypt_r() is unknown. Please report.
219 # endif
220 crypt_res = crypt_r(password, salt, &buffer);
221 }
222 # elif defined(HAVE_CRYPT)
223 crypt_res = crypt(password, salt);
224 # else
225 # error No crypt() implementation
226 # endif
227 #endif
228
229 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
230 return NULL;
231 } else {
232 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
233 return result;
234 }
235 }
236 /* }}} */
237
238
239 /* {{{ proto string crypt(string str [, string salt])
240 Hash a string */
PHP_FUNCTION(crypt)241 PHP_FUNCTION(crypt)
242 {
243 char salt[PHP_MAX_SALT_LEN + 1];
244 char *str, *salt_in = NULL;
245 size_t str_len, salt_in_len = 0;
246 zend_string *result;
247
248 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &str, &str_len, &salt_in, &salt_in_len) == FAILURE) {
249 return;
250 }
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