1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 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 | Author: Sara Golemon <pollita@php.net> |
16 | Scott MacVicar <scottmac@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "php_hash.h"
27 #include "ext/standard/info.h"
28 #include "ext/standard/file.h"
29
30 static int php_hash_le_hash;
31 HashTable php_hash_hashtable;
32
33 #if (PHP_MAJOR_VERSION >= 5)
34 # define DEFAULT_CONTEXT FG(default_context)
35 #else
36 # define DEFAULT_CONTEXT NULL
37 #endif
38
39 #ifdef PHP_MHASH_BC
40 struct mhash_bc_entry {
41 char *mhash_name;
42 char *hash_name;
43 int value;
44 };
45
46 #define MHASH_NUM_ALGOS 34
47
48 static struct mhash_bc_entry mhash_to_hash[MHASH_NUM_ALGOS] = {
49 {"CRC32", "crc32", 0},
50 {"MD5", "md5", 1},
51 {"SHA1", "sha1", 2},
52 {"HAVAL256", "haval256,3", 3},
53 {NULL, NULL, 4},
54 {"RIPEMD160", "ripemd160", 5},
55 {NULL, NULL, 6},
56 {"TIGER", "tiger192,3", 7},
57 {"GOST", "gost", 8},
58 {"CRC32B", "crc32b", 9},
59 {"HAVAL224", "haval224,3", 10},
60 {"HAVAL192", "haval192,3", 11},
61 {"HAVAL160", "haval160,3", 12},
62 {"HAVAL128", "haval128,3", 13},
63 {"TIGER128", "tiger128,3", 14},
64 {"TIGER160", "tiger160,3", 15},
65 {"MD4", "md4", 16},
66 {"SHA256", "sha256", 17},
67 {"ADLER32", "adler32", 18},
68 {"SHA224", "sha224", 19},
69 {"SHA512", "sha512", 20},
70 {"SHA384", "sha384", 21},
71 {"WHIRLPOOL", "whirlpool", 22},
72 {"RIPEMD128", "ripemd128", 23},
73 {"RIPEMD256", "ripemd256", 24},
74 {"RIPEMD320", "ripemd320", 25},
75 {NULL, NULL, 26}, /* support needs to be added for snefru 128 */
76 {"SNEFRU256", "snefru256", 27},
77 {"MD2", "md2", 28},
78 {"FNV132", "fnv132", 29},
79 {"FNV1A32", "fnv1a32", 30},
80 {"FNV164", "fnv164", 31},
81 {"FNV1A64", "fnv1a64", 32},
82 {"JOAAT", "joaat", 33},
83 };
84 #endif
85
86 /* Hash Registry Access */
87
php_hash_fetch_ops(const char * algo,int algo_len)88 PHP_HASH_API const php_hash_ops *php_hash_fetch_ops(const char *algo, int algo_len) /* {{{ */
89 {
90 php_hash_ops *ops;
91 char *lower = estrndup(algo, algo_len);
92
93 zend_str_tolower(lower, algo_len);
94 if (SUCCESS != zend_hash_find(&php_hash_hashtable, lower, algo_len + 1, (void*)&ops)) {
95 ops = NULL;
96 }
97 efree(lower);
98
99 return ops;
100 }
101 /* }}} */
102
php_hash_register_algo(const char * algo,const php_hash_ops * ops)103 PHP_HASH_API void php_hash_register_algo(const char *algo, const php_hash_ops *ops) /* {{{ */
104 {
105 int algo_len = strlen(algo);
106 char *lower = estrndup(algo, algo_len);
107
108 zend_str_tolower(lower, algo_len);
109 zend_hash_add(&php_hash_hashtable, lower, algo_len + 1, (void*)ops, sizeof(php_hash_ops), NULL);
110 efree(lower);
111 }
112 /* }}} */
113
php_hash_copy(const void * ops,void * orig_context,void * dest_context)114 PHP_HASH_API int php_hash_copy(const void *ops, void *orig_context, void *dest_context) /* {{{ */
115 {
116 php_hash_ops *hash_ops = (php_hash_ops *)ops;
117
118 memcpy(dest_context, orig_context, hash_ops->context_size);
119 return SUCCESS;
120 }
121 /* }}} */
122
123 /* Userspace */
124
php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS,int isfilename,zend_bool raw_output_default)125 static void php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
126 {
127 char *algo, *data, *digest;
128 int algo_len, data_len;
129 zend_bool raw_output = raw_output_default;
130 const php_hash_ops *ops;
131 void *context;
132 php_stream *stream = NULL;
133
134 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &algo, &algo_len, &data, &data_len, &raw_output) == FAILURE) {
135 return;
136 }
137
138 ops = php_hash_fetch_ops(algo, algo_len);
139 if (!ops) {
140 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
141 RETURN_FALSE;
142 }
143 if (isfilename) {
144 if (CHECK_NULL_PATH(data, data_len)) {
145 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path");
146 RETURN_FALSE;
147 }
148 stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS, NULL, DEFAULT_CONTEXT);
149 if (!stream) {
150 /* Stream will report errors opening file */
151 RETURN_FALSE;
152 }
153 }
154
155 context = emalloc(ops->context_size);
156 ops->hash_init(context);
157
158 if (isfilename) {
159 char buf[1024];
160 int n;
161
162 while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
163 ops->hash_update(context, (unsigned char *) buf, n);
164 }
165 php_stream_close(stream);
166 } else {
167 ops->hash_update(context, (unsigned char *) data, data_len);
168 }
169
170 digest = emalloc(ops->digest_size + 1);
171 ops->hash_final((unsigned char *) digest, context);
172 efree(context);
173
174 if (raw_output) {
175 digest[ops->digest_size] = 0;
176 RETURN_STRINGL(digest, ops->digest_size, 0);
177 } else {
178 char *hex_digest = safe_emalloc(ops->digest_size, 2, 1);
179
180 php_hash_bin2hex(hex_digest, (unsigned char *) digest, ops->digest_size);
181 hex_digest[2 * ops->digest_size] = 0;
182 efree(digest);
183 RETURN_STRINGL(hex_digest, 2 * ops->digest_size, 0);
184 }
185 }
186 /* }}} */
187
188 /* {{{ proto string hash(string algo, string data[, bool raw_output = false])
189 Generate a hash of a given input string
190 Returns lowercase hexits by default */
PHP_FUNCTION(hash)191 PHP_FUNCTION(hash)
192 {
193 php_hash_do_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
194 }
195 /* }}} */
196
197 /* {{{ proto string hash_file(string algo, string filename[, bool raw_output = false])
198 Generate a hash of a given file
199 Returns lowercase hexits by default */
PHP_FUNCTION(hash_file)200 PHP_FUNCTION(hash_file)
201 {
202 php_hash_do_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
203 }
204 /* }}} */
205
php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS,int isfilename,zend_bool raw_output_default)206 static void php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
207 {
208 char *algo, *data, *digest, *key, *K;
209 int algo_len, data_len, key_len, i;
210 zend_bool raw_output = raw_output_default;
211 const php_hash_ops *ops;
212 void *context;
213 php_stream *stream = NULL;
214
215 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &algo, &algo_len, &data, &data_len,
216 &key, &key_len, &raw_output) == FAILURE) {
217 return;
218 }
219
220 ops = php_hash_fetch_ops(algo, algo_len);
221 if (!ops) {
222 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
223 RETURN_FALSE;
224 }
225 if (isfilename) {
226 if (CHECK_NULL_PATH(data, data_len)) {
227 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path");
228 RETURN_FALSE;
229 }
230 stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS, NULL, DEFAULT_CONTEXT);
231 if (!stream) {
232 /* Stream will report errors opening file */
233 RETURN_FALSE;
234 }
235 }
236
237 context = emalloc(ops->context_size);
238 ops->hash_init(context);
239
240 K = emalloc(ops->block_size);
241 memset(K, 0, ops->block_size);
242
243 if (key_len > ops->block_size) {
244 /* Reduce the key first */
245 ops->hash_update(context, (unsigned char *) key, key_len);
246 ops->hash_final((unsigned char *) K, context);
247 /* Make the context ready to start over */
248 ops->hash_init(context);
249 } else {
250 memcpy(K, key, key_len);
251 }
252
253 /* XOR ipad */
254 for(i=0; i < ops->block_size; i++) {
255 K[i] ^= 0x36;
256 }
257 ops->hash_update(context, (unsigned char *) K, ops->block_size);
258
259 if (isfilename) {
260 char buf[1024];
261 int n;
262
263 while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
264 ops->hash_update(context, (unsigned char *) buf, n);
265 }
266 php_stream_close(stream);
267 } else {
268 ops->hash_update(context, (unsigned char *) data, data_len);
269 }
270
271 digest = emalloc(ops->digest_size + 1);
272 ops->hash_final((unsigned char *) digest, context);
273
274 /* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */
275 for(i=0; i < ops->block_size; i++) {
276 K[i] ^= 0x6A;
277 }
278
279 /* Feed this result into the outter hash */
280 ops->hash_init(context);
281 ops->hash_update(context, (unsigned char *) K, ops->block_size);
282 ops->hash_update(context, (unsigned char *) digest, ops->digest_size);
283 ops->hash_final((unsigned char *) digest, context);
284
285 /* Zero the key */
286 memset(K, 0, ops->block_size);
287 efree(K);
288 efree(context);
289
290 if (raw_output) {
291 digest[ops->digest_size] = 0;
292 RETURN_STRINGL(digest, ops->digest_size, 0);
293 } else {
294 char *hex_digest = safe_emalloc(ops->digest_size, 2, 1);
295
296 php_hash_bin2hex(hex_digest, (unsigned char *) digest, ops->digest_size);
297 hex_digest[2 * ops->digest_size] = 0;
298 efree(digest);
299 RETURN_STRINGL(hex_digest, 2 * ops->digest_size, 0);
300 }
301 }
302 /* }}} */
303
304 /* {{{ proto string hash_hmac(string algo, string data, string key[, bool raw_output = false])
305 Generate a hash of a given input string with a key using HMAC
306 Returns lowercase hexits by default */
PHP_FUNCTION(hash_hmac)307 PHP_FUNCTION(hash_hmac)
308 {
309 php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
310 }
311 /* }}} */
312
313 /* {{{ proto string hash_hmac_file(string algo, string filename, string key[, bool raw_output = false])
314 Generate a hash of a given file with a key using HMAC
315 Returns lowercase hexits by default */
PHP_FUNCTION(hash_hmac_file)316 PHP_FUNCTION(hash_hmac_file)
317 {
318 php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
319 }
320 /* }}} */
321
322
323 /* {{{ proto resource hash_init(string algo[, int options, string key])
324 Initialize a hashing context */
PHP_FUNCTION(hash_init)325 PHP_FUNCTION(hash_init)
326 {
327 char *algo, *key = NULL;
328 int algo_len, key_len = 0, argc = ZEND_NUM_ARGS();
329 long options = 0;
330 void *context;
331 const php_hash_ops *ops;
332 php_hash_data *hash;
333
334 if (zend_parse_parameters(argc TSRMLS_CC, "s|ls", &algo, &algo_len, &options, &key, &key_len) == FAILURE) {
335 return;
336 }
337
338 ops = php_hash_fetch_ops(algo, algo_len);
339 if (!ops) {
340 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
341 RETURN_FALSE;
342 }
343
344 if (options & PHP_HASH_HMAC &&
345 key_len <= 0) {
346 /* Note: a zero length key is no key at all */
347 php_error_docref(NULL TSRMLS_CC, E_WARNING, "HMAC requested without a key");
348 RETURN_FALSE;
349 }
350
351 context = emalloc(ops->context_size);
352 ops->hash_init(context);
353
354 hash = emalloc(sizeof(php_hash_data));
355 hash->ops = ops;
356 hash->context = context;
357 hash->options = options;
358 hash->key = NULL;
359
360 if (options & PHP_HASH_HMAC) {
361 char *K = emalloc(ops->block_size);
362 int i;
363
364 memset(K, 0, ops->block_size);
365
366 if (key_len > ops->block_size) {
367 /* Reduce the key first */
368 ops->hash_update(context, (unsigned char *) key, key_len);
369 ops->hash_final((unsigned char *) K, context);
370 /* Make the context ready to start over */
371 ops->hash_init(context);
372 } else {
373 memcpy(K, key, key_len);
374 }
375
376 /* XOR ipad */
377 for(i=0; i < ops->block_size; i++) {
378 K[i] ^= 0x36;
379 }
380 ops->hash_update(context, (unsigned char *) K, ops->block_size);
381 hash->key = (unsigned char *) K;
382 }
383
384 ZEND_REGISTER_RESOURCE(return_value, hash, php_hash_le_hash);
385 }
386 /* }}} */
387
388 /* {{{ proto bool hash_update(resource context, string data)
389 Pump data into the hashing algorithm */
PHP_FUNCTION(hash_update)390 PHP_FUNCTION(hash_update)
391 {
392 zval *zhash;
393 php_hash_data *hash;
394 char *data;
395 int data_len;
396
397 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zhash, &data, &data_len) == FAILURE) {
398 return;
399 }
400
401 ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
402
403 hash->ops->hash_update(hash->context, (unsigned char *) data, data_len);
404
405 RETURN_TRUE;
406 }
407 /* }}} */
408
409 /* {{{ proto int hash_update_stream(resource context, resource handle[, integer length])
410 Pump data into the hashing algorithm from an open stream */
PHP_FUNCTION(hash_update_stream)411 PHP_FUNCTION(hash_update_stream)
412 {
413 zval *zhash, *zstream;
414 php_hash_data *hash;
415 php_stream *stream = NULL;
416 long length = -1, didread = 0;
417
418 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &zhash, &zstream, &length) == FAILURE) {
419 return;
420 }
421
422 ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
423 php_stream_from_zval(stream, &zstream);
424
425 while (length) {
426 char buf[1024];
427 long n, toread = 1024;
428
429 if (length > 0 && toread > length) {
430 toread = length;
431 }
432
433 if ((n = php_stream_read(stream, buf, toread)) <= 0) {
434 /* Nada mas */
435 RETURN_LONG(didread);
436 }
437 hash->ops->hash_update(hash->context, (unsigned char *) buf, n);
438 length -= n;
439 didread += n;
440 }
441
442 RETURN_LONG(didread);
443 }
444 /* }}} */
445
446 /* {{{ proto bool hash_update_file(resource context, string filename[, resource context])
447 Pump data into the hashing algorithm from a file */
PHP_FUNCTION(hash_update_file)448 PHP_FUNCTION(hash_update_file)
449 {
450 zval *zhash, *zcontext = NULL;
451 php_hash_data *hash;
452 php_stream_context *context;
453 php_stream *stream;
454 char *filename, buf[1024];
455 int filename_len, n;
456
457 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rp|r", &zhash, &filename, &filename_len, &zcontext) == FAILURE) {
458 return;
459 }
460
461 ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
462 context = php_stream_context_from_zval(zcontext, 0);
463
464 stream = php_stream_open_wrapper_ex(filename, "rb", REPORT_ERRORS, NULL, context);
465 if (!stream) {
466 /* Stream will report errors opening file */
467 RETURN_FALSE;
468 }
469
470 while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
471 hash->ops->hash_update(hash->context, (unsigned char *) buf, n);
472 }
473 php_stream_close(stream);
474
475 RETURN_TRUE;
476 }
477 /* }}} */
478
479 /* {{{ proto string hash_final(resource context[, bool raw_output=false])
480 Output resulting digest */
PHP_FUNCTION(hash_final)481 PHP_FUNCTION(hash_final)
482 {
483 zval *zhash;
484 php_hash_data *hash;
485 zend_bool raw_output = 0;
486 zend_rsrc_list_entry *le;
487 char *digest;
488 int digest_len;
489
490 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &zhash, &raw_output) == FAILURE) {
491 return;
492 }
493
494 ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
495
496 digest_len = hash->ops->digest_size;
497 digest = emalloc(digest_len + 1);
498 hash->ops->hash_final((unsigned char *) digest, hash->context);
499 if (hash->options & PHP_HASH_HMAC) {
500 int i;
501
502 /* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */
503 for(i=0; i < hash->ops->block_size; i++) {
504 hash->key[i] ^= 0x6A;
505 }
506
507 /* Feed this result into the outter hash */
508 hash->ops->hash_init(hash->context);
509 hash->ops->hash_update(hash->context, (unsigned char *) hash->key, hash->ops->block_size);
510 hash->ops->hash_update(hash->context, (unsigned char *) digest, hash->ops->digest_size);
511 hash->ops->hash_final((unsigned char *) digest, hash->context);
512
513 /* Zero the key */
514 memset(hash->key, 0, hash->ops->block_size);
515 efree(hash->key);
516 hash->key = NULL;
517 }
518 digest[digest_len] = 0;
519 efree(hash->context);
520 hash->context = NULL;
521
522 /* zend_list_REAL_delete() */
523 if (zend_hash_index_find(&EG(regular_list), Z_RESVAL_P(zhash), (void *) &le)==SUCCESS) {
524 /* This is a hack to avoid letting the resource hide elsewhere (like in separated vars)
525 FETCH_RESOURCE is intelligent enough to handle dealing with any issues this causes */
526 le->refcount = 1;
527 } /* FAILURE is not an option */
528 zend_list_delete(Z_RESVAL_P(zhash));
529
530 if (raw_output) {
531 RETURN_STRINGL(digest, digest_len, 0);
532 } else {
533 char *hex_digest = safe_emalloc(digest_len,2,1);
534
535 php_hash_bin2hex(hex_digest, (unsigned char *) digest, digest_len);
536 hex_digest[2 * digest_len] = 0;
537 efree(digest);
538 RETURN_STRINGL(hex_digest, 2 * digest_len, 0);
539 }
540 }
541 /* }}} */
542
543 /* {{{ proto resource hash_copy(resource context)
544 Copy hash resource */
PHP_FUNCTION(hash_copy)545 PHP_FUNCTION(hash_copy)
546 {
547 zval *zhash;
548 php_hash_data *hash, *copy_hash;
549 void *context;
550 int res;
551
552 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zhash) == FAILURE) {
553 return;
554 }
555
556 ZEND_FETCH_RESOURCE(hash, php_hash_data*, &zhash, -1, PHP_HASH_RESNAME, php_hash_le_hash);
557
558
559 context = emalloc(hash->ops->context_size);
560 hash->ops->hash_init(context);
561
562 res = hash->ops->hash_copy(hash->ops, hash->context, context);
563 if (res != SUCCESS) {
564 efree(context);
565 RETURN_FALSE;
566 }
567
568 copy_hash = emalloc(sizeof(php_hash_data));
569 copy_hash->ops = hash->ops;
570 copy_hash->context = context;
571 copy_hash->options = hash->options;
572 copy_hash->key = ecalloc(1, hash->ops->block_size);
573 if (hash->key) {
574 memcpy(copy_hash->key, hash->key, hash->ops->block_size);
575 }
576 ZEND_REGISTER_RESOURCE(return_value, copy_hash, php_hash_le_hash);
577 }
578 /* }}} */
579
580 /* {{{ proto array hash_algos(void)
581 Return a list of registered hashing algorithms */
PHP_FUNCTION(hash_algos)582 PHP_FUNCTION(hash_algos)
583 {
584 HashPosition pos;
585 char *str;
586 uint str_len;
587 long type;
588 ulong idx;
589
590 array_init(return_value);
591 for(zend_hash_internal_pointer_reset_ex(&php_hash_hashtable, &pos);
592 (type = zend_hash_get_current_key_ex(&php_hash_hashtable, &str, &str_len, &idx, 0, &pos)) != HASH_KEY_NON_EXISTANT;
593 zend_hash_move_forward_ex(&php_hash_hashtable, &pos)) {
594 add_next_index_stringl(return_value, str, str_len-1, 1);
595 }
596 }
597 /* }}} */
598
599 /* Module Housekeeping */
600
php_hash_dtor(zend_rsrc_list_entry * rsrc TSRMLS_DC)601 static void php_hash_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
602 {
603 php_hash_data *hash = (php_hash_data*)rsrc->ptr;
604
605 /* Just in case the algo has internally allocated resources */
606 if (hash->context) {
607 unsigned char *dummy = emalloc(hash->ops->digest_size);
608 hash->ops->hash_final(dummy, hash->context);
609 efree(dummy);
610 efree(hash->context);
611 }
612
613 if (hash->key) {
614 memset(hash->key, 0, hash->ops->block_size);
615 efree(hash->key);
616 }
617 efree(hash);
618 }
619 /* }}} */
620
621 #define PHP_HASH_HAVAL_REGISTER(p,b) php_hash_register_algo("haval" #b "," #p , &php_hash_##p##haval##b##_ops);
622
623 #ifdef PHP_MHASH_BC
624
PHP_MINFO_FUNCTION(mhash)625 PHP_MINFO_FUNCTION(mhash)
626 {
627 php_info_print_table_start();
628 php_info_print_table_row(2, "MHASH support", "Enabled");
629 php_info_print_table_row(2, "MHASH API Version", "Emulated Support");
630 php_info_print_table_end();
631 }
632
633 zend_module_entry mhash_module_entry = {
634 STANDARD_MODULE_HEADER,
635 "mhash",
636 NULL,
637 NULL,
638 NULL,
639 NULL,
640 NULL,
641 PHP_MINFO(mhash),
642 NO_VERSION_YET,
643 STANDARD_MODULE_PROPERTIES,
644 };
645
mhash_init(INIT_FUNC_ARGS)646 static void mhash_init(INIT_FUNC_ARGS)
647 {
648 char buf[128];
649 int len;
650 int algo_number = 0;
651
652 for (algo_number = 0; algo_number < MHASH_NUM_ALGOS; algo_number++) {
653 struct mhash_bc_entry algorithm = mhash_to_hash[algo_number];
654 if (algorithm.mhash_name == NULL) {
655 continue;
656 }
657
658 len = slprintf(buf, 127, "MHASH_%s", algorithm.mhash_name, strlen(algorithm.mhash_name));
659 zend_register_long_constant(buf, len + 1, algorithm.value, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
660 }
661 zend_register_internal_module(&mhash_module_entry TSRMLS_CC);
662 }
663
664 /* {{{ proto string mhash(int hash, string data [, string key])
665 Hash data with hash */
PHP_FUNCTION(mhash)666 PHP_FUNCTION(mhash)
667 {
668 zval **z_algorithm;
669 long algorithm;
670
671 if (zend_parse_parameters(1 TSRMLS_CC, "Z", &z_algorithm) == FAILURE) {
672 return;
673 }
674
675 SEPARATE_ZVAL(z_algorithm);
676 convert_to_long_ex(z_algorithm);
677 algorithm = Z_LVAL_PP(z_algorithm);
678
679 /* need to convert the first parameter from int constant to string algorithm name */
680 if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
681 struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
682 if (algorithm_lookup.hash_name) {
683 ZVAL_STRING(*z_algorithm, algorithm_lookup.hash_name, 1);
684 }
685 }
686
687 if (ZEND_NUM_ARGS() == 3) {
688 php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
689 } else if (ZEND_NUM_ARGS() == 2) {
690 php_hash_do_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
691 } else {
692 WRONG_PARAM_COUNT;
693 }
694 }
695 /* }}} */
696
697 /* {{{ proto string mhash_get_hash_name(int hash)
698 Gets the name of hash */
PHP_FUNCTION(mhash_get_hash_name)699 PHP_FUNCTION(mhash_get_hash_name)
700 {
701 long algorithm;
702
703 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &algorithm) == FAILURE) {
704 return;
705 }
706
707 if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
708 struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
709 if (algorithm_lookup.mhash_name) {
710 RETURN_STRING(algorithm_lookup.mhash_name, 1);
711 }
712 }
713 RETURN_FALSE;
714 }
715 /* }}} */
716
717 /* {{{ proto int mhash_count(void)
718 Gets the number of available hashes */
PHP_FUNCTION(mhash_count)719 PHP_FUNCTION(mhash_count)
720 {
721 if (zend_parse_parameters_none() == FAILURE) {
722 return;
723 }
724 RETURN_LONG(MHASH_NUM_ALGOS - 1);
725 }
726 /* }}} */
727
728 /* {{{ proto int mhash_get_block_size(int hash)
729 Gets the block size of hash */
PHP_FUNCTION(mhash_get_block_size)730 PHP_FUNCTION(mhash_get_block_size)
731 {
732 long algorithm;
733
734 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &algorithm) == FAILURE) {
735 return;
736 }
737 RETVAL_FALSE;
738
739 if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
740 struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
741 if (algorithm_lookup.mhash_name) {
742 const php_hash_ops *ops = php_hash_fetch_ops(algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
743 if (ops) {
744 RETVAL_LONG(ops->digest_size);
745 }
746 }
747 }
748 }
749 /* }}} */
750
751 #define SALT_SIZE 8
752
753 /* {{{ proto string mhash_keygen_s2k(int hash, string input_password, string salt, int bytes)
754 Generates a key using hash functions */
PHP_FUNCTION(mhash_keygen_s2k)755 PHP_FUNCTION(mhash_keygen_s2k)
756 {
757 long algorithm, l_bytes;
758 int bytes;
759 char *password, *salt;
760 int password_len, salt_len;
761 char padded_salt[SALT_SIZE];
762
763 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lssl", &algorithm, &password, &password_len, &salt, &salt_len, &l_bytes) == FAILURE) {
764 return;
765 }
766
767 bytes = (int)l_bytes;
768 if (bytes <= 0){
769 php_error_docref(NULL TSRMLS_CC, E_WARNING, "the byte parameter must be greater than 0");
770 RETURN_FALSE;
771 }
772
773 salt_len = MIN(salt_len, SALT_SIZE);
774
775 memcpy(padded_salt, salt, salt_len);
776 if (salt_len < SALT_SIZE) {
777 memset(padded_salt + salt_len, 0, SALT_SIZE - salt_len);
778 }
779 salt_len = SALT_SIZE;
780
781 RETVAL_FALSE;
782 if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
783 struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
784 if (algorithm_lookup.mhash_name) {
785 const php_hash_ops *ops = php_hash_fetch_ops(algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
786 if (ops) {
787 unsigned char null = '\0';
788 void *context;
789 char *key, *digest;
790 int i = 0, j = 0;
791 int block_size = ops->digest_size;
792 int times = bytes / block_size;
793 if (bytes % block_size != 0) times++;
794
795 context = emalloc(ops->context_size);
796 ops->hash_init(context);
797
798 key = ecalloc(1, times * block_size);
799 digest = emalloc(ops->digest_size + 1);
800
801 for (i = 0; i < times; i++) {
802 ops->hash_init(context);
803
804 for (j=0;j<i;j++) {
805 ops->hash_update(context, &null, 1);
806 }
807 ops->hash_update(context, (unsigned char *)padded_salt, salt_len);
808 ops->hash_update(context, (unsigned char *)password, password_len);
809 ops->hash_final((unsigned char *)digest, context);
810 memcpy( &key[i*block_size], digest, block_size);
811 }
812
813 RETVAL_STRINGL(key, bytes, 1);
814 memset(key, 0, bytes);
815 efree(digest);
816 efree(context);
817 efree(key);
818 }
819 }
820 }
821 }
822 /* }}} */
823
824 #endif
825
826 /* {{{ PHP_MINIT_FUNCTION
827 */
PHP_MINIT_FUNCTION(hash)828 PHP_MINIT_FUNCTION(hash)
829 {
830 php_hash_le_hash = zend_register_list_destructors_ex(php_hash_dtor, NULL, PHP_HASH_RESNAME, module_number);
831
832 zend_hash_init(&php_hash_hashtable, 35, NULL, NULL, 1);
833
834 php_hash_register_algo("md2", &php_hash_md2_ops);
835 php_hash_register_algo("md4", &php_hash_md4_ops);
836 php_hash_register_algo("md5", &php_hash_md5_ops);
837 php_hash_register_algo("sha1", &php_hash_sha1_ops);
838 php_hash_register_algo("sha224", &php_hash_sha224_ops);
839 php_hash_register_algo("sha256", &php_hash_sha256_ops);
840 php_hash_register_algo("sha384", &php_hash_sha384_ops);
841 php_hash_register_algo("sha512", &php_hash_sha512_ops);
842 php_hash_register_algo("ripemd128", &php_hash_ripemd128_ops);
843 php_hash_register_algo("ripemd160", &php_hash_ripemd160_ops);
844 php_hash_register_algo("ripemd256", &php_hash_ripemd256_ops);
845 php_hash_register_algo("ripemd320", &php_hash_ripemd320_ops);
846 php_hash_register_algo("whirlpool", &php_hash_whirlpool_ops);
847 php_hash_register_algo("tiger128,3", &php_hash_3tiger128_ops);
848 php_hash_register_algo("tiger160,3", &php_hash_3tiger160_ops);
849 php_hash_register_algo("tiger192,3", &php_hash_3tiger192_ops);
850 php_hash_register_algo("tiger128,4", &php_hash_4tiger128_ops);
851 php_hash_register_algo("tiger160,4", &php_hash_4tiger160_ops);
852 php_hash_register_algo("tiger192,4", &php_hash_4tiger192_ops);
853 php_hash_register_algo("snefru", &php_hash_snefru_ops);
854 php_hash_register_algo("snefru256", &php_hash_snefru_ops);
855 php_hash_register_algo("gost", &php_hash_gost_ops);
856 php_hash_register_algo("adler32", &php_hash_adler32_ops);
857 php_hash_register_algo("crc32", &php_hash_crc32_ops);
858 php_hash_register_algo("crc32b", &php_hash_crc32b_ops);
859 php_hash_register_algo("fnv132", &php_hash_fnv132_ops);
860 php_hash_register_algo("fnv164", &php_hash_fnv164_ops);
861 php_hash_register_algo("joaat", &php_hash_joaat_ops);
862
863 PHP_HASH_HAVAL_REGISTER(3,128);
864 PHP_HASH_HAVAL_REGISTER(3,160);
865 PHP_HASH_HAVAL_REGISTER(3,192);
866 PHP_HASH_HAVAL_REGISTER(3,224);
867 PHP_HASH_HAVAL_REGISTER(3,256);
868
869 PHP_HASH_HAVAL_REGISTER(4,128);
870 PHP_HASH_HAVAL_REGISTER(4,160);
871 PHP_HASH_HAVAL_REGISTER(4,192);
872 PHP_HASH_HAVAL_REGISTER(4,224);
873 PHP_HASH_HAVAL_REGISTER(4,256);
874
875 PHP_HASH_HAVAL_REGISTER(5,128);
876 PHP_HASH_HAVAL_REGISTER(5,160);
877 PHP_HASH_HAVAL_REGISTER(5,192);
878 PHP_HASH_HAVAL_REGISTER(5,224);
879 PHP_HASH_HAVAL_REGISTER(5,256);
880
881 REGISTER_LONG_CONSTANT("HASH_HMAC", PHP_HASH_HMAC, CONST_CS | CONST_PERSISTENT);
882
883 #ifdef PHP_MHASH_BC
884 mhash_init(INIT_FUNC_ARGS_PASSTHRU);
885 #endif
886
887 return SUCCESS;
888 }
889 /* }}} */
890
891 /* {{{ PHP_MSHUTDOWN_FUNCTION
892 */
PHP_MSHUTDOWN_FUNCTION(hash)893 PHP_MSHUTDOWN_FUNCTION(hash)
894 {
895 zend_hash_destroy(&php_hash_hashtable);
896
897 return SUCCESS;
898 }
899 /* }}} */
900
901 /* {{{ PHP_MINFO_FUNCTION
902 */
PHP_MINFO_FUNCTION(hash)903 PHP_MINFO_FUNCTION(hash)
904 {
905 HashPosition pos;
906 char buffer[2048];
907 char *s = buffer, *e = s + sizeof(buffer), *str;
908 ulong idx;
909 long type;
910
911 for(zend_hash_internal_pointer_reset_ex(&php_hash_hashtable, &pos);
912 (type = zend_hash_get_current_key_ex(&php_hash_hashtable, &str, NULL, &idx, 0, &pos)) != HASH_KEY_NON_EXISTANT;
913 zend_hash_move_forward_ex(&php_hash_hashtable, &pos)) {
914 s += slprintf(s, e - s, "%s ", str);
915 }
916 *s = 0;
917
918 php_info_print_table_start();
919 php_info_print_table_row(2, "hash support", "enabled");
920 php_info_print_table_row(2, "Hashing Engines", buffer);
921 php_info_print_table_end();
922 }
923 /* }}} */
924
925 /* {{{ arginfo */
926 #ifdef PHP_HASH_MD5_NOT_IN_CORE
927 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_md5, 0, 0, 1)
928 ZEND_ARG_INFO(0, str)
929 ZEND_ARG_INFO(0, raw_output)
930 ZEND_END_ARG_INFO()
931
932 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_md5_file, 0, 0, 1)
933 ZEND_ARG_INFO(0, filename)
934 ZEND_ARG_INFO(0, raw_output)
935 ZEND_END_ARG_INFO()
936 #endif
937
938 #ifdef PHP_HASH_SHA1_NOT_IN_CORE
939 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_sha1, 0, 0, 1)
940 ZEND_ARG_INFO(0, str)
941 ZEND_ARG_INFO(0, raw_output)
942 ZEND_END_ARG_INFO()
943
944 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_sha1_file, 0, 0, 1)
945 ZEND_ARG_INFO(0, filename)
946 ZEND_ARG_INFO(0, raw_output)
947 ZEND_END_ARG_INFO()
948 #endif
949
950 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash, 0, 0, 2)
951 ZEND_ARG_INFO(0, algo)
952 ZEND_ARG_INFO(0, data)
953 ZEND_ARG_INFO(0, raw_output)
954 ZEND_END_ARG_INFO()
955
956 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_file, 0, 0, 2)
957 ZEND_ARG_INFO(0, algo)
958 ZEND_ARG_INFO(0, filename)
959 ZEND_ARG_INFO(0, raw_output)
960 ZEND_END_ARG_INFO()
961
962 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_hmac, 0, 0, 3)
963 ZEND_ARG_INFO(0, algo)
964 ZEND_ARG_INFO(0, data)
965 ZEND_ARG_INFO(0, key)
966 ZEND_ARG_INFO(0, raw_output)
967 ZEND_END_ARG_INFO()
968
969 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_hmac_file, 0, 0, 3)
970 ZEND_ARG_INFO(0, algo)
971 ZEND_ARG_INFO(0, filename)
972 ZEND_ARG_INFO(0, key)
973 ZEND_ARG_INFO(0, raw_output)
974 ZEND_END_ARG_INFO()
975
976 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_init, 0, 0, 1)
977 ZEND_ARG_INFO(0, algo)
978 ZEND_ARG_INFO(0, options)
979 ZEND_ARG_INFO(0, key)
980 ZEND_END_ARG_INFO()
981
982 ZEND_BEGIN_ARG_INFO(arginfo_hash_update, 0)
983 ZEND_ARG_INFO(0, context)
984 ZEND_ARG_INFO(0, data)
985 ZEND_END_ARG_INFO()
986
987 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_update_stream, 0, 0, 2)
988 ZEND_ARG_INFO(0, context)
989 ZEND_ARG_INFO(0, handle)
990 ZEND_ARG_INFO(0, length)
991 ZEND_END_ARG_INFO()
992
993 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_update_file, 0, 0, 2)
994 ZEND_ARG_INFO(0, context)
995 ZEND_ARG_INFO(0, filename)
996 ZEND_ARG_INFO(0, context)
997 ZEND_END_ARG_INFO()
998
999 ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_final, 0, 0, 1)
1000 ZEND_ARG_INFO(0, context)
1001 ZEND_ARG_INFO(0, raw_output)
1002 ZEND_END_ARG_INFO()
1003
1004 ZEND_BEGIN_ARG_INFO(arginfo_hash_copy, 0)
1005 ZEND_ARG_INFO(0, context)
1006 ZEND_END_ARG_INFO()
1007
1008 ZEND_BEGIN_ARG_INFO(arginfo_hash_algos, 0)
1009 ZEND_END_ARG_INFO()
1010
1011 /* BC Land */
1012 #ifdef PHP_MHASH_BC
1013 ZEND_BEGIN_ARG_INFO(arginfo_mhash_get_block_size, 0)
1014 ZEND_ARG_INFO(0, hash)
1015 ZEND_END_ARG_INFO()
1016
1017 ZEND_BEGIN_ARG_INFO(arginfo_mhash_get_hash_name, 0)
1018 ZEND_ARG_INFO(0, hash)
1019 ZEND_END_ARG_INFO()
1020
1021 ZEND_BEGIN_ARG_INFO(arginfo_mhash_keygen_s2k, 0)
1022 ZEND_ARG_INFO(0, hash)
1023 ZEND_ARG_INFO(0, input_password)
1024 ZEND_ARG_INFO(0, salt)
1025 ZEND_ARG_INFO(0, bytes)
1026 ZEND_END_ARG_INFO()
1027
1028 ZEND_BEGIN_ARG_INFO(arginfo_mhash_count, 0)
1029 ZEND_END_ARG_INFO()
1030
1031 ZEND_BEGIN_ARG_INFO_EX(arginfo_mhash, 0, 0, 2)
1032 ZEND_ARG_INFO(0, hash)
1033 ZEND_ARG_INFO(0, data)
1034 ZEND_ARG_INFO(0, key)
1035 ZEND_END_ARG_INFO()
1036 #endif
1037
1038 /* }}} */
1039
1040 /* {{{ hash_functions[]
1041 */
1042 const zend_function_entry hash_functions[] = {
1043 PHP_FE(hash, arginfo_hash)
1044 PHP_FE(hash_file, arginfo_hash_file)
1045
1046 PHP_FE(hash_hmac, arginfo_hash_hmac)
1047 PHP_FE(hash_hmac_file, arginfo_hash_hmac_file)
1048
1049 PHP_FE(hash_init, arginfo_hash_init)
1050 PHP_FE(hash_update, arginfo_hash_update)
1051 PHP_FE(hash_update_stream, arginfo_hash_update_stream)
1052 PHP_FE(hash_update_file, arginfo_hash_update_file)
1053 PHP_FE(hash_final, arginfo_hash_final)
1054 PHP_FE(hash_copy, arginfo_hash_copy)
1055
1056 PHP_FE(hash_algos, arginfo_hash_algos)
1057
1058 /* BC Land */
1059 #ifdef PHP_HASH_MD5_NOT_IN_CORE
1060 PHP_NAMED_FE(md5, php_if_md5, arginfo_hash_md5)
1061 PHP_NAMED_FE(md5_file, php_if_md5_file, arginfo_hash_md5_file)
1062 #endif /* PHP_HASH_MD5_NOT_IN_CORE */
1063
1064 #ifdef PHP_HASH_SHA1_NOT_IN_CORE
1065 PHP_NAMED_FE(sha1, php_if_sha1, arginfo_hash_sha1)
1066 PHP_NAMED_FE(sha1_file, php_if_sha1_file, arginfo_hash_sha1_file)
1067 #endif /* PHP_HASH_SHA1_NOT_IN_CORE */
1068
1069 #ifdef PHP_MHASH_BC
1070 PHP_FE(mhash_keygen_s2k, arginfo_mhash_keygen_s2k)
1071 PHP_FE(mhash_get_block_size, arginfo_mhash_get_block_size)
1072 PHP_FE(mhash_get_hash_name, arginfo_mhash_get_hash_name)
1073 PHP_FE(mhash_count, arginfo_mhash_count)
1074 PHP_FE(mhash, arginfo_mhash)
1075 #endif
1076
1077 PHP_FE_END
1078 };
1079 /* }}} */
1080
1081 /* {{{ hash_module_entry
1082 */
1083 zend_module_entry hash_module_entry = {
1084 #if ZEND_MODULE_API_NO >= 20010901
1085 STANDARD_MODULE_HEADER,
1086 #endif
1087 PHP_HASH_EXTNAME,
1088 hash_functions,
1089 PHP_MINIT(hash),
1090 PHP_MSHUTDOWN(hash),
1091 NULL, /* RINIT */
1092 NULL, /* RSHUTDOWN */
1093 PHP_MINFO(hash),
1094 #if ZEND_MODULE_API_NO >= 20010901
1095 PHP_HASH_EXTVER, /* Replace with version number for your extension */
1096 #endif
1097 STANDARD_MODULE_PROPERTIES
1098 };
1099 /* }}} */
1100
1101 #ifdef COMPILE_DL_HASH
1102 ZEND_GET_MODULE(hash)
1103 #endif
1104
1105 /*
1106 * Local variables:
1107 * tab-width: 4
1108 * c-basic-offset: 4
1109 * End:
1110 * vim600: noet sw=4 ts=4 fdm=marker
1111 * vim<600: noet sw=4 ts=4
1112 */
1113