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