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

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:13 +0000 (18 days ago)

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