File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard / php_crypt_r.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:57 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /* $Id: php_crypt_r.c,v 1.1.1.4 2014/06/15 20:03:57 misho Exp $ */
    2: /*
    3:    +----------------------------------------------------------------------+
    4:    | PHP Version 5                                                        |
    5:    +----------------------------------------------------------------------+
    6:    | Copyright (c) 1997-2014 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
   58: MUTEX_T php_crypt_extended_init_lock;
   59: #endif
   60: 
   61: /* TODO: enable it when enabling vista/2k8 mode in tsrm */
   62: #if 0
   63: CONDITION_VARIABLE initialized;
   64: #endif
   65: 	
   66: void php_init_crypt_r()
   67: {
   68: #ifdef ZTS
   69: 	php_crypt_extended_init_lock = tsrm_mutex_alloc();
   70: #endif
   71: }
   72: 
   73: void php_shutdown_crypt_r()
   74: {
   75: #ifdef ZTS
   76: 	tsrm_mutex_free(php_crypt_extended_init_lock);
   77: #endif
   78: }
   79: 
   80: void _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: 
  114: static unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
  115: 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  116: 
  117: static void
  118: to64(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
  127: char * 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:  */
  319: char * 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: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>