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