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 - password.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 137 161 85.1 %
Date: 2016-09-27 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2016 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Anthony Ferrara <ircmaxell@php.net>                         |
      16             :    |          Charles R. Portwood II <charlesportwoodii@erianna.com>      |
      17             :    +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : #include <stdlib.h>
      23             : 
      24             : #include "php.h"
      25             : 
      26             : #include "fcntl.h"
      27             : #include "php_password.h"
      28             : #include "php_rand.h"
      29             : #include "php_crypt.h"
      30             : #include "base64.h"
      31             : #include "zend_interfaces.h"
      32             : #include "info.h"
      33             : #include "php_random.h"
      34             : #if HAVE_ARGON2LIB
      35             : #include "argon2.h"
      36             : #endif
      37             : 
      38             : #if PHP_WIN32
      39             : #include "win32/winutil.h"
      40             : #endif
      41             : 
      42       23950 : PHP_MINIT_FUNCTION(password) /* {{{ */
      43             : {
      44       23950 :         REGISTER_LONG_CONSTANT("PASSWORD_DEFAULT", PHP_PASSWORD_DEFAULT, CONST_CS | CONST_PERSISTENT);
      45       23950 :         REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT", PHP_PASSWORD_BCRYPT, CONST_CS | CONST_PERSISTENT);
      46             : #if HAVE_ARGON2LIB
      47             :         REGISTER_LONG_CONSTANT("PASSWORD_ARGON2I", PHP_PASSWORD_ARGON2I, CONST_CS | CONST_PERSISTENT);
      48             : #endif
      49             : 
      50       23950 :         REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_CS | CONST_PERSISTENT);
      51             : #if HAVE_ARGON2LIB
      52             :         REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_MEMORY_COST", PHP_PASSWORD_ARGON2_MEMORY_COST, CONST_CS | CONST_PERSISTENT);
      53             :         REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_TIME_COST", PHP_PASSWORD_ARGON2_TIME_COST, CONST_CS | CONST_PERSISTENT);
      54             :         REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_THREADS", PHP_PASSWORD_ARGON2_THREADS, CONST_CS | CONST_PERSISTENT);
      55             : #endif
      56             : 
      57       23950 :         return SUCCESS;
      58             : }
      59             : /* }}} */
      60             : 
      61           4 : static char* php_password_get_algo_name(const php_password_algo algo)
      62             : {
      63           4 :         switch (algo) {
      64             :                 case PHP_PASSWORD_BCRYPT:
      65           2 :                         return "bcrypt";
      66             : #if HAVE_ARGON2LIB
      67             :                 case PHP_PASSWORD_ARGON2I:
      68             :                         return "argon2i";
      69             : #endif
      70             :                 case PHP_PASSWORD_UNKNOWN:
      71             :                 default:
      72           2 :                         return "unknown";
      73             :         }
      74             : }
      75             : 
      76          19 : static php_password_algo php_password_determine_algo(const char *hash, const size_t len)
      77             : {
      78          19 :         if (len > 3 && hash[0] == '$' && hash[1] == '2' && hash[2] == 'y' && len == 60) {
      79           8 :                 return PHP_PASSWORD_BCRYPT;
      80             :         } 
      81             : #if HAVE_ARGON2LIB
      82             :         if (len >= sizeof("$argon2i$")-1 && !memcmp(hash, "$argon2i$", sizeof("$argon2i$")-1)) {
      83             :         return PHP_PASSWORD_ARGON2I;
      84             :         }
      85             : #endif
      86             : 
      87          11 :         return PHP_PASSWORD_UNKNOWN;
      88             : }
      89             : 
      90           2 : static int php_password_salt_is_alphabet(const char *str, const size_t len) /* {{{ */
      91             : {
      92           2 :         size_t i = 0;
      93             : 
      94          48 :         for (i = 0; i < len; i++) {
      95          47 :                 if (!((str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= 'a' && str[i] <= 'z') || (str[i] >= '0' && str[i] <= '9') || str[i] == '.' || str[i] == '/')) {
      96           1 :                         return FAILURE;
      97             :                 }
      98             :         }
      99           1 :         return SUCCESS;
     100             : }
     101             : /* }}} */
     102             : 
     103           3 : static int php_password_salt_to64(const char *str, const size_t str_len, const size_t out_len, char *ret) /* {{{ */
     104             : {
     105           3 :         size_t pos = 0;
     106             :         zend_string *buffer;
     107           3 :         if ((int) str_len < 0) {
     108           0 :                 return FAILURE;
     109             :         }
     110           3 :         buffer = php_base64_encode((unsigned char*) str, str_len);
     111           3 :         if (ZSTR_LEN(buffer) < out_len) {
     112             :                 /* Too short of an encoded string generated */
     113             :                 zend_string_release(buffer);
     114           0 :                 return FAILURE;
     115             :         }
     116          69 :         for (pos = 0; pos < out_len; pos++) {
     117          66 :                 if (ZSTR_VAL(buffer)[pos] == '+') {
     118           0 :                         ret[pos] = '.';
     119          66 :                 } else if (ZSTR_VAL(buffer)[pos] == '=') {
     120             :                         zend_string_free(buffer);
     121           0 :                         return FAILURE;
     122             :                 } else {
     123          66 :                         ret[pos] = ZSTR_VAL(buffer)[pos];
     124             :                 }
     125             :         }
     126             :         zend_string_free(buffer);
     127           3 :         return SUCCESS;
     128             : }
     129             : /* }}} */
     130             : 
     131           2 : static int php_password_make_salt(size_t length, char *ret) /* {{{ */
     132             : {
     133             :         size_t raw_length;
     134             :         char *buffer;
     135             :         char *result;
     136             : 
     137           2 :         if (length > (INT_MAX / 3)) {
     138           0 :                 php_error_docref(NULL, E_WARNING, "Length is too large to safely generate");
     139           0 :                 return FAILURE;
     140             :         }
     141             : 
     142           2 :         raw_length = length * 3 / 4 + 1;
     143             : 
     144           2 :         buffer = (char *) safe_emalloc(raw_length, 1, 1);
     145             : 
     146           2 :         if (FAILURE == php_random_bytes_silent(buffer, raw_length)) {
     147           0 :                 php_error_docref(NULL, E_WARNING, "Unable to generate salt");
     148           0 :                 efree(buffer);
     149           0 :                 return FAILURE;
     150             :         }
     151             : 
     152           2 :         result = safe_emalloc(length, 1, 1);
     153           2 :         if (php_password_salt_to64(buffer, raw_length, length, result) == FAILURE) {
     154           0 :                 php_error_docref(NULL, E_WARNING, "Generated salt too short");
     155           0 :                 efree(buffer);
     156           0 :                 efree(result);
     157           0 :                 return FAILURE;
     158             :         }
     159           2 :         memcpy(ret, result, length);
     160           2 :         efree(result);
     161           2 :         efree(buffer);
     162           2 :         ret[length] = 0;
     163           2 :         return SUCCESS;
     164             : }
     165             : /* }}} */
     166             : 
     167             : /* {{{ proto array password_get_info(string $hash)
     168             : Retrieves information about a given hash */
     169           6 : PHP_FUNCTION(password_get_info)
     170             : {
     171             :         php_password_algo algo;
     172             :         size_t hash_len;
     173             :         char *hash, *algo_name;
     174             :         zval options;
     175             : 
     176           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &hash, &hash_len) == FAILURE) {
     177           2 :                 return;
     178             :         }
     179             : 
     180           4 :         array_init(&options);
     181             : 
     182           4 :         algo = php_password_determine_algo(hash, (size_t) hash_len);
     183           4 :         algo_name = php_password_get_algo_name(algo);
     184             : 
     185           4 :         switch (algo) {
     186             :                 case PHP_PASSWORD_BCRYPT:
     187             :                         {
     188           2 :                                 zend_long cost = PHP_PASSWORD_BCRYPT_COST;
     189           2 :                                 sscanf(hash, "$2y$" ZEND_LONG_FMT "$", &cost);
     190           2 :                                 add_assoc_long(&options, "cost", cost);
     191             :                         }
     192             :                         break;
     193             : #if HAVE_ARGON2LIB
     194             :                 case PHP_PASSWORD_ARGON2I:
     195             :                         {
     196             :                                 zend_long v = 0;
     197             :                                 zend_long memory_cost = PHP_PASSWORD_ARGON2_MEMORY_COST;
     198             :                                 zend_long time_cost = PHP_PASSWORD_ARGON2_TIME_COST;
     199             :                                 zend_long threads = PHP_PASSWORD_ARGON2_THREADS;
     200             : 
     201             :                                 sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &memory_cost, &time_cost, &threads);
     202             :                                 add_assoc_long(&options, "memory_cost", memory_cost);
     203             :                                 add_assoc_long(&options, "time_cost", time_cost);
     204             :                                 add_assoc_long(&options, "threads", threads);
     205             :                         }
     206             :                         break;
     207             : #endif
     208             :                 case PHP_PASSWORD_UNKNOWN:
     209             :                 default:
     210             :                         break;
     211             :         }
     212             : 
     213           4 :         array_init(return_value);
     214             : 
     215           4 :         add_assoc_long(return_value, "algo", algo);
     216           4 :         add_assoc_string(return_value, "algoName", algo_name);
     217           4 :         add_assoc_zval(return_value, "options", &options);
     218             : }
     219             : /** }}} */
     220             : 
     221             : /* {{{ proto boolean password_needs_rehash(string $hash, integer $algo[, array $options])
     222             : Determines if a given hash requires re-hashing based upon parameters */
     223          13 : PHP_FUNCTION(password_needs_rehash)
     224             : {
     225          13 :         zend_long new_algo = 0;
     226             :         php_password_algo algo;
     227             :         size_t hash_len;
     228             :         char *hash;
     229          13 :         HashTable *options = 0;
     230             :         zval *option_buffer;
     231             : 
     232          13 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|H", &hash, &hash_len, &new_algo, &options) == FAILURE) {
     233           5 :                 return;
     234             :         }
     235             : 
     236           8 :         algo = php_password_determine_algo(hash, (size_t) hash_len);
     237             : 
     238           8 :         if ((zend_long)algo != new_algo) {
     239           1 :                 RETURN_TRUE;
     240             :         }
     241             : 
     242           7 :         switch (algo) {
     243             :                 case PHP_PASSWORD_BCRYPT:
     244             :                         {
     245           6 :                                 zend_long new_cost = PHP_PASSWORD_BCRYPT_COST, cost = 0;
     246             : 
     247           6 :                                 if (options && (option_buffer = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) {
     248           5 :                                         new_cost = zval_get_long(option_buffer);
     249             :                                 }
     250             : 
     251           6 :                                 sscanf(hash, "$2y$" ZEND_LONG_FMT "$", &cost);
     252           6 :                                 if (cost != new_cost) {
     253           3 :                                         RETURN_TRUE;
     254             :                                 }
     255             :                         }
     256             :                         break;
     257             : #if HAVE_ARGON2LIB
     258             :                 case PHP_PASSWORD_ARGON2I:
     259             :                         {
     260             :                                 zend_long v = 0;
     261             :                                 zend_long new_memory_cost = PHP_PASSWORD_ARGON2_MEMORY_COST, memory_cost = 0;
     262             :                                 zend_long new_time_cost = PHP_PASSWORD_ARGON2_TIME_COST, time_cost = 0;
     263             :                                 zend_long new_threads = PHP_PASSWORD_ARGON2_THREADS, threads = 0;
     264             : 
     265             :                                 if (options && (option_buffer = zend_hash_str_find(options, "memory_cost", sizeof("memory_cost")-1)) != NULL) {
     266             :                                         new_memory_cost = zval_get_long(option_buffer);
     267             :                                 }
     268             : 
     269             :                                 if (options && (option_buffer = zend_hash_str_find(options, "time_cost", sizeof("time_cost")-1)) != NULL) {
     270             :                                         new_time_cost = zval_get_long(option_buffer);
     271             :                                 }
     272             : 
     273             :                                 if (options && (option_buffer = zend_hash_str_find(options, "threads", sizeof("threads")-1)) != NULL) {
     274             :                                         new_threads = zval_get_long(option_buffer);
     275             :                                 }
     276             : 
     277             :                                 sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &memory_cost, &time_cost, &threads);
     278             : 
     279             :                                 if (new_time_cost != time_cost || new_memory_cost != memory_cost || new_threads != threads) {
     280             :                                         RETURN_TRUE;
     281             :                                 }
     282             :                         }
     283             :                         break;
     284             : #endif
     285             :                 case PHP_PASSWORD_UNKNOWN:
     286             :                 default:
     287             :                         break;
     288             :         }
     289           4 :         RETURN_FALSE;
     290             : }
     291             : /* }}} */
     292             : 
     293             : /* {{{ proto boolean password_verify(string password, string hash)
     294             : Verify a hash created using crypt() or password_hash() */
     295           9 : PHP_FUNCTION(password_verify)
     296             : {
     297           9 :         int status = 0;
     298             :         size_t i, password_len, hash_len;
     299             :         char *password, *hash;
     300             :         zend_string *ret;
     301             :         php_password_algo algo;
     302             : 
     303           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &password, &password_len, &hash, &hash_len) == FAILURE) {
     304           2 :                 RETURN_FALSE;
     305             :         }
     306             : 
     307           7 :         algo = php_password_determine_algo(hash, (size_t) hash_len);
     308             : 
     309             :         switch(algo) {
     310             : #if HAVE_ARGON2LIB
     311             :                 case PHP_PASSWORD_ARGON2I:
     312             :                         {
     313             :                                 argon2_type type = Argon2_i;
     314             : 
     315             :                                 status = argon2_verify(hash, password, password_len, type);
     316             :                                 
     317             :                                 if (status == ARGON2_OK) {
     318             :                                         RETURN_TRUE;
     319             :                                 }
     320             : 
     321             :                                 RETURN_FALSE;
     322             :                         }
     323             :                         break;
     324             : #endif
     325             :                 case PHP_PASSWORD_BCRYPT:
     326             :                 case PHP_PASSWORD_UNKNOWN:
     327             :                 default:
     328             :                         {
     329           7 :                                 if ((ret = php_crypt(password, (int)password_len, hash, (int)hash_len, 1)) == NULL) {
     330           1 :                                         RETURN_FALSE;
     331             :                                 }
     332             : 
     333           6 :                                 if (ZSTR_LEN(ret) != hash_len || hash_len < 13) {
     334             :                                         zend_string_free(ret);
     335           3 :                                         RETURN_FALSE;
     336             :                                 }
     337             : 
     338             :                                 /* We're using this method instead of == in order to provide
     339             :                                 * resistance towards timing attacks. This is a constant time
     340             :                                 * equality check that will always check every byte of both
     341             :                                 * values. */
     342         136 :                                 for (i = 0; i < hash_len; i++) {
     343         133 :                                         status |= (ZSTR_VAL(ret)[i] ^ hash[i]);
     344             :                                 }
     345             : 
     346             :                                 zend_string_free(ret);
     347             : 
     348           3 :                                 RETURN_BOOL(status == 0);
     349             :                         }
     350             :         }
     351             : 
     352             :         RETURN_FALSE;
     353             : }
     354             : /* }}} */
     355             : 
     356             : /* {{{ proto string password_hash(string password, int algo[, array options = array()])
     357             : Hash a password */
     358          18 : PHP_FUNCTION(password_hash)
     359             : {
     360             :         char hash_format[8], *hash, *salt, *password;
     361          18 :         zend_long algo = 0;
     362          18 :         size_t password_len = 0;
     363             :         int hash_len;
     364          18 :         size_t salt_len = 0, required_salt_len = 0, hash_format_len;
     365          18 :         HashTable *options = 0;
     366             :         zval *option_buffer;
     367             : 
     368             : #if HAVE_ARGON2LIB
     369             :         size_t time_cost = PHP_PASSWORD_ARGON2_TIME_COST; 
     370             :         size_t memory_cost = PHP_PASSWORD_ARGON2_MEMORY_COST;
     371             :         size_t threads = PHP_PASSWORD_ARGON2_THREADS;
     372             :         argon2_type type = Argon2_i;
     373             : #endif
     374             : 
     375          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|H", &password, &password_len, &algo, &options) == FAILURE) {
     376           5 :                 return;
     377             :         }
     378             : 
     379          13 :         switch (algo) {
     380             :                 case PHP_PASSWORD_BCRYPT:
     381             :                         {
     382          12 :                                 zend_long cost = PHP_PASSWORD_BCRYPT_COST;
     383             : 
     384          12 :                                 if (options && (option_buffer = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) {
     385           4 :                                         cost = zval_get_long(option_buffer);
     386             :                                 }
     387             : 
     388          12 :                                 if (cost < 4 || cost > 31) {
     389           3 :                                         php_error_docref(NULL, E_WARNING, "Invalid bcrypt cost parameter specified: " ZEND_LONG_FMT, cost);
     390           3 :                                         RETURN_NULL();
     391             :                                 }
     392             : 
     393           9 :                                 required_salt_len = 22;
     394           9 :                                 sprintf(hash_format, "$2y$%02ld$", (long) cost);
     395           9 :                                 hash_format_len = 7;
     396             :                         }
     397           9 :                         break;
     398             : #if HAVE_ARGON2LIB
     399             :                 case PHP_PASSWORD_ARGON2I:
     400             :                         {
     401             :                                 if (options && (option_buffer = zend_hash_str_find(options, "memory_cost", sizeof("memory_cost")-1)) != NULL) {
     402             :                                         memory_cost = zval_get_long(option_buffer);
     403             :                                 }
     404             : 
     405             :                                 if (memory_cost > ARGON2_MAX_MEMORY || memory_cost < ARGON2_MIN_MEMORY) {
     406             :                                         php_error_docref(NULL, E_WARNING, "Memory cost is outside of allowed memory range", memory_cost);
     407             :                                         RETURN_NULL();
     408             :                                 }
     409             : 
     410             :                                 if (options && (option_buffer = zend_hash_str_find(options, "time_cost", sizeof("time_cost")-1)) != NULL) {
     411             :                                         time_cost = zval_get_long(option_buffer);
     412             :                                 }
     413             : 
     414             :                                 if (time_cost > ARGON2_MAX_TIME || time_cost < ARGON2_MIN_TIME) {
     415             :                                         php_error_docref(NULL, E_WARNING, "Time cost is outside of allowed time range", time_cost);
     416             :                                         RETURN_NULL();
     417             :                                 }
     418             :                                 
     419             :                                 if (options && (option_buffer = zend_hash_str_find(options, "threads", sizeof("threads")-1)) != NULL) {
     420             :                                         threads = zval_get_long(option_buffer);
     421             :                                 }
     422             : 
     423             :                                 if (threads > ARGON2_MAX_LANES || threads == 0) {
     424             :                                         php_error_docref(NULL, E_WARNING, "Invalid number of threads", threads);
     425             :                                         RETURN_NULL();
     426             :                                 }
     427             : 
     428             :                                 required_salt_len = 16;
     429             :                         }
     430             :                         break;
     431             : #endif
     432             :                 case PHP_PASSWORD_UNKNOWN:
     433             :                 default:
     434           1 :                         php_error_docref(NULL, E_WARNING, "Unknown password hashing algorithm: " ZEND_LONG_FMT, algo);
     435           1 :                         RETURN_NULL();
     436             :         }
     437             : 
     438          11 :         if (options && (option_buffer = zend_hash_str_find(options, "salt", sizeof("salt")-1)) != NULL) {
     439             :                 zend_string *buffer;
     440             : 
     441           7 :                 php_error_docref(NULL, E_DEPRECATED, "Use of the 'salt' option to password_hash is deprecated");
     442             : 
     443           7 :                 switch (Z_TYPE_P(option_buffer)) {
     444             :                         case IS_STRING:
     445           8 :                                 buffer = zend_string_copy(Z_STR_P(option_buffer));
     446           4 :                                 break;
     447             :                         case IS_LONG:
     448             :                         case IS_DOUBLE:
     449             :                         case IS_OBJECT:
     450           2 :                                 buffer = zval_get_string(option_buffer);
     451           2 :                                 break;
     452             :                         case IS_FALSE:
     453             :                         case IS_TRUE:
     454             :                         case IS_NULL:
     455             :                         case IS_RESOURCE:
     456             :                         case IS_ARRAY:
     457             :                         default:
     458           1 :                                 php_error_docref(NULL, E_WARNING, "Non-string salt parameter supplied");
     459           1 :                                 RETURN_NULL();
     460             :                 }
     461             : 
     462             :                 /* XXX all the crypt related APIs work with int for string length.
     463             :                         That should be revised for size_t and then we maybe don't require
     464             :                         the > INT_MAX check. */
     465           6 :                 if (ZSTR_LEN(buffer) > INT_MAX) {
     466           0 :                         php_error_docref(NULL, E_WARNING, "Supplied salt is too long");
     467           0 :                         RETURN_NULL();
     468           6 :                 } else if (ZSTR_LEN(buffer) < required_salt_len) {
     469           4 :                         php_error_docref(NULL, E_WARNING, "Provided salt is too short: %zd expecting %zd", ZSTR_LEN(buffer), required_salt_len);
     470             :                         zend_string_release(buffer);
     471           4 :                         RETURN_NULL();
     472           2 :                 } else if (php_password_salt_is_alphabet(ZSTR_VAL(buffer), ZSTR_LEN(buffer)) == FAILURE) {
     473           1 :                         salt = safe_emalloc(required_salt_len, 1, 1);
     474           1 :                         if (php_password_salt_to64(ZSTR_VAL(buffer), ZSTR_LEN(buffer), required_salt_len, salt) == FAILURE) {
     475           0 :                                 efree(salt);
     476           0 :                                 php_error_docref(NULL, E_WARNING, "Provided salt is too short: %zd", ZSTR_LEN(buffer));
     477             :                                 zend_string_release(buffer);
     478           0 :                                 RETURN_NULL();
     479             :                         }
     480           1 :                         salt_len = required_salt_len;
     481             :                 } else {
     482           1 :                         salt = safe_emalloc(required_salt_len, 1, 1);
     483           1 :                         memcpy(salt, ZSTR_VAL(buffer), required_salt_len);
     484           1 :                         salt_len = required_salt_len;
     485             :                 }
     486             :                 zend_string_release(buffer);
     487             :         } else {
     488           2 :                 salt = safe_emalloc(required_salt_len, 1, 1);
     489           2 :                 if (php_password_make_salt(required_salt_len, salt) == FAILURE) {
     490           0 :                         efree(salt);
     491           0 :                         RETURN_FALSE;
     492             :                 }
     493           2 :                 salt_len = required_salt_len;
     494             :         }
     495             : 
     496           4 :         switch (algo) {
     497             :                 case PHP_PASSWORD_BCRYPT:
     498             :                         {
     499             :                                 zend_string *result;
     500           4 :                                 salt[salt_len] = 0;
     501             : 
     502           4 :                                 hash = safe_emalloc(salt_len + hash_format_len, 1, 1);
     503           4 :                                 sprintf(hash, "%s%s", hash_format, salt);
     504           4 :                                 hash[hash_format_len + salt_len] = 0;
     505             : 
     506           4 :                                 efree(salt);
     507             : 
     508             :                                 /* This cast is safe, since both values are defined here in code and cannot overflow */
     509           4 :                                 hash_len = (int) (hash_format_len + salt_len);
     510             : 
     511           4 :                                 if ((result = php_crypt(password, (int)password_len, hash, hash_len, 1)) == NULL) {
     512           0 :                                         efree(hash);
     513           0 :                                         RETURN_FALSE;
     514             :                                 }
     515             : 
     516           4 :                                 efree(hash);
     517             : 
     518           4 :                                 if (ZSTR_LEN(result) < 13) {
     519             :                                         zend_string_free(result);
     520           0 :                                         RETURN_FALSE;
     521             :                                 }
     522             : 
     523           4 :                                 RETURN_STR(result);
     524             :                         }
     525             :                         break;
     526             : #if HAVE_ARGON2LIB
     527             :                 case PHP_PASSWORD_ARGON2I:
     528             :                         {
     529             :                                 size_t out_len = 32;
     530             :                                 size_t encoded_len;
     531             :                                 int status = 0;
     532             :                                 char *out;
     533             :                                 zend_string *encoded;
     534             : 
     535             :                                 encoded_len = argon2_encodedlen(
     536             :                                         time_cost,
     537             :                                         memory_cost,
     538             :                                         threads,
     539             :                                         (uint32_t)salt_len,
     540             :                                         out_len
     541             :                                 );
     542             : 
     543             :                                 out = emalloc(out_len + 1);
     544             :                                 encoded = zend_string_alloc(encoded_len, 0);
     545             : 
     546             :                                 status = argon2_hash(
     547             :                                         time_cost,
     548             :                                         memory_cost,
     549             :                                         threads,
     550             :                                         password,
     551             :                                         password_len,
     552             :                                         salt,
     553             :                                         salt_len,
     554             :                                         out,
     555             :                                         out_len,
     556             :                                         ZSTR_VAL(encoded),
     557             :                                         encoded_len,
     558             :                                         type,
     559             :                                         ARGON2_VERSION_NUMBER
     560             :                                 );
     561             : 
     562             :                                 efree(out);
     563             :                                 efree(salt);
     564             : 
     565             :                                 if (status != ARGON2_OK) {
     566             :                                         zend_string_free(encoded);
     567             :                                         php_error_docref(NULL, E_WARNING, argon2_error_message(status));
     568             :                                         RETURN_FALSE;
     569             :                                 }
     570             :                                         
     571             :                                 RETURN_STR(encoded);
     572             :                         }
     573             :                         break;
     574             : #endif
     575             :                 default:
     576           0 :                         RETURN_FALSE;
     577             :         }
     578             : }
     579             : /* }}} */
     580             : 
     581             : /*
     582             :  * Local variables:
     583             :  * tab-width: 4
     584             :  * c-basic-offset: 4
     585             :  * End:
     586             :  * vim600: sw=4 ts=4 fdm=marker
     587             :  * vim<600: sw=4 ts=4
     588             :  */

Generated by: LCOV version 1.10

Generated at Tue, 27 Sep 2016 10:26:08 +0000 (2 days ago)

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