1/* $Id$ */
2/*
3 +----------------------------------------------------------------------+
4 | PHP Version 5 |
5 +----------------------------------------------------------------------+
6 | Copyright (c) 1997-2015 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(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
114static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
115 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
116
117static void
118to64(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
127char * 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 (strncpy_s(passwd + MD5_MAGIC_LEN, MD5_HASH_MAX_LEN - MD5_MAGIC_LEN, sp, sl + 1) != 0) {
223 goto _destroyCtx1;
224 }
225 passwd[MD5_MAGIC_LEN + sl] = '\0';
226 strcat_s(passwd, MD5_HASH_MAX_LEN, "$");
227
228 dwHashLen = 16;
229
230 /* Fetch the ctx hash value */
231 CryptGetHashParam(ctx, HP_HASHVAL, final, &dwHashLen, 0);
232
233 for (i = 0; i < 1000; i++) {
234 if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
235 goto _destroyCtx1;
236 }
237
238 if ((i & 1) != 0) {
239 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
240 goto _destroyCtx1;
241 }
242 } else {
243 if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
244 goto _destroyCtx1;
245 }
246 }
247
248 if ((i % 3) != 0) {
249 if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
250 goto _destroyCtx1;
251 }
252 }
253
254 if ((i % 7) != 0) {
255 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
256 goto _destroyCtx1;
257 }
258 }
259
260 if ((i & 1) != 0) {
261 if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
262 goto _destroyCtx1;
263 }
264 } else {
265 if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
266 goto _destroyCtx1;
267 }
268 }
269
270 /* Fetch the ctx hash value */
271 dwHashLen = 16;
272 CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
273 if(!(CryptDestroyHash(ctx1))) {
274 goto _destroyCtx0;
275 }
276 }
277
278 ctx1 = (HCRYPTHASH) NULL;
279
280 p = passwd + sl + MD5_MAGIC_LEN + 1;
281
282 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
283 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
284 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
285 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
286 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
287 l = final[11]; to64(p,l,2); p += 2;
288
289 *p = '\0';
290
291 memset(final, 0, sizeof(final));
292
293
294_destroyCtx1:
295 if (ctx1) {
296 if (!CryptDestroyHash(ctx1)) {
297
298 }
299 }
300
301_destroyCtx0:
302 CryptDestroyHash(ctx);
303
304_destroyProv:
305 /* Release the provider handle.*/
306 if(hCryptProv) {
307 if(!(CryptReleaseContext(hCryptProv, 0))) {
308 return NULL;
309 }
310 }
311
312 return out;
313}
314#else
315
316/*
317 * MD5 password encryption.
318 */
319char * php_md5_crypt_r(const char *pw, const char *salt, char *out)
320{
321 static char passwd[MD5_HASH_MAX_LEN], *p;
322 const char *sp, *ep;
323 unsigned char final[16];
324 unsigned int i, sl, pwl;
325 PHP_MD5_CTX ctx, ctx1;
326 php_uint32 l;
327 int pl;
328
329 pwl = strlen(pw);
330
331 /* Refine the salt first */
332 sp = salt;
333
334 /* If it starts with the magic string, then skip that */
335 if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0)
336 sp += MD5_MAGIC_LEN;
337
338 /* It stops at the first '$', max 8 chars */
339 for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++)
340 continue;
341
342 /* get the length of the true salt */
343 sl = ep - sp;
344
345 PHP_MD5Init(&ctx);
346
347 /* The password first, since that is what is most unknown */
348 PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl);
349
350 /* Then our magic string */
351 PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN);
352
353 /* Then the raw salt */
354 PHP_MD5Update(&ctx, (const unsigned char *)sp, sl);
355
356 /* Then just as many characters of the MD5(pw,salt,pw) */
357 PHP_MD5Init(&ctx1);
358 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
359 PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
360 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
361 PHP_MD5Final(final, &ctx1);
362
363 for (pl = pwl; pl > 0; pl -= 16)
364 PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl));
365
366 /* Don't leave anything around in vm they could use. */
367 memset(final, 0, sizeof(final));
368
369 /* Then something really weird... */
370 for (i = pwl; i != 0; i >>= 1)
371 if ((i & 1) != 0)
372 PHP_MD5Update(&ctx, final, 1);
373 else
374 PHP_MD5Update(&ctx, (const unsigned char *)pw, 1);
375
376 /* Now make the output string */
377 memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
378 strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
379 strcat(passwd, "$");
380
381 PHP_MD5Final(final, &ctx);
382
383 /*
384 * And now, just to make sure things don't run too fast. On a 60 MHz
385 * Pentium this takes 34 msec, so you would need 30 seconds to build
386 * a 1000 entry dictionary...
387 */
388 for (i = 0; i < 1000; i++) {
389 PHP_MD5Init(&ctx1);
390
391 if ((i & 1) != 0)
392 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
393 else
394 PHP_MD5Update(&ctx1, final, 16);
395
396 if ((i % 3) != 0)
397 PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
398
399 if ((i % 7) != 0)
400 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
401
402 if ((i & 1) != 0)
403 PHP_MD5Update(&ctx1, final, 16);
404 else
405 PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
406
407 PHP_MD5Final(final, &ctx1);
408 }
409
410 p = passwd + sl + MD5_MAGIC_LEN + 1;
411
412 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
413 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
414 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
415 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
416 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
417 l = final[11] ; to64(p,l,2); p += 2;
418 *p = '\0';
419
420 /* Don't leave anything around in vm they could use. */
421 memset(final, 0, sizeof(final));
422 return (passwd);
423}
424
425#undef MD5_MAGIC
426#undef MD5_MAGIC_LEN
427#endif
428
429