Back to index

php5  5.3.10
hash.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: Sara Golemon <pollita@php.net>                               |
00016   |         Scott MacVicar <scottmac@php.net>                            |
00017   +----------------------------------------------------------------------+
00018 */
00019 
00020 /* $Id: hash.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif
00025 
00026 #include "php_hash.h"
00027 #include "ext/standard/info.h"
00028 #include "ext/standard/file.h"
00029 
00030 static int php_hash_le_hash;
00031 HashTable php_hash_hashtable;
00032 
00033 #if (PHP_MAJOR_VERSION >= 5)
00034 # define DEFAULT_CONTEXT FG(default_context)
00035 #else
00036 # define DEFAULT_CONTEXT NULL
00037 #endif
00038 
00039 #ifdef PHP_MHASH_BC
00040 struct mhash_bc_entry {
00041        char *mhash_name;
00042        char *hash_name;
00043        int value;
00044 };
00045 
00046 #define MHASH_NUM_ALGOS 29
00047 
00048 static struct mhash_bc_entry mhash_to_hash[MHASH_NUM_ALGOS] = {
00049        {"CRC32", "crc32", 0},
00050        {"MD5", "md5", 1},
00051        {"SHA1", "sha1", 2},
00052        {"HAVAL256", "haval256,3", 3},
00053        {NULL, NULL, 4},
00054        {"RIPEMD160", "ripemd160", 5},
00055        {NULL, NULL, 6},
00056        {"TIGER", "tiger192,3", 7},
00057        {"GOST", "gost", 8},
00058        {"CRC32B", "crc32b", 9},
00059        {"HAVAL224", "haval224,3", 10},
00060        {"HAVAL192", "haval192,3", 11},
00061        {"HAVAL160", "haval160,3", 12},
00062        {"HAVAL128", "haval128,3", 13},
00063        {"TIGER128", "tiger128,3", 14},
00064        {"TIGER160", "tiger160,3", 15},
00065        {"MD4", "md4", 16},
00066        {"SHA256", "sha256", 17},
00067        {"ADLER32", "adler32", 18},
00068        {"SHA224", "sha224", 19},
00069        {"SHA512", "sha512", 20},
00070        {"SHA384", "sha384", 21},
00071        {"WHIRLPOOL", "whirlpool", 22},
00072        {"RIPEMD128", "ripemd128", 23},
00073        {"RIPEMD256", "ripemd256", 24},
00074        {"RIPEMD320", "ripemd320", 25},
00075        {NULL, NULL, 26}, /* support needs to be added for snefru 128 */
00076        {"SNEFRU256", "snefru256", 27},
00077        {"MD2", "md2", 28}
00078 };
00079 #endif
00080 
00081 /* Hash Registry Access */
00082 
00083 PHP_HASH_API const php_hash_ops *php_hash_fetch_ops(const char *algo, int algo_len) /* {{{ */
00084 {
00085        php_hash_ops *ops;
00086        char *lower = estrndup(algo, algo_len);
00087 
00088        zend_str_tolower(lower, algo_len);
00089        if (SUCCESS != zend_hash_find(&php_hash_hashtable, lower, algo_len + 1, (void*)&ops)) {
00090               ops = NULL;
00091        }
00092        efree(lower);
00093 
00094        return ops;
00095 }
00096 /* }}} */
00097 
00098 PHP_HASH_API void php_hash_register_algo(const char *algo, const php_hash_ops *ops) /* {{{ */
00099 {
00100        int algo_len = strlen(algo);
00101        char *lower = estrndup(algo, algo_len);
00102        
00103        zend_str_tolower(lower, algo_len);
00104        zend_hash_add(&php_hash_hashtable, lower, algo_len + 1, (void*)ops, sizeof(php_hash_ops), NULL);
00105        efree(lower);
00106 }
00107 /* }}} */
00108 
00109 PHP_HASH_API int php_hash_copy(const void *ops, void *orig_context, void *dest_context) /* {{{ */
00110 {
00111        php_hash_ops *hash_ops = (php_hash_ops *)ops;
00112 
00113        memcpy(dest_context, orig_context, hash_ops->context_size);
00114        return SUCCESS;
00115 }
00116 /* }}} */
00117 
00118 /* Userspace */
00119 
00120 static void php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
00121 {
00122        char *algo, *data, *digest;
00123        int algo_len, data_len;
00124        zend_bool raw_output = raw_output_default;
00125        const php_hash_ops *ops;
00126        void *context;
00127        php_stream *stream = NULL;
00128 
00129        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &algo, &algo_len, &data, &data_len, &raw_output) == FAILURE) {
00130               return;
00131        }
00132 
00133        ops = php_hash_fetch_ops(algo, algo_len);
00134        if (!ops) {
00135               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
00136               RETURN_FALSE;
00137        }
00138        if (isfilename) {
00139               stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL, DEFAULT_CONTEXT);
00140               if (!stream) {
00141                      /* Stream will report errors opening file */
00142                      RETURN_FALSE;
00143               }
00144        }
00145 
00146        context = emalloc(ops->context_size);
00147        ops->hash_init(context);
00148 
00149        if (isfilename) {
00150               char buf[1024];
00151               int n;
00152 
00153               while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
00154                      ops->hash_update(context, (unsigned char *) buf, n);
00155               }
00156               php_stream_close(stream);
00157        } else {
00158               ops->hash_update(context, (unsigned char *) data, data_len);
00159        }
00160 
00161        digest = emalloc(ops->digest_size + 1);
00162        ops->hash_final((unsigned char *) digest, context);
00163        efree(context);
00164 
00165        if (raw_output) {
00166               digest[ops->digest_size] = 0;
00167               RETURN_STRINGL(digest, ops->digest_size, 0);
00168        } else {
00169               char *hex_digest = safe_emalloc(ops->digest_size, 2, 1);
00170 
00171               php_hash_bin2hex(hex_digest, (unsigned char *) digest, ops->digest_size);
00172               hex_digest[2 * ops->digest_size] = 0;
00173               efree(digest);
00174               RETURN_STRINGL(hex_digest, 2 * ops->digest_size, 0);
00175        }
00176 }
00177 /* }}} */
00178 
00179 /* {{{ proto string hash(string algo, string data[, bool raw_output = false])
00180 Generate a hash of a given input string
00181 Returns lowercase hexits by default */
00182 PHP_FUNCTION(hash)
00183 {
00184        php_hash_do_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
00185 }
00186 /* }}} */
00187 
00188 /* {{{ proto string hash_file(string algo, string filename[, bool raw_output = false])
00189 Generate a hash of a given file
00190 Returns lowercase hexits by default */
00191 PHP_FUNCTION(hash_file)
00192 {
00193        php_hash_do_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
00194 }
00195 /* }}} */
00196 
00197 static void php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
00198 {
00199        char *algo, *data, *digest, *key, *K;
00200        int algo_len, data_len, key_len, i;
00201        zend_bool raw_output = raw_output_default;
00202        const php_hash_ops *ops;
00203        void *context;
00204        php_stream *stream = NULL;
00205 
00206        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &algo, &algo_len, &data, &data_len, 
00207                                                                                                                   &key, &key_len, &raw_output) == FAILURE) {
00208               return;
00209        }
00210 
00211        ops = php_hash_fetch_ops(algo, algo_len);
00212        if (!ops) {
00213               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
00214               RETURN_FALSE;
00215        }
00216        if (isfilename) {
00217               stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL, DEFAULT_CONTEXT);
00218               if (!stream) {
00219                      /* Stream will report errors opening file */
00220                      RETURN_FALSE;
00221               }
00222        }
00223 
00224        context = emalloc(ops->context_size);
00225        ops->hash_init(context);
00226 
00227        K = emalloc(ops->block_size);
00228        memset(K, 0, ops->block_size);
00229 
00230        if (key_len > ops->block_size) {
00231               /* Reduce the key first */
00232               ops->hash_update(context, (unsigned char *) key, key_len);
00233               ops->hash_final((unsigned char *) K, context);
00234               /* Make the context ready to start over */
00235               ops->hash_init(context);
00236        } else {
00237               memcpy(K, key, key_len);
00238        }
00239                      
00240        /* XOR ipad */
00241        for(i=0; i < ops->block_size; i++) {
00242               K[i] ^= 0x36;
00243        }
00244        ops->hash_update(context, (unsigned char *) K, ops->block_size);
00245 
00246        if (isfilename) {
00247               char buf[1024];
00248               int n;
00249 
00250               while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
00251                      ops->hash_update(context, (unsigned char *) buf, n);
00252               }
00253               php_stream_close(stream);
00254        } else {
00255               ops->hash_update(context, (unsigned char *) data, data_len);
00256        }
00257 
00258        digest = emalloc(ops->digest_size + 1);
00259        ops->hash_final((unsigned char *) digest, context);
00260 
00261        /* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */
00262        for(i=0; i < ops->block_size; i++) {
00263               K[i] ^= 0x6A;
00264        }
00265 
00266        /* Feed this result into the outter hash */
00267        ops->hash_init(context);
00268        ops->hash_update(context, (unsigned char *) K, ops->block_size);
00269        ops->hash_update(context, (unsigned char *) digest, ops->digest_size);
00270        ops->hash_final((unsigned char *) digest, context);
00271 
00272        /* Zero the key */
00273        memset(K, 0, ops->block_size);
00274        efree(K);
00275        efree(context);
00276 
00277        if (raw_output) {
00278               digest[ops->digest_size] = 0;
00279               RETURN_STRINGL(digest, ops->digest_size, 0);
00280        } else {
00281               char *hex_digest = safe_emalloc(ops->digest_size, 2, 1);
00282 
00283               php_hash_bin2hex(hex_digest, (unsigned char *) digest, ops->digest_size);
00284               hex_digest[2 * ops->digest_size] = 0;
00285               efree(digest);
00286               RETURN_STRINGL(hex_digest, 2 * ops->digest_size, 0);
00287        }
00288 }
00289 /* }}} */
00290 
00291 /* {{{ proto string hash_hmac(string algo, string data, string key[, bool raw_output = false])
00292 Generate a hash of a given input string with a key using HMAC
00293 Returns lowercase hexits by default */
00294 PHP_FUNCTION(hash_hmac)
00295 {
00296        php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
00297 }
00298 /* }}} */
00299 
00300 /* {{{ proto string hash_hmac_file(string algo, string filename, string key[, bool raw_output = false])
00301 Generate a hash of a given file with a key using HMAC
00302 Returns lowercase hexits by default */
00303 PHP_FUNCTION(hash_hmac_file)
00304 {
00305        php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
00306 }
00307 /* }}} */
00308 
00309 
00310 /* {{{ proto resource hash_init(string algo[, int options, string key])
00311 Initialize a hashing context */
00312 PHP_FUNCTION(hash_init)
00313 {
00314        char *algo, *key = NULL;
00315        int algo_len, key_len = 0, argc = ZEND_NUM_ARGS();
00316        long options = 0;
00317        void *context;
00318        const php_hash_ops *ops;
00319        php_hash_data *hash;
00320 
00321        if (zend_parse_parameters(argc TSRMLS_CC, "s|ls", &algo, &algo_len, &options, &key, &key_len) == FAILURE) {
00322               return;
00323        }
00324 
00325        ops = php_hash_fetch_ops(algo, algo_len);
00326        if (!ops) {
00327               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
00328               RETURN_FALSE;
00329        }
00330 
00331        if (options & PHP_HASH_HMAC &&
00332               key_len <= 0) {
00333               /* Note: a zero length key is no key at all */
00334               php_error_docref(NULL TSRMLS_CC, E_WARNING, "HMAC requested without a key");
00335               RETURN_FALSE;
00336        }
00337 
00338        context = emalloc(ops->context_size);
00339        ops->hash_init(context);
00340 
00341        hash = emalloc(sizeof(php_hash_data));
00342        hash->ops = ops;
00343        hash->context = context;
00344        hash->options = options;
00345        hash->key = NULL;
00346 
00347        if (options & PHP_HASH_HMAC) {
00348               char *K = emalloc(ops->block_size);
00349               int i;
00350 
00351               memset(K, 0, ops->block_size);
00352 
00353               if (key_len > ops->block_size) {
00354                      /* Reduce the key first */
00355                      ops->hash_update(context, (unsigned char *) key, key_len);
00356                      ops->hash_final((unsigned char *) K, context);
00357                      /* Make the context ready to start over */
00358                      ops->hash_init(context);
00359               } else {
00360                      memcpy(K, key, key_len);
00361               }
00362                      
00363               /* XOR ipad */
00364               for(i=0; i < ops->block_size; i++) {
00365                      K[i] ^= 0x36;
00366               }
00367               ops->hash_update(context, (unsigned char *) K, ops->block_size);
00368               hash->key = (unsigned char *) K;
00369        }
00370 
00371        ZEND_REGISTER_RESOURCE(return_value, hash, php_hash_le_hash);
00372 }
00373 /* }}} */
00374 
00375 /* {{{ proto bool hash_update(resource context, string data)
00376 Pump data into the hashing algorithm */
00377 PHP_FUNCTION(hash_update)
00378 {
00379        zval *zhash;
00380        php_hash_data *hash;
00381        char *data;
00382        int data_len;
00383 
00384        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zhash, &data, &data_len) == FAILURE) {
00385               return;
00386        }
00387 
00388        ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
00389 
00390        hash->ops->hash_update(hash->context, (unsigned char *) data, data_len);
00391 
00392        RETURN_TRUE;
00393 }
00394 /* }}} */
00395 
00396 /* {{{ proto int hash_update_stream(resource context, resource handle[, integer length])
00397 Pump data into the hashing algorithm from an open stream */
00398 PHP_FUNCTION(hash_update_stream)
00399 {
00400        zval *zhash, *zstream;
00401        php_hash_data *hash;
00402        php_stream *stream = NULL;
00403        long length = -1, didread = 0;
00404 
00405        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &zhash, &zstream, &length) == FAILURE) {
00406               return;
00407        }
00408 
00409        ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
00410        php_stream_from_zval(stream, &zstream);
00411 
00412        while (length) {
00413               char buf[1024];
00414               long n, toread = 1024;
00415 
00416               if (length > 0 && toread > length) {
00417                      toread = length;
00418               }
00419 
00420               if ((n = php_stream_read(stream, buf, toread)) <= 0) {
00421                      /* Nada mas */
00422                      RETURN_LONG(didread);
00423               }
00424               hash->ops->hash_update(hash->context, (unsigned char *) buf, n);
00425               length -= n;
00426               didread += n;
00427        } 
00428 
00429        RETURN_LONG(didread);
00430 }
00431 /* }}} */
00432 
00433 /* {{{ proto bool hash_update_file(resource context, string filename[, resource context])
00434 Pump data into the hashing algorithm from a file */
00435 PHP_FUNCTION(hash_update_file)
00436 {
00437        zval *zhash, *zcontext = NULL;
00438        php_hash_data *hash;
00439        php_stream_context *context;
00440        php_stream *stream;
00441        char *filename, buf[1024];
00442        int filename_len, n;
00443 
00444        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|r", &zhash, &filename, &filename_len, &zcontext) == FAILURE) {
00445               return;
00446        }
00447 
00448        ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
00449        context = php_stream_context_from_zval(zcontext, 0);
00450 
00451        stream = php_stream_open_wrapper_ex(filename, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL, context);
00452        if (!stream) {
00453               /* Stream will report errors opening file */
00454               RETURN_FALSE;
00455        }
00456 
00457        while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
00458               hash->ops->hash_update(hash->context, (unsigned char *) buf, n);
00459        }
00460        php_stream_close(stream);
00461 
00462        RETURN_TRUE;
00463 }
00464 /* }}} */
00465 
00466 /* {{{ proto string hash_final(resource context[, bool raw_output=false])
00467 Output resulting digest */
00468 PHP_FUNCTION(hash_final)
00469 {
00470        zval *zhash;
00471        php_hash_data *hash;
00472        zend_bool raw_output = 0;
00473        zend_rsrc_list_entry *le;
00474        char *digest;
00475        int digest_len;
00476 
00477        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &zhash, &raw_output) == FAILURE) {
00478               return;
00479        }
00480 
00481        ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
00482 
00483        digest_len = hash->ops->digest_size;
00484        digest = emalloc(digest_len + 1);
00485        hash->ops->hash_final((unsigned char *) digest, hash->context);
00486        if (hash->options & PHP_HASH_HMAC) {
00487               int i;
00488 
00489               /* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */
00490               for(i=0; i < hash->ops->block_size; i++) {
00491                      hash->key[i] ^= 0x6A;
00492               }
00493 
00494               /* Feed this result into the outter hash */
00495               hash->ops->hash_init(hash->context);
00496               hash->ops->hash_update(hash->context, (unsigned char *) hash->key, hash->ops->block_size);
00497               hash->ops->hash_update(hash->context, (unsigned char *) digest, hash->ops->digest_size);
00498               hash->ops->hash_final((unsigned char *) digest, hash->context);
00499 
00500               /* Zero the key */
00501               memset(hash->key, 0, hash->ops->block_size);
00502               efree(hash->key);
00503               hash->key = NULL;
00504        }
00505        digest[digest_len] = 0;
00506        efree(hash->context);
00507        hash->context = NULL;
00508 
00509        /* zend_list_REAL_delete() */
00510        if (zend_hash_index_find(&EG(regular_list), Z_RESVAL_P(zhash), (void *) &le)==SUCCESS) {
00511               /* This is a hack to avoid letting the resource hide elsewhere (like in separated vars)
00512                      FETCH_RESOURCE is intelligent enough to handle dealing with any issues this causes */
00513               le->refcount = 1;
00514        } /* FAILURE is not an option */
00515        zend_list_delete(Z_RESVAL_P(zhash));
00516 
00517        if (raw_output) {
00518               RETURN_STRINGL(digest, digest_len, 0);
00519        } else {
00520               char *hex_digest = safe_emalloc(digest_len,2,1);
00521 
00522               php_hash_bin2hex(hex_digest, (unsigned char *) digest, digest_len);
00523               hex_digest[2 * digest_len] = 0;
00524               efree(digest);
00525               RETURN_STRINGL(hex_digest, 2 * digest_len, 0);          
00526        }
00527 }
00528 /* }}} */
00529 
00530 /* {{{ proto resource hash_copy(resource context)
00531 Copy hash resource */
00532 PHP_FUNCTION(hash_copy)
00533 {
00534        zval *zhash;
00535        php_hash_data *hash, *copy_hash;
00536        void *context;
00537        int res;
00538 
00539        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zhash) == FAILURE) {
00540               return;
00541        }
00542 
00543        ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
00544 
00545 
00546        context = emalloc(hash->ops->context_size);
00547        hash->ops->hash_init(context);
00548 
00549        res = hash->ops->hash_copy(hash->ops, hash->context, context);
00550        if (res != SUCCESS) {
00551               efree(context);
00552               RETURN_FALSE;
00553        }
00554 
00555        copy_hash = emalloc(sizeof(php_hash_data));
00556        copy_hash->ops = hash->ops;
00557        copy_hash->context = context;
00558        copy_hash->options = hash->options;
00559        copy_hash->key = ecalloc(1, hash->ops->block_size);
00560        if (hash->key) {
00561               memcpy(copy_hash->key, hash->key, hash->ops->block_size);
00562        }
00563        ZEND_REGISTER_RESOURCE(return_value, copy_hash, php_hash_le_hash);
00564 }
00565 /* }}} */
00566 
00567 /* {{{ proto array hash_algos(void)
00568 Return a list of registered hashing algorithms */
00569 PHP_FUNCTION(hash_algos)
00570 {
00571        HashPosition pos;
00572        char *str;
00573        uint str_len;
00574        long type;
00575        ulong idx;
00576 
00577        array_init(return_value);
00578        for(zend_hash_internal_pointer_reset_ex(&php_hash_hashtable, &pos);
00579               (type = zend_hash_get_current_key_ex(&php_hash_hashtable, &str, &str_len, &idx, 0, &pos)) != HASH_KEY_NON_EXISTANT;
00580               zend_hash_move_forward_ex(&php_hash_hashtable, &pos)) {
00581               add_next_index_stringl(return_value, str, str_len-1, 1);
00582        }
00583 }
00584 /* }}} */
00585 
00586 /* Module Housekeeping */
00587 
00588 static void php_hash_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00589 {
00590        php_hash_data *hash = (php_hash_data*)rsrc->ptr;
00591 
00592        /* Just in case the algo has internally allocated resources */
00593        if (hash->context) {
00594               unsigned char *dummy = emalloc(hash->ops->digest_size);
00595               hash->ops->hash_final(dummy, hash->context);
00596               efree(dummy);
00597               efree(hash->context);
00598        }
00599 
00600        if (hash->key) {
00601               memset(hash->key, 0, hash->ops->block_size);
00602               efree(hash->key);
00603        }
00604        efree(hash);
00605 }
00606 /* }}} */
00607 
00608 #define PHP_HASH_HAVAL_REGISTER(p,b)      php_hash_register_algo("haval" #b "," #p , &php_hash_##p##haval##b##_ops);
00609 
00610 #ifdef PHP_MHASH_BC
00611 
00612 PHP_MINFO_FUNCTION(mhash)
00613 {
00614        php_info_print_table_start();
00615        php_info_print_table_row(2, "MHASH support", "Enabled");
00616        php_info_print_table_row(2, "MHASH API Version", "Emulated Support");
00617        php_info_print_table_end();
00618 }
00619 
00620 zend_module_entry mhash_module_entry = {
00621        STANDARD_MODULE_HEADER,
00622        "mhash",
00623        NULL,
00624        NULL,
00625        NULL,
00626        NULL,
00627        NULL,
00628        PHP_MINFO(mhash),
00629        NO_VERSION_YET,
00630        STANDARD_MODULE_PROPERTIES,
00631 };
00632 
00633 static void mhash_init(INIT_FUNC_ARGS)
00634 {
00635        char buf[128];
00636        int len;
00637        int algo_number = 0;
00638 
00639        for (algo_number = 0; algo_number < MHASH_NUM_ALGOS; algo_number++) {
00640               struct mhash_bc_entry algorithm = mhash_to_hash[algo_number];
00641               if (algorithm.mhash_name == NULL) {
00642                      continue;
00643               }
00644 
00645               len = slprintf(buf, 127, "MHASH_%s", algorithm.mhash_name, strlen(algorithm.mhash_name));
00646               zend_register_long_constant(buf, len + 1, algorithm.value, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
00647        }
00648        zend_register_internal_module(&mhash_module_entry TSRMLS_CC);
00649 }
00650 
00651 /* {{{ proto string mhash(int hash, string data [, string key])
00652    Hash data with hash */
00653 PHP_FUNCTION(mhash)
00654 {
00655        zval **z_algorithm;
00656        long algorithm;
00657 
00658        if (zend_parse_parameters(1 TSRMLS_CC, "Z", &z_algorithm) == FAILURE) {
00659               return;
00660        }
00661 
00662        SEPARATE_ZVAL(z_algorithm);
00663        convert_to_long_ex(z_algorithm);
00664        algorithm = Z_LVAL_PP(z_algorithm);
00665 
00666        /* need to convert the first parameter from int constant to string algorithm name */
00667        if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
00668               struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
00669               if (algorithm_lookup.hash_name) {
00670                      ZVAL_STRING(*z_algorithm, algorithm_lookup.hash_name, 1);
00671               }
00672        }
00673 
00674        if (ZEND_NUM_ARGS() == 3) {
00675               php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
00676        } else if (ZEND_NUM_ARGS() == 2) {
00677               php_hash_do_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
00678        } else {
00679               WRONG_PARAM_COUNT;
00680        }
00681 }
00682 /* }}} */
00683 
00684 /* {{{ proto string mhash_get_hash_name(int hash)
00685    Gets the name of hash */
00686 PHP_FUNCTION(mhash_get_hash_name)
00687 {
00688        long algorithm;
00689 
00690        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &algorithm) == FAILURE) {
00691               return;
00692        }
00693 
00694        if (algorithm >= 0 && algorithm  < MHASH_NUM_ALGOS) {
00695               struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
00696               if (algorithm_lookup.mhash_name) {
00697                      RETURN_STRING(algorithm_lookup.mhash_name, 1);
00698               }
00699        }
00700        RETURN_FALSE;
00701 }
00702 /* }}} */
00703 
00704 /* {{{ proto int mhash_count(void)
00705    Gets the number of available hashes */
00706 PHP_FUNCTION(mhash_count)
00707 {
00708        if (zend_parse_parameters_none() == FAILURE) {
00709               return;
00710        }
00711        RETURN_LONG(MHASH_NUM_ALGOS - 1);
00712 }
00713 /* }}} */
00714 
00715 /* {{{ proto int mhash_get_block_size(int hash)
00716    Gets the block size of hash */
00717 PHP_FUNCTION(mhash_get_block_size)
00718 {
00719        long algorithm;
00720 
00721        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &algorithm) == FAILURE) {
00722               return;
00723        }
00724        RETVAL_FALSE;
00725 
00726        if (algorithm >= 0 && algorithm  < MHASH_NUM_ALGOS) {
00727               struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
00728               if (algorithm_lookup.mhash_name) {
00729                      const php_hash_ops *ops = php_hash_fetch_ops(algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
00730                      if (ops) {
00731                             RETVAL_LONG(ops->digest_size);
00732                      }
00733               }
00734        }
00735 }
00736 /* }}} */
00737 
00738 #define SALT_SIZE 8
00739 
00740 /* {{{ proto string mhash_keygen_s2k(int hash, string input_password, string salt, int bytes)
00741    Generates a key using hash functions */
00742 PHP_FUNCTION(mhash_keygen_s2k)
00743 {
00744        long algorithm, l_bytes;
00745        int bytes;
00746        char *password, *salt;
00747        int password_len, salt_len;
00748        char padded_salt[SALT_SIZE];
00749 
00750        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lssl", &algorithm, &password, &password_len, &salt, &salt_len, &l_bytes) == FAILURE) {
00751               return;
00752        }
00753 
00754        bytes = (int)l_bytes;
00755        if (bytes <= 0){
00756               php_error_docref(NULL TSRMLS_CC, E_WARNING, "the byte parameter must be greater than 0");
00757               RETURN_FALSE;
00758        }
00759 
00760        salt_len = MIN(salt_len, SALT_SIZE);
00761 
00762        memcpy(padded_salt, salt, salt_len);
00763        if (salt_len < SALT_SIZE) {
00764               memset(padded_salt + salt_len, 0, SALT_SIZE - salt_len);
00765        }
00766        salt_len = SALT_SIZE;
00767 
00768        RETVAL_FALSE;
00769        if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
00770               struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
00771               if (algorithm_lookup.mhash_name) {
00772                      const php_hash_ops *ops = php_hash_fetch_ops(algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
00773                      if (ops) {
00774                             unsigned char null = '\0';
00775                             void *context;
00776                             char *key, *digest;
00777                             int i = 0, j = 0;
00778                             int block_size = ops->digest_size;
00779                             int times = bytes / block_size;
00780                             if (bytes % block_size  != 0) times++;
00781 
00782                             context = emalloc(ops->context_size);
00783                             ops->hash_init(context);
00784 
00785                             key = ecalloc(1, times * block_size);
00786                             digest = emalloc(ops->digest_size + 1);
00787 
00788                             for (i = 0; i < times; i++) {
00789                                    ops->hash_init(context);
00790 
00791                                    for (j=0;j<i;j++) {
00792                                           ops->hash_update(context, &null, 1);
00793                                    }
00794                                    ops->hash_update(context, (unsigned char *)padded_salt, salt_len);
00795                                    ops->hash_update(context, (unsigned char *)password, password_len);
00796                                    ops->hash_final((unsigned char *)digest, context);
00797                                    memcpy( &key[i*block_size], digest, block_size);
00798                             }
00799 
00800                             RETVAL_STRINGL(key, bytes, 1);
00801                             memset(key, 0, bytes);
00802                             efree(digest);
00803                             efree(context);
00804                             efree(key);
00805                      }
00806               }
00807        }
00808 }
00809 /* }}} */
00810 
00811 #endif
00812 
00813 /* {{{ PHP_MINIT_FUNCTION
00814  */
00815 PHP_MINIT_FUNCTION(hash)
00816 {
00817        php_hash_le_hash = zend_register_list_destructors_ex(php_hash_dtor, NULL, PHP_HASH_RESNAME, module_number);
00818 
00819        zend_hash_init(&php_hash_hashtable, 35, NULL, NULL, 1);
00820 
00821        php_hash_register_algo("md2",                    &php_hash_md2_ops);
00822        php_hash_register_algo("md4",                    &php_hash_md4_ops);
00823        php_hash_register_algo("md5",                    &php_hash_md5_ops);
00824        php_hash_register_algo("sha1",                   &php_hash_sha1_ops);
00825        php_hash_register_algo("sha224",          &php_hash_sha224_ops);
00826        php_hash_register_algo("sha256",          &php_hash_sha256_ops);
00827        php_hash_register_algo("sha384",          &php_hash_sha384_ops);
00828        php_hash_register_algo("sha512",          &php_hash_sha512_ops);
00829        php_hash_register_algo("ripemd128",              &php_hash_ripemd128_ops);
00830        php_hash_register_algo("ripemd160",              &php_hash_ripemd160_ops);
00831        php_hash_register_algo("ripemd256",              &php_hash_ripemd256_ops);
00832        php_hash_register_algo("ripemd320",              &php_hash_ripemd320_ops);
00833        php_hash_register_algo("whirlpool",              &php_hash_whirlpool_ops);
00834        php_hash_register_algo("tiger128,3",      &php_hash_3tiger128_ops);
00835        php_hash_register_algo("tiger160,3",      &php_hash_3tiger160_ops);
00836        php_hash_register_algo("tiger192,3",      &php_hash_3tiger192_ops);
00837        php_hash_register_algo("tiger128,4",      &php_hash_4tiger128_ops);
00838        php_hash_register_algo("tiger160,4",      &php_hash_4tiger160_ops);
00839        php_hash_register_algo("tiger192,4",      &php_hash_4tiger192_ops);
00840        php_hash_register_algo("snefru",          &php_hash_snefru_ops);
00841        php_hash_register_algo("snefru256",              &php_hash_snefru_ops);
00842        php_hash_register_algo("gost",                   &php_hash_gost_ops);
00843        php_hash_register_algo("adler32",         &php_hash_adler32_ops);
00844        php_hash_register_algo("crc32",                  &php_hash_crc32_ops);
00845        php_hash_register_algo("crc32b",          &php_hash_crc32b_ops);
00846        php_hash_register_algo("salsa10",         &php_hash_salsa10_ops);
00847        php_hash_register_algo("salsa20",         &php_hash_salsa20_ops);
00848 
00849        PHP_HASH_HAVAL_REGISTER(3,128);
00850        PHP_HASH_HAVAL_REGISTER(3,160);
00851        PHP_HASH_HAVAL_REGISTER(3,192);
00852        PHP_HASH_HAVAL_REGISTER(3,224);
00853        PHP_HASH_HAVAL_REGISTER(3,256);
00854 
00855        PHP_HASH_HAVAL_REGISTER(4,128);
00856        PHP_HASH_HAVAL_REGISTER(4,160);
00857        PHP_HASH_HAVAL_REGISTER(4,192);
00858        PHP_HASH_HAVAL_REGISTER(4,224);
00859        PHP_HASH_HAVAL_REGISTER(4,256);
00860 
00861        PHP_HASH_HAVAL_REGISTER(5,128);
00862        PHP_HASH_HAVAL_REGISTER(5,160);
00863        PHP_HASH_HAVAL_REGISTER(5,192);
00864        PHP_HASH_HAVAL_REGISTER(5,224);
00865        PHP_HASH_HAVAL_REGISTER(5,256);
00866 
00867        REGISTER_LONG_CONSTANT("HASH_HMAC",              PHP_HASH_HMAC,       CONST_CS | CONST_PERSISTENT);
00868 
00869 #ifdef PHP_MHASH_BC
00870        mhash_init(INIT_FUNC_ARGS_PASSTHRU);
00871 #endif
00872 
00873        return SUCCESS;
00874 }
00875 /* }}} */
00876 
00877 /* {{{ PHP_MSHUTDOWN_FUNCTION
00878  */
00879 PHP_MSHUTDOWN_FUNCTION(hash)
00880 {
00881        zend_hash_destroy(&php_hash_hashtable);
00882 
00883        return SUCCESS;
00884 }
00885 /* }}} */
00886 
00887 /* {{{ PHP_MINFO_FUNCTION
00888  */
00889 PHP_MINFO_FUNCTION(hash)
00890 {
00891        HashPosition pos;
00892        char buffer[2048];
00893        char *s = buffer, *e = s + sizeof(buffer), *str;
00894        ulong idx;
00895        long type;
00896 
00897        for(zend_hash_internal_pointer_reset_ex(&php_hash_hashtable, &pos);
00898               (type = zend_hash_get_current_key_ex(&php_hash_hashtable, &str, NULL, &idx, 0, &pos)) != HASH_KEY_NON_EXISTANT;
00899               zend_hash_move_forward_ex(&php_hash_hashtable, &pos)) {
00900               s += slprintf(s, e - s, "%s ", str);
00901        }
00902        *s = 0;
00903 
00904        php_info_print_table_start();
00905        php_info_print_table_row(2, "hash support", "enabled");
00906        php_info_print_table_row(2, "Hashing Engines", buffer);
00907        php_info_print_table_end();
00908 }
00909 /* }}} */
00910 
00911 /* {{{ arginfo */
00912 #ifdef PHP_HASH_MD5_NOT_IN_CORE
00913 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_md5, 0, 0, 1)
00914        ZEND_ARG_INFO(0, str)
00915        ZEND_ARG_INFO(0, raw_output)
00916 ZEND_END_ARG_INFO()
00917 
00918 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_md5_file, 0, 0, 1)
00919        ZEND_ARG_INFO(0, filename)
00920        ZEND_ARG_INFO(0, raw_output)
00921 ZEND_END_ARG_INFO()
00922 #endif
00923 
00924 #ifdef PHP_HASH_SHA1_NOT_IN_CORE
00925 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_sha1, 0, 0, 1)
00926        ZEND_ARG_INFO(0, str)
00927        ZEND_ARG_INFO(0, raw_output)
00928 ZEND_END_ARG_INFO()
00929 
00930 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_sha1_file, 0, 0, 1)
00931        ZEND_ARG_INFO(0, filename)
00932        ZEND_ARG_INFO(0, raw_output)
00933 ZEND_END_ARG_INFO()
00934 #endif
00935 
00936 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash, 0, 0, 2)
00937        ZEND_ARG_INFO(0, algo)
00938        ZEND_ARG_INFO(0, data)
00939        ZEND_ARG_INFO(0, raw_output)
00940 ZEND_END_ARG_INFO()
00941 
00942 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_file, 0, 0, 2)
00943        ZEND_ARG_INFO(0, algo)
00944        ZEND_ARG_INFO(0, filename)
00945        ZEND_ARG_INFO(0, raw_output)
00946 ZEND_END_ARG_INFO()
00947 
00948 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_hmac, 0, 0, 3)
00949        ZEND_ARG_INFO(0, algo)
00950        ZEND_ARG_INFO(0, data)
00951        ZEND_ARG_INFO(0, key)
00952        ZEND_ARG_INFO(0, raw_output)
00953 ZEND_END_ARG_INFO()
00954 
00955 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_hmac_file, 0, 0, 3)
00956        ZEND_ARG_INFO(0, algo)
00957        ZEND_ARG_INFO(0, filename)
00958        ZEND_ARG_INFO(0, key)
00959        ZEND_ARG_INFO(0, raw_output)
00960 ZEND_END_ARG_INFO()
00961 
00962 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_init, 0, 0, 1)
00963        ZEND_ARG_INFO(0, algo)
00964        ZEND_ARG_INFO(0, options)
00965        ZEND_ARG_INFO(0, key)
00966 ZEND_END_ARG_INFO()
00967 
00968 ZEND_BEGIN_ARG_INFO(arginfo_hash_update, 0)
00969        ZEND_ARG_INFO(0, context)
00970        ZEND_ARG_INFO(0, data)
00971 ZEND_END_ARG_INFO()
00972 
00973 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_update_stream, 0, 0, 2)
00974        ZEND_ARG_INFO(0, context)
00975        ZEND_ARG_INFO(0, handle)
00976        ZEND_ARG_INFO(0, length)
00977 ZEND_END_ARG_INFO()
00978 
00979 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_update_file, 0, 0, 2)
00980        ZEND_ARG_INFO(0, context)
00981        ZEND_ARG_INFO(0, filename)
00982        ZEND_ARG_INFO(0, context)
00983 ZEND_END_ARG_INFO()
00984 
00985 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_final, 0, 0, 1)
00986        ZEND_ARG_INFO(0, context)
00987        ZEND_ARG_INFO(0, raw_output)
00988 ZEND_END_ARG_INFO()
00989 
00990 ZEND_BEGIN_ARG_INFO(arginfo_hash_copy, 0)
00991        ZEND_ARG_INFO(0, context)
00992 ZEND_END_ARG_INFO()
00993 
00994 ZEND_BEGIN_ARG_INFO(arginfo_hash_algos, 0)
00995 ZEND_END_ARG_INFO()
00996 
00997 /* BC Land */
00998 #ifdef PHP_MHASH_BC
00999 ZEND_BEGIN_ARG_INFO(arginfo_mhash_get_block_size, 0)
01000        ZEND_ARG_INFO(0, hash)
01001 ZEND_END_ARG_INFO()
01002 
01003 ZEND_BEGIN_ARG_INFO(arginfo_mhash_get_hash_name, 0)
01004        ZEND_ARG_INFO(0, hash)
01005 ZEND_END_ARG_INFO()
01006 
01007 ZEND_BEGIN_ARG_INFO(arginfo_mhash_keygen_s2k, 0)
01008        ZEND_ARG_INFO(0, hash)
01009        ZEND_ARG_INFO(0, input_password)
01010        ZEND_ARG_INFO(0, salt)
01011        ZEND_ARG_INFO(0, bytes)
01012 ZEND_END_ARG_INFO()
01013 
01014 ZEND_BEGIN_ARG_INFO(arginfo_mhash_count, 0)
01015 ZEND_END_ARG_INFO()
01016 
01017 ZEND_BEGIN_ARG_INFO_EX(arginfo_mhash, 0, 0, 2)
01018        ZEND_ARG_INFO(0, hash)
01019        ZEND_ARG_INFO(0, data)
01020        ZEND_ARG_INFO(0, key)
01021 ZEND_END_ARG_INFO()
01022 #endif
01023 
01024 /* }}} */
01025 
01026 /* {{{ hash_functions[]
01027  */
01028 const zend_function_entry hash_functions[] = {
01029        PHP_FE(hash,                                                          arginfo_hash)
01030        PHP_FE(hash_file,                                                     arginfo_hash_file)
01031 
01032        PHP_FE(hash_hmac,                                                     arginfo_hash_hmac)
01033        PHP_FE(hash_hmac_file,                                                arginfo_hash_hmac_file)
01034 
01035        PHP_FE(hash_init,                                                     arginfo_hash_init)
01036        PHP_FE(hash_update,                                                   arginfo_hash_update)
01037        PHP_FE(hash_update_stream,                                     arginfo_hash_update_stream)
01038        PHP_FE(hash_update_file,                                       arginfo_hash_update_file)
01039        PHP_FE(hash_final,                                                    arginfo_hash_final)
01040        PHP_FE(hash_copy,                                                     arginfo_hash_copy)
01041 
01042        PHP_FE(hash_algos,                                                    arginfo_hash_algos)
01043 
01044        /* BC Land */
01045 #ifdef PHP_HASH_MD5_NOT_IN_CORE
01046        PHP_NAMED_FE(md5, php_if_md5,                                  arginfo_hash_md5)
01047        PHP_NAMED_FE(md5_file, php_if_md5_file,                 arginfo_hash_md5_file)
01048 #endif /* PHP_HASH_MD5_NOT_IN_CORE */
01049 
01050 #ifdef PHP_HASH_SHA1_NOT_IN_CORE
01051        PHP_NAMED_FE(sha1, php_if_sha1,                                arginfo_hash_sha1)
01052        PHP_NAMED_FE(sha1_file, php_if_sha1_file,        arginfo_hash_sha1_file)
01053 #endif /* PHP_HASH_SHA1_NOT_IN_CORE */
01054 
01055 #ifdef PHP_MHASH_BC
01056        PHP_FE(mhash_keygen_s2k, arginfo_mhash_keygen_s2k)
01057        PHP_FE(mhash_get_block_size, arginfo_mhash_get_block_size)
01058        PHP_FE(mhash_get_hash_name, arginfo_mhash_get_hash_name)
01059        PHP_FE(mhash_count, arginfo_mhash_count)
01060        PHP_FE(mhash, arginfo_mhash)
01061 #endif
01062 
01063        PHP_FE_END
01064 };
01065 /* }}} */
01066 
01067 /* {{{ hash_module_entry
01068  */
01069 zend_module_entry hash_module_entry = {
01070 #if ZEND_MODULE_API_NO >= 20010901
01071        STANDARD_MODULE_HEADER,
01072 #endif
01073        PHP_HASH_EXTNAME,
01074        hash_functions,
01075        PHP_MINIT(hash),
01076        PHP_MSHUTDOWN(hash),
01077        NULL, /* RINIT */
01078        NULL, /* RSHUTDOWN */
01079        PHP_MINFO(hash),
01080 #if ZEND_MODULE_API_NO >= 20010901
01081        PHP_HASH_EXTVER, /* Replace with version number for your extension */
01082 #endif
01083        STANDARD_MODULE_PROPERTIES
01084 };
01085 /* }}} */
01086 
01087 #ifdef COMPILE_DL_HASH
01088 ZEND_GET_MODULE(hash)
01089 #endif
01090 
01091 /*
01092  * Local variables:
01093  * tab-width: 4
01094  * c-basic-offset: 4
01095  * End:
01096  * vim600: noet sw=4 ts=4 fdm=marker
01097  * vim<600: noet sw=4 ts=4
01098  */