source: src/router/php7/ext/standard/php_crypt_r.c.orig @ 31874

Last change on this file since 31874 was 31874, checked in by brainslayer, 2 months ago

update php

File size: 10.8 KB
Line 
1/* $Id$ */
2/*
3   +----------------------------------------------------------------------+
4   | PHP Version 7                                                        |
5   +----------------------------------------------------------------------+
6   | Copyright (c) 1997-2016 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
58MUTEX_T php_crypt_extended_init_lock;
59#endif
60
61/* TODO: enable it when enabling vista/2k8 mode in tsrm */
62#if 0
63CONDITION_VARIABLE initialized;
64#endif
65
66void php_init_crypt_r()
67{
68#ifdef ZTS
69        php_crypt_extended_init_lock = tsrm_mutex_alloc();
70#endif
71}
72
73void php_shutdown_crypt_r()
74{
75#ifdef ZTS
76        tsrm_mutex_free(php_crypt_extended_init_lock);
77#endif
78}
79
80void _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(__GNUC__) && (__GNUC__ == 3))
100                initialized = 1;
101#elif defined(HAVE_ATOMIC_H) /* Solaris 10 defines atomic API within */
102                membar_producer();
103                atomic_add_int(&initialized, 1);
104#endif
105                _crypt_extended_init();
106        }
107#ifdef ZTS
108        tsrm_mutex_unlock(php_crypt_extended_init_lock);
109#endif
110}
111
112/* MD% crypt implementation using the windows CryptoApi */
113#define MD5_MAGIC "$1$"
114#define MD5_MAGIC_LEN 3
115
116static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
117        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
118
119static void
120to64(char *s, int32_t v, int n)
121{
122        while (--n >= 0) {
123                *s++ = itoa64[v & 0x3f];
124                v >>= 6;
125        }
126}
127
128#if PHP_WIN32
129char * php_md5_crypt_r(const char *pw, const char *salt, char *out) {
130        HCRYPTPROV hCryptProv;
131        HCRYPTHASH ctx, ctx1;
132        DWORD i, pwl, sl;
133        const BYTE magic_md5[4] = "$1$";
134        const DWORD magic_md5_len = 3;
135        DWORD        dwHashLen;
136        int pl;
137        __int32 l;
138        const char *sp = salt;
139        const char *ep = salt;
140        char *p = NULL;
141        char *passwd = out;
142        unsigned char final[16];
143
144        /* Acquire a cryptographic provider context handle. */
145        if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
146                return NULL;
147        }
148
149        pwl = (DWORD) strlen(pw);
150
151        /* Refine the salt first */
152        sp = salt;
153
154        /* If it starts with the magic string, then skip that */
155        if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0) {
156                sp += MD5_MAGIC_LEN;
157        }
158
159        /* It stops at the first '$', max 8 chars */
160        for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++) {
161                continue;
162        }
163
164        /* get the length of the true salt */
165        sl = (DWORD)(ep - sp);
166
167        /* Create an empty hash object. */
168        if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx)) {
169                goto _destroyProv;
170        }
171
172        /* The password first, since that is what is most unknown */
173        if(!CryptHashData(ctx, (BYTE *)pw, pwl, 0)) {
174                goto _destroyCtx0;
175        }
176
177        /* Then our magic string */
178        if(!CryptHashData(ctx, magic_md5, magic_md5_len, 0)) {
179                goto _destroyCtx0;
180        }
181
182        /* Then the raw salt */
183        if(!CryptHashData( ctx, (BYTE *)sp, sl, 0)) {
184                goto _destroyCtx0;
185        }
186
187        /* MD5(pw,salt,pw), valid. */
188        /* Then just as many characters of the MD5(pw,salt,pw) */
189        if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
190                goto _destroyCtx0;
191        }
192        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
193                goto _destroyCtx1;
194        }
195        if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
196                goto _destroyCtx1;
197        }
198        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
199                goto _destroyCtx1;
200        }
201
202        dwHashLen = 16;
203        CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
204        /*  MD5(pw,salt,pw). Valid. */
205
206        for (pl = pwl; pl > 0; pl -= 16) {
207                CryptHashData(ctx, final, (DWORD)(pl > 16 ? 16 : pl), 0);
208        }
209
210        /* Don't leave anything around in vm they could use. */
211        ZEND_SECURE_ZERO(final, sizeof(final));
212
213        /* Then something really weird... */
214        for (i = pwl; i != 0; i >>= 1) {
215                if ((i & 1) != 0) {
216                        CryptHashData(ctx, (const BYTE *)final, 1, 0);
217                } else {
218                        CryptHashData(ctx, (const BYTE *)pw, 1, 0);
219                }
220        }
221
222        memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
223
224        if (strncpy_s(passwd + MD5_MAGIC_LEN, MD5_HASH_MAX_LEN - MD5_MAGIC_LEN, sp, sl + 1) != 0) {
225                goto _destroyCtx1;
226        }
227        passwd[MD5_MAGIC_LEN + sl] = '\0';
228        strcat_s(passwd, MD5_HASH_MAX_LEN, "$");
229
230        dwHashLen = 16;
231
232        /* Fetch the ctx hash value */
233        CryptGetHashParam(ctx, HP_HASHVAL, final, &dwHashLen, 0);
234
235        for (i = 0; i < 1000; i++) {
236                if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
237                        goto _destroyCtx1;
238                }
239
240                if ((i & 1) != 0) {
241                        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
242                                goto _destroyCtx1;
243                        }
244                } else {
245                        if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
246                                goto _destroyCtx1;
247                        }
248                }
249
250                if ((i % 3) != 0) {
251                        if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
252                                goto _destroyCtx1;
253                        }
254                }
255
256                if ((i % 7) != 0) {
257                        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
258                                goto _destroyCtx1;
259                        }
260                }
261
262                if ((i & 1) != 0) {
263                        if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
264                                goto _destroyCtx1;
265                        }
266                } else {
267                        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
268                                goto _destroyCtx1;
269                        }
270                }
271
272                /* Fetch the ctx hash value */
273                dwHashLen = 16;
274                CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
275                if(!(CryptDestroyHash(ctx1))) {
276                        goto _destroyCtx0;
277                }
278        }
279
280        ctx1 = (HCRYPTHASH) NULL;
281
282        p = passwd + sl + MD5_MAGIC_LEN + 1;
283
284        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
285        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
286        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
287        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
288        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
289        l = final[11]; to64(p,l,2); p += 2;
290
291        *p = '\0';
292
293        ZEND_SECURE_ZERO(final, sizeof(final));
294
295
296_destroyCtx1:
297        if (ctx1) {
298                if (!CryptDestroyHash(ctx1)) {
299
300                }
301        }
302
303_destroyCtx0:
304        CryptDestroyHash(ctx);
305
306_destroyProv:
307        /* Release the provider handle.*/
308        if(hCryptProv) {
309                if(!(CryptReleaseContext(hCryptProv, 0))) {
310                        return NULL;
311                }
312        }
313
314        return out;
315}
316#else
317
318/*
319 * MD5 password encryption.
320 */
321char * php_md5_crypt_r(const char *pw, const char *salt, char *out)
322{
323        ZEND_TLS char passwd[MD5_HASH_MAX_LEN], *p;
324        const char *sp, *ep;
325        unsigned char final[16];
326        unsigned int i, sl, pwl;
327        PHP_MD5_CTX     ctx, ctx1;
328        php_uint32 l;
329        int pl;
330
331        pwl = strlen(pw);
332
333        /* Refine the salt first */
334        sp = salt;
335
336        /* If it starts with the magic string, then skip that */
337        if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0)
338                sp += MD5_MAGIC_LEN;
339
340        /* It stops at the first '$', max 8 chars */
341        for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++)
342                continue;
343
344        /* get the length of the true salt */
345        sl = ep - sp;
346
347        PHP_MD5Init(&ctx);
348
349        /* The password first, since that is what is most unknown */
350        PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl);
351
352        /* Then our magic string */
353        PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN);
354
355        /* Then the raw salt */
356        PHP_MD5Update(&ctx, (const unsigned char *)sp, sl);
357
358        /* Then just as many characters of the MD5(pw,salt,pw) */
359        PHP_MD5Init(&ctx1);
360        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
361        PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
362        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
363        PHP_MD5Final(final, &ctx1);
364
365        for (pl = pwl; pl > 0; pl -= 16)
366                PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl));
367
368        /* Don't leave anything around in vm they could use. */
369        memset(final, 0, sizeof(final));
370
371        /* Then something really weird... */
372        for (i = pwl; i != 0; i >>= 1)
373                if ((i & 1) != 0)
374                    PHP_MD5Update(&ctx, final, 1);
375                else
376                    PHP_MD5Update(&ctx, (const unsigned char *)pw, 1);
377
378        /* Now make the output string */
379        memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
380        strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
381        strcat(passwd, "$");
382
383        PHP_MD5Final(final, &ctx);
384
385        /*
386         * And now, just to make sure things don't run too fast. On a 60 MHz
387         * Pentium this takes 34 msec, so you would need 30 seconds to build
388         * a 1000 entry dictionary...
389         */
390        for (i = 0; i < 1000; i++) {
391                PHP_MD5Init(&ctx1);
392
393                if ((i & 1) != 0)
394                        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
395                else
396                        PHP_MD5Update(&ctx1, final, 16);
397
398                if ((i % 3) != 0)
399                        PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
400
401                if ((i % 7) != 0)
402                        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
403
404                if ((i & 1) != 0)
405                        PHP_MD5Update(&ctx1, final, 16);
406                else
407                        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
408
409                PHP_MD5Final(final, &ctx1);
410        }
411
412        p = passwd + sl + MD5_MAGIC_LEN + 1;
413
414        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
415        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
416        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
417        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
418        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
419        l =                    final[11]                ; to64(p,l,2); p += 2;
420        *p = '\0';
421
422        /* Don't leave anything around in vm they could use. */
423        ZEND_SECURE_ZERO(final, sizeof(final));
424        return (passwd);
425}
426
427#undef MD5_MAGIC
428#undef MD5_MAGIC_LEN
429#endif
430
Note: See TracBrowser for help on using the repository browser.