1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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 #include <time.h>
41 #include <string.h>
42
43 #ifdef PHP_WIN32
44 #include <process.h>
45 #endif
46
47 #include "php_crypt.h"
48 #include "php_random.h"
49
50 /* sha512 crypt has the maximal salt length of 123 characters */
51 #define PHP_MAX_SALT_LEN 123
52
53 /* Used to check DES salts to ensure that they contain only valid characters */
54 #define IS_VALID_SALT_CHARACTER(c) (((c) >= '.' && (c) <= '9') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
55
56 #define DES_INVALID_SALT_ERROR "Supplied salt is not valid for DES. Possible bug in provided salt format."
57
58
PHP_MINIT_FUNCTION(crypt)59 PHP_MINIT_FUNCTION(crypt) /* {{{ */
60 {
61 REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_CS | CONST_PERSISTENT);
62 REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_CS | CONST_PERSISTENT);
63 REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_CS | CONST_PERSISTENT);
64 REGISTER_LONG_CONSTANT("CRYPT_MD5", 1, CONST_CS | CONST_PERSISTENT);
65 REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", 1, CONST_CS | CONST_PERSISTENT);
66 REGISTER_LONG_CONSTANT("CRYPT_SHA256", 1, CONST_CS | CONST_PERSISTENT);
67 REGISTER_LONG_CONSTANT("CRYPT_SHA512", 1, CONST_CS | CONST_PERSISTENT);
68
69 #if PHP_USE_PHP_CRYPT_R
70 php_init_crypt_r();
71 #endif
72
73 return SUCCESS;
74 }
75 /* }}} */
76
PHP_MSHUTDOWN_FUNCTION(crypt)77 PHP_MSHUTDOWN_FUNCTION(crypt) /* {{{ */
78 {
79 #if PHP_USE_PHP_CRYPT_R
80 php_shutdown_crypt_r();
81 #endif
82
83 return SUCCESS;
84 }
85 /* }}} */
86
87 static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
88
php_to64(char * s,int n)89 static void php_to64(char *s, int n) /* {{{ */
90 {
91 while (--n >= 0) {
92 *s = itoa64[*s & 0x3f];
93 s++;
94 }
95 }
96 /* }}} */
97
php_crypt(const char * password,const int pass_len,const char * salt,int salt_len,zend_bool quiet)98 PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const char *salt, int salt_len, zend_bool quiet)
99 {
100 char *crypt_res;
101 zend_string *result;
102
103 if (salt[0] == '*' && (salt[1] == '0' || salt[1] == '1')) {
104 return NULL;
105 }
106
107 /* Windows (win32/crypt) has a stripped down version of libxcrypt and
108 a CryptoApi md5_crypt implementation */
109 #if PHP_USE_PHP_CRYPT_R
110 {
111 struct php_crypt_extended_data buffer;
112
113 if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') {
114 char output[MD5_HASH_MAX_LEN], *out;
115
116 out = php_md5_crypt_r(password, salt, output);
117 if (out) {
118 return zend_string_init(out, strlen(out), 0);
119 }
120 return NULL;
121 } else if (salt[0]=='$' && salt[1]=='6' && salt[2]=='$') {
122 char *output;
123 output = emalloc(PHP_MAX_SALT_LEN);
124
125 crypt_res = php_sha512_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
126 if (!crypt_res) {
127 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
128 efree(output);
129 return NULL;
130 } else {
131 result = zend_string_init(output, strlen(output), 0);
132 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
133 efree(output);
134 return result;
135 }
136 } else if (salt[0]=='$' && salt[1]=='5' && salt[2]=='$') {
137 char *output;
138 output = emalloc(PHP_MAX_SALT_LEN);
139
140 crypt_res = php_sha256_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
141 if (!crypt_res) {
142 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
143 efree(output);
144 return NULL;
145 } else {
146 result = zend_string_init(output, strlen(output), 0);
147 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
148 efree(output);
149 return result;
150 }
151 } else if (
152 salt[0] == '$' &&
153 salt[1] == '2' &&
154 salt[3] == '$') {
155 char output[PHP_MAX_SALT_LEN + 1];
156
157 memset(output, 0, PHP_MAX_SALT_LEN + 1);
158
159 crypt_res = php_crypt_blowfish_rn(password, salt, output, sizeof(output));
160 if (!crypt_res) {
161 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
162 return NULL;
163 } else {
164 result = zend_string_init(output, strlen(output), 0);
165 ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
166 return result;
167 }
168 } else {
169 /* DES Fallback */
170
171 /* Only check the salt if it's not EXT_DES */
172 if (salt[0] != '_') {
173 /* DES style hashes */
174 if (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1])) {
175 if (!quiet) {
176 /* error consistently about invalid DES fallbacks */
177 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
178 }
179 }
180 }
181
182 memset(&buffer, 0, sizeof(buffer));
183 _crypt_extended_init_r();
184
185 crypt_res = _crypt_extended_r((const unsigned char *) password, salt, &buffer);
186 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
187 return NULL;
188 } else {
189 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
190 return result;
191 }
192 }
193 }
194 #else
195
196 if (salt[0] != '$' && salt[0] != '_' && (!IS_VALID_SALT_CHARACTER(salt[0]) || !IS_VALID_SALT_CHARACTER(salt[1]))) {
197 if (!quiet) {
198 /* error consistently about invalid DES fallbacks */
199 php_error_docref(NULL, E_DEPRECATED, DES_INVALID_SALT_ERROR);
200 }
201 }
202
203 # if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE))
204 {
205 # if defined(CRYPT_R_STRUCT_CRYPT_DATA)
206 struct crypt_data buffer;
207 memset(&buffer, 0, sizeof(buffer));
208 # elif defined(CRYPT_R_CRYPTD)
209 CRYPTD buffer;
210 # else
211 # error Data struct used by crypt_r() is unknown. Please report.
212 # endif
213 crypt_res = crypt_r(password, salt, &buffer);
214 }
215 # elif defined(HAVE_CRYPT)
216 crypt_res = crypt(password, salt);
217 # else
218 # error No crypt() implementation
219 # endif
220 #endif
221
222 if (!crypt_res || (salt[0] == '*' && salt[1] == '0')) {
223 return NULL;
224 } else {
225 result = zend_string_init(crypt_res, strlen(crypt_res), 0);
226 return result;
227 }
228 }
229 /* }}} */
230
231
232 /* {{{ proto string crypt(string str [, string salt])
233 Hash a string */
PHP_FUNCTION(crypt)234 PHP_FUNCTION(crypt)
235 {
236 char salt[PHP_MAX_SALT_LEN + 1];
237 char *str, *salt_in = NULL;
238 size_t str_len, salt_in_len = 0;
239 zend_string *result;
240
241 ZEND_PARSE_PARAMETERS_START(1, 2)
242 Z_PARAM_STRING(str, str_len)
243 Z_PARAM_OPTIONAL
244 Z_PARAM_STRING(salt_in, salt_in_len)
245 ZEND_PARSE_PARAMETERS_END();
246
247 salt[0] = salt[PHP_MAX_SALT_LEN] = '\0';
248
249 /* This will produce suitable results if people depend on DES-encryption
250 * available (passing always 2-character salt). At least for glibc6.1 */
251 memset(&salt[1], '$', PHP_MAX_SALT_LEN - 1);
252
253 if (salt_in) {
254 memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len));
255 } else {
256 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.");
257 }
258
259 /* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */
260 if (!*salt) {
261 memcpy(salt, "$1$", 3);
262 php_random_bytes_throw(&salt[3], 8);
263 php_to64(&salt[3], 8);
264 strncpy(&salt[11], "$", PHP_MAX_SALT_LEN - 11);
265 salt_in_len = strlen(salt);
266 } else {
267 salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len);
268 }
269 salt[salt_in_len] = '\0';
270
271 if ((result = php_crypt(str, (int)str_len, salt, (int)salt_in_len, 0)) == NULL) {
272 if (salt[0] == '*' && salt[1] == '0') {
273 RETURN_STRING("*1");
274 } else {
275 RETURN_STRING("*0");
276 }
277 }
278 RETURN_STR(result);
279 }
280 /* }}} */
281