PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/zend/php-crypt_r.cpp

https://gitlab.com/iranjith4/hhvm
C++ | 381 lines | 234 code | 76 blank | 71 comment | 70 complexity | 5f1bc9f3d66532cb066656669e4871d7 MD5 | raw file
  1. /* $Id$ */
  2. /*
  3. +----------------------------------------------------------------------+
  4. | PHP Version 7 |
  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. * 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. #ifdef _MSC_VER
  35. #include <Windows.h>
  36. #include <wincrypt.h>
  37. #endif
  38. #include <string.h>
  39. #include <signal.h>
  40. #include "php-crypt_r.h"
  41. #include "crypt-freesec.h"
  42. #include "zend-md5.h"
  43. #include "hphp/util/lock.h"
  44. #include "hphp/util/mutex.h"
  45. namespace HPHP {
  46. void _crypt_extended_init_r() {
  47. static Mutex m;
  48. static volatile bool initialized = 0;
  49. Lock l(m);
  50. if (!initialized) {
  51. initialized = 1;
  52. _crypt_extended_init();
  53. }
  54. }
  55. /* MD% crypt implementation using the windows CryptoApi */
  56. #define MD5_MAGIC "$1$"
  57. #define MD5_MAGIC_LEN 3
  58. static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
  59. "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  60. static void
  61. to64(char *s, int v, int n) {
  62. while (--n >= 0) {
  63. *s++ = itoa64[v & 0x3f];
  64. v >>= 6;
  65. }
  66. }
  67. #ifdef _MSC_VER
  68. char* php_md5_crypt_r(const char *pw, const char *salt, char *out) {
  69. HCRYPTPROV hCryptProv;
  70. HCRYPTHASH ctx, ctx1;
  71. unsigned int i, pwl, sl;
  72. const BYTE magic_md5[4] = "$1$";
  73. const DWORD magic_md5_len = 3;
  74. DWORD dwHashLen;
  75. int pl;
  76. __int32 l;
  77. const char *sp = salt;
  78. const char *ep = salt;
  79. char *p = NULL;
  80. char *passwd = out;
  81. unsigned char final[16];
  82. /* Acquire a cryptographic provider context handle. */
  83. if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
  84. return NULL;
  85. }
  86. pwl = (unsigned int) strlen(pw);
  87. /* Refine the salt first */
  88. sp = salt;
  89. /* If it starts with the magic string, then skip that */
  90. if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0) {
  91. sp += MD5_MAGIC_LEN;
  92. }
  93. /* It stops at the first '$', max 8 chars */
  94. for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++) {
  95. continue;
  96. }
  97. /* get the length of the true salt */
  98. sl = (unsigned int)(ep - sp);
  99. /* Create an empty hash object. */
  100. if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx)) {
  101. goto _destroyProv;
  102. }
  103. /* The password first, since that is what is most unknown */
  104. if(!CryptHashData(ctx, (BYTE *)pw, pwl, 0)) {
  105. goto _destroyCtx0;
  106. }
  107. /* Then our magic string */
  108. if(!CryptHashData(ctx, magic_md5, magic_md5_len, 0)) {
  109. goto _destroyCtx0;
  110. }
  111. /* Then the raw salt */
  112. if(!CryptHashData( ctx, (BYTE *)sp, sl, 0)) {
  113. goto _destroyCtx0;
  114. }
  115. /* MD5(pw,salt,pw), valid. */
  116. /* Then just as many characters of the MD5(pw,salt,pw) */
  117. if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
  118. goto _destroyCtx0;
  119. }
  120. if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
  121. goto _destroyCtx1;
  122. }
  123. if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
  124. goto _destroyCtx1;
  125. }
  126. if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
  127. goto _destroyCtx1;
  128. }
  129. dwHashLen = 16;
  130. CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
  131. /* MD5(pw,salt,pw). Valid. */
  132. for (pl = pwl; pl > 0; pl -= 16) {
  133. CryptHashData(ctx, final, (DWORD)(pl > 16 ? 16 : pl), 0);
  134. }
  135. /* Don't leave anything around in vm they could use. */
  136. RtlSecureZeroMemory(final, sizeof(final));
  137. /* Then something really weird... */
  138. for (i = pwl; i != 0; i >>= 1) {
  139. if ((i & 1) != 0) {
  140. CryptHashData(ctx, (const BYTE *)final, 1, 0);
  141. } else {
  142. CryptHashData(ctx, (const BYTE *)pw, 1, 0);
  143. }
  144. }
  145. memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
  146. if (strncpy_s(passwd + MD5_MAGIC_LEN, MD5_HASH_MAX_LEN - MD5_MAGIC_LEN, sp, sl + 1) != 0) {
  147. goto _destroyCtx1;
  148. }
  149. passwd[MD5_MAGIC_LEN + sl] = '\0';
  150. strcat_s(passwd, MD5_HASH_MAX_LEN, "$");
  151. dwHashLen = 16;
  152. /* Fetch the ctx hash value */
  153. CryptGetHashParam(ctx, HP_HASHVAL, final, &dwHashLen, 0);
  154. for (i = 0; i < 1000; i++) {
  155. if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
  156. goto _destroyCtx1;
  157. }
  158. if ((i & 1) != 0) {
  159. if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
  160. goto _destroyCtx1;
  161. }
  162. } else {
  163. if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
  164. goto _destroyCtx1;
  165. }
  166. }
  167. if ((i % 3) != 0) {
  168. if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
  169. goto _destroyCtx1;
  170. }
  171. }
  172. if ((i % 7) != 0) {
  173. if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
  174. goto _destroyCtx1;
  175. }
  176. }
  177. if ((i & 1) != 0) {
  178. if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
  179. goto _destroyCtx1;
  180. }
  181. } else {
  182. if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
  183. goto _destroyCtx1;
  184. }
  185. }
  186. /* Fetch the ctx hash value */
  187. dwHashLen = 16;
  188. CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
  189. if(!(CryptDestroyHash(ctx1))) {
  190. goto _destroyCtx0;
  191. }
  192. }
  193. ctx1 = (HCRYPTHASH) NULL;
  194. p = passwd + sl + MD5_MAGIC_LEN + 1;
  195. l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
  196. l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
  197. l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
  198. l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
  199. l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
  200. l = final[11]; to64(p,l,2); p += 2;
  201. *p = '\0';
  202. RtlSecureZeroMemory(final, sizeof(final));
  203. _destroyCtx1:
  204. if (ctx1) {
  205. if (!CryptDestroyHash(ctx1)) {
  206. }
  207. }
  208. _destroyCtx0:
  209. CryptDestroyHash(ctx);
  210. _destroyProv:
  211. /* Release the provider handle.*/
  212. if(hCryptProv) {
  213. if(!(CryptReleaseContext(hCryptProv, 0))) {
  214. return NULL;
  215. }
  216. }
  217. return out;
  218. }
  219. #else
  220. /*
  221. * MD5 password encryption.
  222. */
  223. char* php_md5_crypt_r(const char *pw, const char *salt, char *out)
  224. {
  225. static __thread char passwd[MD5_HASH_MAX_LEN], *p;
  226. const char *sp, *ep;
  227. unsigned char final[16];
  228. unsigned int i, sl, pwl;
  229. PHP_MD5_CTX ctx, ctx1;
  230. uint32_t l;
  231. int pl;
  232. pwl = strlen(pw);
  233. /* Refine the salt first */
  234. sp = salt;
  235. /* If it starts with the magic string, then skip that */
  236. if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0)
  237. sp += MD5_MAGIC_LEN;
  238. /* It stops at the first '$', max 8 chars */
  239. for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++)
  240. continue;
  241. /* get the length of the true salt */
  242. sl = ep - sp;
  243. PHP_MD5Init(&ctx);
  244. /* The password first, since that is what is most unknown */
  245. PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl);
  246. /* Then our magic string */
  247. PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN);
  248. /* Then the raw salt */
  249. PHP_MD5Update(&ctx, (const unsigned char *)sp, sl);
  250. /* Then just as many characters of the MD5(pw,salt,pw) */
  251. PHP_MD5Init(&ctx1);
  252. PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
  253. PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
  254. PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
  255. PHP_MD5Final(final, &ctx1);
  256. for (pl = pwl; pl > 0; pl -= 16)
  257. PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl));
  258. /* Don't leave anything around in vm they could use. */
  259. memset(final, 0, sizeof(final));
  260. /* Then something really weird... */
  261. for (i = pwl; i != 0; i >>= 1)
  262. if ((i & 1) != 0)
  263. PHP_MD5Update(&ctx, final, 1);
  264. else
  265. PHP_MD5Update(&ctx, (const unsigned char *)pw, 1);
  266. /* Now make the output string */
  267. memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
  268. strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
  269. strcat(passwd, "$");
  270. PHP_MD5Final(final, &ctx);
  271. /*
  272. * And now, just to make sure things don't run too fast. On a 60 MHz
  273. * Pentium this takes 34 msec, so you would need 30 seconds to build
  274. * a 1000 entry dictionary...
  275. */
  276. for (i = 0; i < 1000; i++) {
  277. PHP_MD5Init(&ctx1);
  278. if ((i & 1) != 0)
  279. PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
  280. else
  281. PHP_MD5Update(&ctx1, final, 16);
  282. if ((i % 3) != 0)
  283. PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
  284. if ((i % 7) != 0)
  285. PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
  286. if ((i & 1) != 0)
  287. PHP_MD5Update(&ctx1, final, 16);
  288. else
  289. PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
  290. PHP_MD5Final(final, &ctx1);
  291. }
  292. p = passwd + sl + MD5_MAGIC_LEN + 1;
  293. l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
  294. l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
  295. l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
  296. l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
  297. l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
  298. l = final[11] ; to64(p,l,2); p += 2;
  299. *p = '\0';
  300. /* Don't leave anything around in vm they could use. */
  301. SECURE_ZERO(final, sizeof(final));
  302. return (passwd);
  303. }
  304. #endif
  305. }