1 /* $Id$ */
2 /*
3 +----------------------------------------------------------------------+
4 | PHP Version 5 |
5 +----------------------------------------------------------------------+
6 | Copyright (c) 1997-2013 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
16 | Authors: Pierre Alain Joye <pajoye@php.net |
17 +----------------------------------------------------------------------+
18 */
19
20 /*
21 * License for the Unix md5crypt implementation (md5_crypt):
22 *
23 * ----------------------------------------------------------------------------
24 * "THE BEER-WARE LICENSE" (Revision 42):
25 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
26 * can do whatever you want with this stuff. If we meet some day, and you think
27 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
28 * ----------------------------------------------------------------------------
29 *
30 * from FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp
31 * via OpenBSD: md5crypt.c,v 1.9 1997/07/23 20:58:27 kstailey Exp
32 * via NetBSD: md5crypt.c,v 1.4.2.1 2002/01/22 19:31:59 he Exp
33 *
34 */
35
36 #include "php.h"
37
38 #include <string.h>
39
40 #if PHP_WIN32
41 # include <windows.h>
42 # include <Wincrypt.h>
43 #endif
44
45 #ifdef HAVE_ATOMIC_H /* Solaris 10 defines atomic API within */
46 # include <atomic.h>
47 #else
48 # include <signal.h>
49 #endif
50 #include "php_crypt_r.h"
51 #include "crypt_freesec.h"
52
53 #if !PHP_WIN32
54 #include "ext/standard/md5.h"
55 #endif
56
57 #ifdef ZTS
58 MUTEX_T php_crypt_extended_init_lock;
59 #endif
60
61 /* TODO: enable it when enabling vista/2k8 mode in tsrm */
62 #if 0
63 CONDITION_VARIABLE initialized;
64 #endif
65
php_init_crypt_r()66 void php_init_crypt_r()
67 {
68 #ifdef ZTS
69 php_crypt_extended_init_lock = tsrm_mutex_alloc();
70 #endif
71 }
72
php_shutdown_crypt_r()73 void php_shutdown_crypt_r()
74 {
75 #ifdef ZTS
76 tsrm_mutex_free(php_crypt_extended_init_lock);
77 #endif
78 }
79
_crypt_extended_init_r(void)80 void _crypt_extended_init_r(void)
81 {
82 #ifdef PHP_WIN32
83 LONG volatile initialized = 0;
84 #elif defined(HAVE_ATOMIC_H) /* Solaris 10 defines atomic API within */
85 volatile unsigned int initialized = 0;
86 #else
87 static volatile sig_atomic_t initialized = 0;
88 #endif
89
90 #ifdef ZTS
91 tsrm_mutex_lock(php_crypt_extended_init_lock);
92 #endif
93
94 if (!initialized) {
95 #ifdef PHP_WIN32
96 InterlockedIncrement(&initialized);
97 #elif defined(HAVE_SYNC_FETCH_AND_ADD)
98 __sync_fetch_and_add(&initialized, 1);
99 #elif defined(HAVE_ATOMIC_H) /* Solaris 10 defines atomic API within */
100 membar_producer();
101 atomic_add_int(&initialized, 1);
102 #endif
103 _crypt_extended_init();
104 }
105 #ifdef ZTS
106 tsrm_mutex_unlock(php_crypt_extended_init_lock);
107 #endif
108 }
109
110 /* MD% crypt implementation using the windows CryptoApi */
111 #define MD5_MAGIC "$1$"
112 #define MD5_MAGIC_LEN 3
113
114 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
115 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
116
117 static void
to64(char * s,int32_t v,int n)118 to64(char *s, int32_t v, int n)
119 {
120 while (--n >= 0) {
121 *s++ = itoa64[v & 0x3f];
122 v >>= 6;
123 }
124 }
125
126 #if PHP_WIN32
php_md5_crypt_r(const char * pw,const char * salt,char * out)127 char * php_md5_crypt_r(const char *pw, const char *salt, char *out) {
128 HCRYPTPROV hCryptProv;
129 HCRYPTHASH ctx, ctx1;
130 unsigned int i, pwl, sl;
131 const BYTE magic_md5[4] = "$1$";
132 const DWORD magic_md5_len = 3;
133 DWORD dwHashLen;
134 int pl;
135 __int32 l;
136 const char *sp = salt;
137 const char *ep = salt;
138 char *p = NULL;
139 char *passwd = out;
140 unsigned char final[16];
141
142 /* Acquire a cryptographic provider context handle. */
143 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
144 return NULL;
145 }
146
147 pwl = (unsigned int) strlen(pw);
148
149 /* Refine the salt first */
150 sp = salt;
151
152 /* If it starts with the magic string, then skip that */
153 if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0) {
154 sp += MD5_MAGIC_LEN;
155 }
156
157 /* It stops at the first '$', max 8 chars */
158 for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++) {
159 continue;
160 }
161
162 /* get the length of the true salt */
163 sl = ep - sp;
164
165 /* Create an empty hash object. */
166 if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx)) {
167 goto _destroyProv;
168 }
169
170 /* The password first, since that is what is most unknown */
171 if(!CryptHashData(ctx, (BYTE *)pw, pwl, 0)) {
172 goto _destroyCtx0;
173 }
174
175 /* Then our magic string */
176 if(!CryptHashData(ctx, magic_md5, magic_md5_len, 0)) {
177 goto _destroyCtx0;
178 }
179
180 /* Then the raw salt */
181 if(!CryptHashData( ctx, (BYTE *)sp, sl, 0)) {
182 goto _destroyCtx0;
183 }
184
185 /* MD5(pw,salt,pw), valid. */
186 /* Then just as many characters of the MD5(pw,salt,pw) */
187 if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
188 goto _destroyCtx0;
189 }
190 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
191 goto _destroyCtx1;
192 }
193 if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
194 goto _destroyCtx1;
195 }
196 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
197 goto _destroyCtx1;
198 }
199
200 dwHashLen = 16;
201 CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
202 /* MD5(pw,salt,pw). Valid. */
203
204 for (pl = pwl; pl > 0; pl -= 16) {
205 CryptHashData(ctx, final, (DWORD)(pl > 16 ? 16 : pl), 0);
206 }
207
208 /* Don't leave anything around in vm they could use. */
209 memset(final, 0, sizeof(final));
210
211 /* Then something really weird... */
212 for (i = pwl; i != 0; i >>= 1) {
213 if ((i & 1) != 0) {
214 CryptHashData(ctx, (const BYTE *)final, 1, 0);
215 } else {
216 CryptHashData(ctx, (const BYTE *)pw, 1, 0);
217 }
218 }
219
220 memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
221
222 #if _MSC_VER >= 1500
223 if (strncpy_s(passwd + MD5_MAGIC_LEN, MD5_HASH_MAX_LEN - MD5_MAGIC_LEN, sp, sl + 1) != 0) {
224 goto _destroyCtx1;
225 }
226 passwd[MD5_MAGIC_LEN + sl] = '\0';
227 strcat_s(passwd, MD5_HASH_MAX_LEN, "$");
228 #else
229 /* VC6 version doesn't have strcat_s or strncpy_s */
230 strncpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
231 strcat(passwd, "$");
232 #endif
233 dwHashLen = 16;
234
235 /* Fetch the ctx hash value */
236 CryptGetHashParam(ctx, HP_HASHVAL, final, &dwHashLen, 0);
237
238 for (i = 0; i < 1000; i++) {
239 if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
240 goto _destroyCtx1;
241 }
242
243 if ((i & 1) != 0) {
244 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
245 goto _destroyCtx1;
246 }
247 } else {
248 if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
249 goto _destroyCtx1;
250 }
251 }
252
253 if ((i % 3) != 0) {
254 if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
255 goto _destroyCtx1;
256 }
257 }
258
259 if ((i % 7) != 0) {
260 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
261 goto _destroyCtx1;
262 }
263 }
264
265 if ((i & 1) != 0) {
266 if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
267 goto _destroyCtx1;
268 }
269 } else {
270 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
271 goto _destroyCtx1;
272 }
273 }
274
275 /* Fetch the ctx hash value */
276 dwHashLen = 16;
277 CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
278 if(!(CryptDestroyHash(ctx1))) {
279 goto _destroyCtx0;
280 }
281 }
282
283 ctx1 = (HCRYPTHASH) NULL;
284
285 p = passwd + sl + MD5_MAGIC_LEN + 1;
286
287 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
288 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
289 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
290 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
291 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
292 l = final[11]; to64(p,l,2); p += 2;
293
294 *p = '\0';
295
296 memset(final, 0, sizeof(final));
297
298
299 _destroyCtx1:
300 if (ctx1) {
301 if (!CryptDestroyHash(ctx1)) {
302
303 }
304 }
305
306 _destroyCtx0:
307 CryptDestroyHash(ctx);
308
309 _destroyProv:
310 /* Release the provider handle.*/
311 if(hCryptProv) {
312 if(!(CryptReleaseContext(hCryptProv, 0))) {
313 return NULL;
314 }
315 }
316
317 return out;
318 }
319 #else
320
321 /*
322 * MD5 password encryption.
323 */
php_md5_crypt_r(const char * pw,const char * salt,char * out)324 char * php_md5_crypt_r(const char *pw, const char *salt, char *out)
325 {
326 static char passwd[MD5_HASH_MAX_LEN], *p;
327 const char *sp, *ep;
328 unsigned char final[16];
329 unsigned int i, sl, pwl;
330 PHP_MD5_CTX ctx, ctx1;
331 php_uint32 l;
332 int pl;
333
334 pwl = strlen(pw);
335
336 /* Refine the salt first */
337 sp = salt;
338
339 /* If it starts with the magic string, then skip that */
340 if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0)
341 sp += MD5_MAGIC_LEN;
342
343 /* It stops at the first '$', max 8 chars */
344 for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++)
345 continue;
346
347 /* get the length of the true salt */
348 sl = ep - sp;
349
350 PHP_MD5Init(&ctx);
351
352 /* The password first, since that is what is most unknown */
353 PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl);
354
355 /* Then our magic string */
356 PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN);
357
358 /* Then the raw salt */
359 PHP_MD5Update(&ctx, (const unsigned char *)sp, sl);
360
361 /* Then just as many characters of the MD5(pw,salt,pw) */
362 PHP_MD5Init(&ctx1);
363 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
364 PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
365 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
366 PHP_MD5Final(final, &ctx1);
367
368 for (pl = pwl; pl > 0; pl -= 16)
369 PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl));
370
371 /* Don't leave anything around in vm they could use. */
372 memset(final, 0, sizeof(final));
373
374 /* Then something really weird... */
375 for (i = pwl; i != 0; i >>= 1)
376 if ((i & 1) != 0)
377 PHP_MD5Update(&ctx, final, 1);
378 else
379 PHP_MD5Update(&ctx, (const unsigned char *)pw, 1);
380
381 /* Now make the output string */
382 memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
383 strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
384 strcat(passwd, "$");
385
386 PHP_MD5Final(final, &ctx);
387
388 /*
389 * And now, just to make sure things don't run too fast. On a 60 MHz
390 * Pentium this takes 34 msec, so you would need 30 seconds to build
391 * a 1000 entry dictionary...
392 */
393 for (i = 0; i < 1000; i++) {
394 PHP_MD5Init(&ctx1);
395
396 if ((i & 1) != 0)
397 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
398 else
399 PHP_MD5Update(&ctx1, final, 16);
400
401 if ((i % 3) != 0)
402 PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
403
404 if ((i % 7) != 0)
405 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
406
407 if ((i & 1) != 0)
408 PHP_MD5Update(&ctx1, final, 16);
409 else
410 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
411
412 PHP_MD5Final(final, &ctx1);
413 }
414
415 p = passwd + sl + MD5_MAGIC_LEN + 1;
416
417 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
418 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
419 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
420 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
421 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
422 l = final[11] ; to64(p,l,2); p += 2;
423 *p = '\0';
424
425 /* Don't leave anything around in vm they could use. */
426 memset(final, 0, sizeof(final));
427 return (passwd);
428 }
429
430 #undef MD5_MAGIC
431 #undef MD5_MAGIC_LEN
432 #endif
433
434