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