PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/standard - php_crypt_r.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 65 65 100.0 %
Date: 2014-07-23 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $Id$ */
       2             : /*
       3             :    +----------------------------------------------------------------------+
       4             :    | PHP Version 5                                                        |
       5             :    +----------------------------------------------------------------------+
       6             :    | Copyright (c) 1997-2013 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       19341 : void php_init_crypt_r()
      67             : {
      68             : #ifdef ZTS
      69             :         php_crypt_extended_init_lock = tsrm_mutex_alloc();
      70             : #endif
      71       19341 : }
      72             : 
      73       19376 : void php_shutdown_crypt_r()
      74             : {
      75             : #ifdef ZTS
      76             :         tsrm_mutex_free(php_crypt_extended_init_lock);
      77             : #endif
      78       19376 : }
      79             : 
      80           8 : 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           8 :         if (!initialized) {
      95             : #ifdef PHP_WIN32
      96             :                 InterlockedIncrement(&initialized);
      97             : #elif defined(HAVE_SYNC_FETCH_AND_ADD)
      98           4 :                 __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           4 :                 _crypt_extended_init();
     104             :         }
     105             : #ifdef ZTS
     106             :         tsrm_mutex_unlock(php_crypt_extended_init_lock);
     107             : #endif
     108           8 : }
     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          60 : to64(char *s, int32_t v, int n)
     119             : {
     120         340 :         while (--n >= 0) {
     121         220 :                 *s++ = itoa64[v & 0x3f];
     122         220 :                 v >>= 6;
     123             :         }
     124          60 : }
     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          10 : 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          10 :         pwl = strlen(pw);
     335             :         
     336             :         /* Refine the salt first */
     337          10 :         sp = salt;
     338             : 
     339             :         /* If it starts with the magic string, then skip that */
     340          10 :         if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0)
     341          10 :                 sp += MD5_MAGIC_LEN;
     342             : 
     343             :         /* It stops at the first '$', max 8 chars */
     344          90 :         for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++)
     345          80 :                 continue;
     346             : 
     347             :         /* get the length of the true salt */
     348          10 :         sl = ep - sp;
     349             : 
     350          10 :         PHP_MD5Init(&ctx);
     351             : 
     352             :         /* The password first, since that is what is most unknown */
     353          10 :         PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl);
     354             : 
     355             :         /* Then our magic string */
     356          10 :         PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN);
     357             : 
     358             :         /* Then the raw salt */
     359          10 :         PHP_MD5Update(&ctx, (const unsigned char *)sp, sl);
     360             : 
     361             :         /* Then just as many characters of the MD5(pw,salt,pw) */
     362          10 :         PHP_MD5Init(&ctx1);
     363          10 :         PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
     364          10 :         PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
     365          10 :         PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
     366          10 :         PHP_MD5Final(final, &ctx1);
     367             : 
     368          20 :         for (pl = pwl; pl > 0; pl -= 16)
     369          10 :                 PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl));
     370             : 
     371             :         /* Don't leave anything around in vm they could use. */
     372          10 :         memset(final, 0, sizeof(final));
     373             : 
     374             :         /* Then something really weird... */
     375          37 :         for (i = pwl; i != 0; i >>= 1)
     376          27 :                 if ((i & 1) != 0)
     377          17 :                     PHP_MD5Update(&ctx, final, 1);
     378             :                 else
     379          10 :                     PHP_MD5Update(&ctx, (const unsigned char *)pw, 1);
     380             : 
     381             :         /* Now make the output string */
     382          10 :         memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN);
     383          10 :         strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1);
     384          10 :         strcat(passwd, "$");
     385             : 
     386          10 :         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       10010 :         for (i = 0; i < 1000; i++) {
     394       10000 :                 PHP_MD5Init(&ctx1);
     395             : 
     396       10000 :                 if ((i & 1) != 0)
     397        5000 :                         PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
     398             :                 else
     399        5000 :                         PHP_MD5Update(&ctx1, final, 16);
     400             : 
     401       10000 :                 if ((i % 3) != 0)
     402        6660 :                         PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl);
     403             : 
     404       10000 :                 if ((i % 7) != 0)
     405        8570 :                         PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
     406             : 
     407       10000 :                 if ((i & 1) != 0)
     408        5000 :                         PHP_MD5Update(&ctx1, final, 16);
     409             :                 else
     410        5000 :                         PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl);
     411             : 
     412       10000 :                 PHP_MD5Final(final, &ctx1);
     413             :         }
     414             : 
     415          10 :         p = passwd + sl + MD5_MAGIC_LEN + 1;
     416             : 
     417          10 :         l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
     418          10 :         l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
     419          10 :         l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
     420          10 :         l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
     421          10 :         l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
     422          10 :         l =                    final[11]                ; to64(p,l,2); p += 2;
     423          10 :         *p = '\0';
     424             : 
     425             :         /* Don't leave anything around in vm they could use. */
     426          10 :         memset(final, 0, sizeof(final));
     427          10 :         return (passwd);
     428             : }
     429             : 
     430             : #undef MD5_MAGIC
     431             : #undef MD5_MAGIC_LEN
     432             : #endif
     433             : 

Generated by: LCOV version 1.10

Generated at Wed, 23 Jul 2014 19:58:40 +0000 (2 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.