Annotation of embedaddon/php/ext/standard/php_crypt_r.c, revision 1.1

1.1     ! misho       1: /* $Id: php_crypt_r.c 321634 2012-01-01 13:15:04Z felipe $ */
        !             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: /*
        !            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 _MSC_VER >= 1500
        !           223:        if (strncpy_s(passwd + MD5_MAGIC_LEN, MD5_HASH_MAX_LEN - MD5_MAGIC_LEN, sp, sl + 1) != 0) {
        !           224:                goto _destroyCtx1;
        !           225:        }
        !           226:        passwd[MD5_MAGIC_LEN + sl] = '\0';
        !           227:        strcat_s(passwd, MD5_HASH_MAX_LEN, "$");
        !           228: #else
        !           229:        /* VC6 version doesn't have strcat_s or strncpy_s */
        !           230:        strncpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
        !           231:        strcat(passwd, "$");
        !           232: #endif
        !           233:        dwHashLen = 16;
        !           234: 
        !           235:        /* Fetch the ctx hash value */
        !           236:        CryptGetHashParam(ctx, HP_HASHVAL, final, &dwHashLen, 0);
        !           237: 
        !           238:        for (i = 0; i < 1000; i++) {
        !           239:                if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx1)) {
        !           240:                        goto _destroyCtx1;
        !           241:                }
        !           242: 
        !           243:                if ((i & 1) != 0) {
        !           244:                        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
        !           245:                                goto _destroyCtx1;
        !           246:                        }
        !           247:                } else {
        !           248:                        if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
        !           249:                                goto _destroyCtx1;
        !           250:                        }
        !           251:                }
        !           252: 
        !           253:                if ((i % 3) != 0) {
        !           254:                        if(!CryptHashData(ctx1, (BYTE *)sp, sl, 0)) {
        !           255:                                goto _destroyCtx1;
        !           256:                        }
        !           257:                }
        !           258: 
        !           259:                if ((i % 7) != 0) {
        !           260:                        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
        !           261:                                goto _destroyCtx1;
        !           262:                        }
        !           263:                }
        !           264: 
        !           265:                if ((i & 1) != 0) {
        !           266:                        if(!CryptHashData(ctx1, (BYTE *)final, 16, 0)) {
        !           267:                                goto _destroyCtx1;
        !           268:                        }
        !           269:                } else {
        !           270:                        if(!CryptHashData(ctx1, (BYTE *)pw, pwl, 0)) {
        !           271:                                goto _destroyCtx1;
        !           272:                        }
        !           273:                }
        !           274: 
        !           275:                /* Fetch the ctx hash value */
        !           276:                dwHashLen = 16;
        !           277:                CryptGetHashParam(ctx1, HP_HASHVAL, final, &dwHashLen, 0);
        !           278:                if(!(CryptDestroyHash(ctx1))) {
        !           279:                        goto _destroyCtx0;
        !           280:                }
        !           281:        }
        !           282: 
        !           283:        ctx1 = (HCRYPTHASH) NULL;
        !           284: 
        !           285:        p = passwd + sl + MD5_MAGIC_LEN + 1;
        !           286: 
        !           287:        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
        !           288:        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
        !           289:        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
        !           290:        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
        !           291:        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
        !           292:        l = final[11]; to64(p,l,2); p += 2;
        !           293: 
        !           294:        *p = '\0';
        !           295: 
        !           296:        memset(final, 0, sizeof(final));
        !           297: 
        !           298: 
        !           299: _destroyCtx1:
        !           300:        if (ctx1) {
        !           301:                if (!CryptDestroyHash(ctx1)) {
        !           302:                        
        !           303:                }
        !           304:        }
        !           305: 
        !           306: _destroyCtx0:
        !           307:        CryptDestroyHash(ctx);
        !           308: 
        !           309: _destroyProv:
        !           310:        /* Release the provider handle.*/
        !           311:        if(hCryptProv) {
        !           312:                if(!(CryptReleaseContext(hCryptProv, 0))) {
        !           313:                        return NULL;
        !           314:                }
        !           315:        }
        !           316: 
        !           317:        return out;
        !           318: }
        !           319: #else
        !           320: 
        !           321: /*
        !           322:  * MD5 password encryption.
        !           323:  */
        !           324: char * php_md5_crypt_r(const char *pw, const char *salt, char *out)
        !           325: {
        !           326:        static char passwd[MD5_HASH_MAX_LEN], *p;
        !           327:        const char *sp, *ep;
        !           328:        unsigned char final[16];
        !           329:        unsigned int i, sl, pwl;
        !           330:        PHP_MD5_CTX     ctx, ctx1;
        !           331:        php_uint32 l;
        !           332:        int pl;
        !           333:        
        !           334:        pwl = strlen(pw);
        !           335:        
        !           336:        /* Refine the salt first */
        !           337:        sp = salt;
        !           338: 
        !           339:        /* If it starts with the magic string, then skip that */
        !           340:        if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0)
        !           341:                sp += MD5_MAGIC_LEN;
        !           342: 
        !           343:        /* It stops at the first '$', max 8 chars */
        !           344:        for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++)
        !           345:                continue;
        !           346: 
        !           347:        /* get the length of the true salt */
        !           348:        sl = ep - sp;
        !           349: 
        !           350:        PHP_MD5Init(&ctx);
        !           351: 
        !           352:        /* The password first, since that is what is most unknown */
        !           353:        PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl);
        !           354: 
        !           355:        /* Then our magic string */
        !           356:        PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN);
        !           357: 
        !           358:        /* Then the raw salt */
        !           359:        PHP_MD5Update(&ctx, (const unsigned char *)sp, sl);
        !           360: 
        !           361:        /* Then just as many characters of the MD5(pw,salt,pw) */
        !           362:        PHP_MD5Init(&ctx1);
        !           363:        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
        !           364:        PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
        !           365:        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
        !           366:        PHP_MD5Final(final, &ctx1);
        !           367: 
        !           368:        for (pl = pwl; pl > 0; pl -= 16)
        !           369:                PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl));
        !           370: 
        !           371:        /* Don't leave anything around in vm they could use. */
        !           372:        memset(final, 0, sizeof(final));
        !           373: 
        !           374:        /* Then something really weird... */
        !           375:        for (i = pwl; i != 0; i >>= 1)
        !           376:                if ((i & 1) != 0)
        !           377:                    PHP_MD5Update(&ctx, final, 1);
        !           378:                else
        !           379:                    PHP_MD5Update(&ctx, (const unsigned char *)pw, 1);
        !           380: 
        !           381:        /* Now make the output string */
        !           382:        memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
        !           383:        strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
        !           384:        strcat(passwd, "$");
        !           385: 
        !           386:        PHP_MD5Final(final, &ctx);
        !           387: 
        !           388:        /*
        !           389:         * And now, just to make sure things don't run too fast. On a 60 MHz
        !           390:         * Pentium this takes 34 msec, so you would need 30 seconds to build
        !           391:         * a 1000 entry dictionary...
        !           392:         */
        !           393:        for (i = 0; i < 1000; i++) {
        !           394:                PHP_MD5Init(&ctx1);
        !           395: 
        !           396:                if ((i & 1) != 0)
        !           397:                        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
        !           398:                else
        !           399:                        PHP_MD5Update(&ctx1, final, 16);
        !           400: 
        !           401:                if ((i % 3) != 0)
        !           402:                        PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
        !           403: 
        !           404:                if ((i % 7) != 0)
        !           405:                        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
        !           406: 
        !           407:                if ((i & 1) != 0)
        !           408:                        PHP_MD5Update(&ctx1, final, 16);
        !           409:                else
        !           410:                        PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
        !           411: 
        !           412:                PHP_MD5Final(final, &ctx1);
        !           413:        }
        !           414: 
        !           415:        p = passwd + sl + MD5_MAGIC_LEN + 1;
        !           416: 
        !           417:        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
        !           418:        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
        !           419:        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
        !           420:        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
        !           421:        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
        !           422:        l =                    final[11]                ; to64(p,l,2); p += 2;
        !           423:        *p = '\0';
        !           424: 
        !           425:        /* Don't leave anything around in vm they could use. */
        !           426:        memset(final, 0, sizeof(final));
        !           427:        return (passwd);
        !           428: }
        !           429: 
        !           430: #undef MD5_MAGIC
        !           431: #undef MD5_MAGIC_LEN
        !           432: #endif
        !           433: 

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