PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/standard/php_crypt_r.c

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