3 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
21 * License for the Unix md5crypt implementation (md5_crypt):
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 * ----------------------------------------------------------------------------
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
44 #include "php-crypt_r.h"
45 #include "crypt-freesec.h"
48 #include "hphp/util/lock.h"
49 #include "hphp/util/mutex.h"
53 void _crypt_extended_init_r() {
55 static volatile bool initialized
= 0;
61 _crypt_extended_init();
65 /* MD% crypt implementation using the windows CryptoApi */
66 #define MD5_MAGIC "$1$"
67 #define MD5_MAGIC_LEN 3
69 static unsigned char itoa64
[] = /* 0 ... 63 => ascii - 64 */
70 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
73 to64(char *s
, int v
, int n
) {
75 *s
++ = itoa64
[v
& 0x3f];
81 char* php_md5_crypt_r(const char *pw
, const char *salt
, char *out
) {
82 HCRYPTPROV hCryptProv
;
84 unsigned int i
, pwl
, sl
;
85 const BYTE magic_md5
[4] = "$1$";
86 const DWORD magic_md5_len
= 3;
90 const char *sp
= salt
;
91 const char *ep
= salt
;
94 unsigned char final
[16];
96 /* Acquire a cryptographic provider context handle. */
97 if(!CryptAcquireContext(&hCryptProv
, NULL
, NULL
, PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
)) {
101 pwl
= (unsigned int) strlen(pw
);
103 /* Refine the salt first */
106 /* If it starts with the magic string, then skip that */
107 if (strncmp(sp
, MD5_MAGIC
, MD5_MAGIC_LEN
) == 0) {
111 /* It stops at the first '$', max 8 chars */
112 for (ep
= sp
; *ep
!= '\0' && *ep
!= '$' && ep
< (sp
+ 8); ep
++) {
116 /* get the length of the true salt */
117 sl
= (unsigned int)(ep
- sp
);
119 /* Create an empty hash object. */
120 if(!CryptCreateHash(hCryptProv
, CALG_MD5
, 0, 0, &ctx
)) {
124 /* The password first, since that is what is most unknown */
125 if(!CryptHashData(ctx
, (BYTE
*)pw
, pwl
, 0)) {
129 /* Then our magic string */
130 if(!CryptHashData(ctx
, magic_md5
, magic_md5_len
, 0)) {
134 /* Then the raw salt */
135 if(!CryptHashData( ctx
, (BYTE
*)sp
, sl
, 0)) {
139 /* MD5(pw,salt,pw), valid. */
140 /* Then just as many characters of the MD5(pw,salt,pw) */
141 if(!CryptCreateHash(hCryptProv
, CALG_MD5
, 0, 0, &ctx1
)) {
144 if(!CryptHashData(ctx1
, (BYTE
*)pw
, pwl
, 0)) {
147 if(!CryptHashData(ctx1
, (BYTE
*)sp
, sl
, 0)) {
150 if(!CryptHashData(ctx1
, (BYTE
*)pw
, pwl
, 0)) {
155 CryptGetHashParam(ctx1
, HP_HASHVAL
, final
, &dwHashLen
, 0);
156 /* MD5(pw,salt,pw). Valid. */
158 for (pl
= pwl
; pl
> 0; pl
-= 16) {
159 CryptHashData(ctx
, final
, (DWORD
)(pl
> 16 ? 16 : pl
), 0);
162 /* Don't leave anything around in vm they could use. */
163 RtlSecureZeroMemory(final
, sizeof(final
));
165 /* Then something really weird... */
166 for (i
= pwl
; i
!= 0; i
>>= 1) {
168 CryptHashData(ctx
, (const BYTE
*)final
, 1, 0);
170 CryptHashData(ctx
, (const BYTE
*)pw
, 1, 0);
174 memcpy(passwd
, MD5_MAGIC
, MD5_MAGIC_LEN
);
176 if (strncpy_s(passwd
+ MD5_MAGIC_LEN
, MD5_HASH_MAX_LEN
- MD5_MAGIC_LEN
, sp
, sl
+ 1) != 0) {
179 passwd
[MD5_MAGIC_LEN
+ sl
] = '\0';
180 strcat_s(passwd
, MD5_HASH_MAX_LEN
, "$");
184 /* Fetch the ctx hash value */
185 CryptGetHashParam(ctx
, HP_HASHVAL
, final
, &dwHashLen
, 0);
187 for (i
= 0; i
< 1000; i
++) {
188 if(!CryptCreateHash(hCryptProv
, CALG_MD5
, 0, 0, &ctx1
)) {
193 if(!CryptHashData(ctx1
, (BYTE
*)pw
, pwl
, 0)) {
197 if(!CryptHashData(ctx1
, (BYTE
*)final
, 16, 0)) {
203 if(!CryptHashData(ctx1
, (BYTE
*)sp
, sl
, 0)) {
209 if(!CryptHashData(ctx1
, (BYTE
*)pw
, pwl
, 0)) {
215 if(!CryptHashData(ctx1
, (BYTE
*)final
, 16, 0)) {
219 if(!CryptHashData(ctx1
, (BYTE
*)pw
, pwl
, 0)) {
224 /* Fetch the ctx hash value */
226 CryptGetHashParam(ctx1
, HP_HASHVAL
, final
, &dwHashLen
, 0);
227 if(!(CryptDestroyHash(ctx1
))) {
232 ctx1
= (HCRYPTHASH
) NULL
;
234 p
= passwd
+ sl
+ MD5_MAGIC_LEN
+ 1;
236 l
= (final
[ 0]<<16) | (final
[ 6]<<8) | final
[12]; to64(p
,l
,4); p
+= 4;
237 l
= (final
[ 1]<<16) | (final
[ 7]<<8) | final
[13]; to64(p
,l
,4); p
+= 4;
238 l
= (final
[ 2]<<16) | (final
[ 8]<<8) | final
[14]; to64(p
,l
,4); p
+= 4;
239 l
= (final
[ 3]<<16) | (final
[ 9]<<8) | final
[15]; to64(p
,l
,4); p
+= 4;
240 l
= (final
[ 4]<<16) | (final
[10]<<8) | final
[ 5]; to64(p
,l
,4); p
+= 4;
241 l
= final
[11]; to64(p
,l
,2); p
+= 2;
245 RtlSecureZeroMemory(final
, sizeof(final
));
250 if (!CryptDestroyHash(ctx1
)) {
256 CryptDestroyHash(ctx
);
259 /* Release the provider handle.*/
261 if(!(CryptReleaseContext(hCryptProv
, 0))) {
272 * MD5 password encryption.
274 char* php_md5_crypt_r(const char *pw
, const char *salt
, char *out
)
276 static __thread
char passwd
[MD5_HASH_MAX_LEN
], *p
;
278 unsigned char final
[16];
279 unsigned int i
, sl
, pwl
;
280 PHP_MD5_CTX ctx
, ctx1
;
286 /* Refine the salt first */
289 /* If it starts with the magic string, then skip that */
290 if (strncmp(sp
, MD5_MAGIC
, MD5_MAGIC_LEN
) == 0)
293 /* It stops at the first '$', max 8 chars */
294 for (ep
= sp
; *ep
!= '\0' && *ep
!= '$' && ep
< (sp
+ 8); ep
++)
297 /* get the length of the true salt */
302 /* The password first, since that is what is most unknown */
303 PHP_MD5Update(&ctx
, (const unsigned char *)pw
, pwl
);
305 /* Then our magic string */
306 PHP_MD5Update(&ctx
, (const unsigned char *)MD5_MAGIC
, MD5_MAGIC_LEN
);
308 /* Then the raw salt */
309 PHP_MD5Update(&ctx
, (const unsigned char *)sp
, sl
);
311 /* Then just as many characters of the MD5(pw,salt,pw) */
313 PHP_MD5Update(&ctx1
, (const unsigned char *)pw
, pwl
);
314 PHP_MD5Update(&ctx1
, (const unsigned char *)sp
, sl
);
315 PHP_MD5Update(&ctx1
, (const unsigned char *)pw
, pwl
);
316 PHP_MD5Final(final
, &ctx1
);
318 for (pl
= pwl
; pl
> 0; pl
-= 16)
319 PHP_MD5Update(&ctx
, final
, (unsigned int)(pl
> 16 ? 16 : pl
));
321 /* Don't leave anything around in vm they could use. */
322 memset(final
, 0, sizeof(final
));
324 /* Then something really weird... */
325 for (i
= pwl
; i
!= 0; i
>>= 1)
327 PHP_MD5Update(&ctx
, final
, 1);
329 PHP_MD5Update(&ctx
, (const unsigned char *)pw
, 1);
331 /* Now make the output string */
332 memcpy(passwd
, MD5_MAGIC
, MD5_MAGIC_LEN
);
333 strlcpy(passwd
+ MD5_MAGIC_LEN
, sp
, sl
+ 1);
336 PHP_MD5Final(final
, &ctx
);
339 * And now, just to make sure things don't run too fast. On a 60 MHz
340 * Pentium this takes 34 msec, so you would need 30 seconds to build
341 * a 1000 entry dictionary...
343 for (i
= 0; i
< 1000; i
++) {
347 PHP_MD5Update(&ctx1
, (const unsigned char *)pw
, pwl
);
349 PHP_MD5Update(&ctx1
, final
, 16);
352 PHP_MD5Update(&ctx1
, (const unsigned char *)sp
, sl
);
355 PHP_MD5Update(&ctx1
, (const unsigned char *)pw
, pwl
);
358 PHP_MD5Update(&ctx1
, final
, 16);
360 PHP_MD5Update(&ctx1
, (const unsigned char *)pw
, pwl
);
362 PHP_MD5Final(final
, &ctx1
);
365 p
= passwd
+ sl
+ MD5_MAGIC_LEN
+ 1;
367 l
= (final
[ 0]<<16) | (final
[ 6]<<8) | final
[12]; to64(p
,l
,4); p
+= 4;
368 l
= (final
[ 1]<<16) | (final
[ 7]<<8) | final
[13]; to64(p
,l
,4); p
+= 4;
369 l
= (final
[ 2]<<16) | (final
[ 8]<<8) | final
[14]; to64(p
,l
,4); p
+= 4;
370 l
= (final
[ 3]<<16) | (final
[ 9]<<8) | final
[15]; to64(p
,l
,4); p
+= 4;
371 l
= (final
[ 4]<<16) | (final
[10]<<8) | final
[ 5]; to64(p
,l
,4); p
+= 4;
372 l
= final
[11] ; to64(p
,l
,2); p
+= 2;
375 /* Don't leave anything around in vm they could use. */
376 SECURE_ZERO(final
, sizeof(final
));