/src/php-src/ext/standard/php_crypt_r.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Copyright (c) The PHP Group | |
4 | | +----------------------------------------------------------------------+ |
5 | | | This source file is subject to version 3.01 of the PHP license, | |
6 | | | that is bundled with this package in the file LICENSE, and is | |
7 | | | available through the world-wide-web at the following url: | |
8 | | | https://www.php.net/license/3_01.txt | |
9 | | | If you did not receive a copy of the PHP license and are unable to | |
10 | | | obtain it through the world-wide-web, please send a note to | |
11 | | | license@php.net so we can mail you a copy immediately. | |
12 | | +----------------------------------------------------------------------+ |
13 | | | Authors: Pierre Alain Joye <pajoye@php.net | |
14 | | +----------------------------------------------------------------------+ |
15 | | */ |
16 | | |
17 | | /* |
18 | | * License for the Unix md5crypt implementation (md5_crypt): |
19 | | * |
20 | | * ---------------------------------------------------------------------------- |
21 | | * "THE BEER-WARE LICENSE" (Revision 42): |
22 | | * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you |
23 | | * can do whatever you want with this stuff. If we meet some day, and you think |
24 | | * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp |
25 | | * ---------------------------------------------------------------------------- |
26 | | * |
27 | | * from FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp |
28 | | * via OpenBSD: md5crypt.c,v 1.9 1997/07/23 20:58:27 kstailey Exp |
29 | | * via NetBSD: md5crypt.c,v 1.4.2.1 2002/01/22 19:31:59 he Exp |
30 | | * |
31 | | */ |
32 | | |
33 | | #include "php.h" |
34 | | |
35 | | #include <string.h> |
36 | | |
37 | | #ifdef PHP_WIN32 |
38 | | # include <windows.h> |
39 | | # include <Wincrypt.h> |
40 | | #endif |
41 | | |
42 | | #include "php_crypt_r.h" |
43 | | #include "crypt_freesec.h" |
44 | | #include "ext/standard/md5.h" |
45 | | |
46 | | #ifdef ZTS |
47 | | MUTEX_T php_crypt_extended_init_lock; |
48 | | #endif |
49 | | |
50 | | void php_init_crypt_r(void) |
51 | 16 | { |
52 | | #ifdef ZTS |
53 | | php_crypt_extended_init_lock = tsrm_mutex_alloc(); |
54 | | #endif |
55 | 16 | } |
56 | | |
57 | | void php_shutdown_crypt_r(void) |
58 | 0 | { |
59 | | #ifdef ZTS |
60 | | tsrm_mutex_free(php_crypt_extended_init_lock); |
61 | | #endif |
62 | 0 | } |
63 | | |
64 | | void _crypt_extended_init_r(void) |
65 | 0 | { |
66 | 0 | static int initialized = 0; |
67 | |
|
68 | | #ifdef ZTS |
69 | | tsrm_mutex_lock(php_crypt_extended_init_lock); |
70 | | #endif |
71 | |
|
72 | 0 | if (!initialized) { |
73 | 0 | initialized = 1; |
74 | 0 | _crypt_extended_init(); |
75 | 0 | } |
76 | |
|
77 | | #ifdef ZTS |
78 | | tsrm_mutex_unlock(php_crypt_extended_init_lock); |
79 | | #endif |
80 | 0 | } |
81 | | |
82 | | /* MD5 crypt implementation using the windows CryptoApi */ |
83 | 0 | #define MD5_MAGIC "$1$" |
84 | 0 | #define MD5_MAGIC_LEN 3 |
85 | | |
86 | | static const unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ |
87 | | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
88 | | |
89 | | /* Convert a 16/32 bit integer to Base64 string representation */ |
90 | | static void to64(char *s, int32_t v, int n) |
91 | 0 | { |
92 | 0 | while (--n >= 0) { |
93 | 0 | *s++ = itoa64[v & 0x3f]; |
94 | 0 | v >>= 6; |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | /* |
99 | | * MD5 password encryption. |
100 | | */ |
101 | | char * php_md5_crypt_r(const char *pw, const char *salt, char *out) |
102 | 0 | { |
103 | 0 | ZEND_TLS char passwd[MD5_HASH_MAX_LEN], *p; |
104 | 0 | const char *sp, *ep; |
105 | 0 | unsigned char final[16]; |
106 | 0 | unsigned int i, sl, pwl; |
107 | 0 | PHP_MD5_CTX ctx, ctx1; |
108 | 0 | uint32_t l; |
109 | 0 | int pl; |
110 | |
|
111 | 0 | pwl = strlen(pw); |
112 | | |
113 | | /* Refine the salt first */ |
114 | 0 | sp = salt; |
115 | | |
116 | | /* If it starts with the magic string, then skip that */ |
117 | 0 | if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0) |
118 | 0 | sp += MD5_MAGIC_LEN; |
119 | | |
120 | | /* It stops at the first '$', max 8 chars */ |
121 | 0 | for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++); |
122 | | |
123 | | /* get the length of the true salt */ |
124 | 0 | sl = ep - sp; |
125 | |
|
126 | 0 | PHP_MD5Init(&ctx); |
127 | | |
128 | | /* The password first, since that is what is most unknown */ |
129 | 0 | PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl); |
130 | | |
131 | | /* Then our magic string */ |
132 | 0 | PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN); |
133 | | |
134 | | /* Then the raw salt */ |
135 | 0 | PHP_MD5Update(&ctx, (const unsigned char *)sp, sl); |
136 | | |
137 | | /* Then just as many characters of the MD5(pw,salt,pw) */ |
138 | 0 | PHP_MD5Init(&ctx1); |
139 | 0 | PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); |
140 | 0 | PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl); |
141 | 0 | PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); |
142 | 0 | PHP_MD5Final(final, &ctx1); |
143 | |
|
144 | 0 | for (pl = pwl; pl > 0; pl -= 16) |
145 | 0 | PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl)); |
146 | | |
147 | | /* Don't leave anything around in vm they could use. */ |
148 | 0 | ZEND_SECURE_ZERO(final, sizeof(final)); |
149 | | |
150 | | /* Then something really weird... */ |
151 | 0 | for (i = pwl; i != 0; i >>= 1) |
152 | 0 | if ((i & 1) != 0) |
153 | 0 | PHP_MD5Update(&ctx, final, 1); |
154 | 0 | else |
155 | 0 | PHP_MD5Update(&ctx, (const unsigned char *)pw, 1); |
156 | | |
157 | | /* Now make the output string */ |
158 | 0 | memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN); |
159 | 0 | strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1); |
160 | 0 | strcat(passwd, "$"); |
161 | |
|
162 | 0 | PHP_MD5Final(final, &ctx); |
163 | | |
164 | | /* |
165 | | * And now, just to make sure things don't run too fast. On a 60 MHz |
166 | | * Pentium this takes 34 msec, so you would need 30 seconds to build |
167 | | * a 1000 entry dictionary... |
168 | | */ |
169 | 0 | for (i = 0; i < 1000; i++) { |
170 | 0 | PHP_MD5Init(&ctx1); |
171 | |
|
172 | 0 | if ((i & 1) != 0) |
173 | 0 | PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); |
174 | 0 | else |
175 | 0 | PHP_MD5Update(&ctx1, final, 16); |
176 | |
|
177 | 0 | if ((i % 3) != 0) |
178 | 0 | PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl); |
179 | |
|
180 | 0 | if ((i % 7) != 0) |
181 | 0 | PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); |
182 | |
|
183 | 0 | if ((i & 1) != 0) |
184 | 0 | PHP_MD5Update(&ctx1, final, 16); |
185 | 0 | else |
186 | 0 | PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); |
187 | |
|
188 | 0 | PHP_MD5Final(final, &ctx1); |
189 | 0 | } |
190 | |
|
191 | 0 | p = passwd + sl + MD5_MAGIC_LEN + 1; |
192 | |
|
193 | 0 | l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; |
194 | 0 | l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; |
195 | 0 | l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; |
196 | 0 | l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; |
197 | 0 | l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; |
198 | 0 | l = final[11] ; to64(p,l,2); p += 2; |
199 | 0 | *p = '\0'; |
200 | | |
201 | | /* Don't leave anything around in vm they could use. */ |
202 | 0 | ZEND_SECURE_ZERO(final, sizeof(final)); |
203 | 0 | return (passwd); |
204 | 0 | } |