Skip to content

Commit 110b4e9

Browse files
committed
hash: Support custom algo parameters
The concrete need on this change is to support passing an initial seed to the murmur hash. Passing a custom seed is important in terms of randomizing the hash function. The suggested implementation adds a HashTable parameter to all the init callbacks. Further on, an array with custom arguments is accepted from `hash` or `hash_init` from the user land. Currently several things like `hash_hkdf` are not touched, as they don't need passing custom args. Some convenience macros have been added to the SHA/MD families of functions, so the consuming code doesn't have to be changed widely. Another way to implement this is to add another type of the init that would accept a HT with arguments. However, that would still require touching all the context structs in all the algos. That would also increase the size of those structs. As an init function is called just once, the way of modifying the existing init callback has been seen as more preferrable. Closes GH-6400. Signed-off-by: Anatol Belski <ab@php.net> Co-Developed-by: Nikita Popov <nikita.ppv@googlemail.com> Signed-off-by: Nikita Popov <nikita.ppv@googlemail.com> Acked-by: Michael Wallner <mike@php.net> Reviewed-by: Máté Kocsis <kocsismate@woohoolabs.com> Reviewed-by: Eddie Kohler <ekohler@gmail.com>
1 parent 70c22de commit 110b4e9

37 files changed

+220
-110
lines changed

ext/hash/hash.c

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ PHP_HASH_API int php_hash_unserialize(php_hashcontext_object *hash, zend_long ma
349349
/* Userspace */
350350

351351
static void php_hash_do_hash(
352-
zval *return_value, zend_string *algo, char *data, size_t data_len, zend_bool raw_output, bool isfilename
352+
zval *return_value, zend_string *algo, char *data, size_t data_len, zend_bool raw_output, bool isfilename, HashTable *args
353353
) /* {{{ */ {
354354
zend_string *digest;
355355
const php_hash_ops *ops;
@@ -374,7 +374,7 @@ static void php_hash_do_hash(
374374
}
375375

376376
context = php_hash_alloc_context(ops);
377-
ops->hash_init(context);
377+
ops->hash_init(context, args);
378378

379379
if (isfilename) {
380380
char buf[1024];
@@ -418,15 +418,17 @@ PHP_FUNCTION(hash)
418418
char *data;
419419
size_t data_len;
420420
zend_bool raw_output = 0;
421+
HashTable *args = NULL;
421422

422-
ZEND_PARSE_PARAMETERS_START(2, 3)
423+
ZEND_PARSE_PARAMETERS_START(2, 4)
423424
Z_PARAM_STR(algo)
424425
Z_PARAM_STRING(data, data_len)
425426
Z_PARAM_OPTIONAL
426427
Z_PARAM_BOOL(raw_output)
428+
Z_PARAM_ARRAY_HT(args)
427429
ZEND_PARSE_PARAMETERS_END();
428430

429-
php_hash_do_hash(return_value, algo, data, data_len, raw_output, 0);
431+
php_hash_do_hash(return_value, algo, data, data_len, raw_output, 0, args);
430432
}
431433
/* }}} */
432434

@@ -438,15 +440,17 @@ PHP_FUNCTION(hash_file)
438440
char *data;
439441
size_t data_len;
440442
zend_bool raw_output = 0;
443+
HashTable *args = NULL;
441444

442445
ZEND_PARSE_PARAMETERS_START(2, 3)
443446
Z_PARAM_STR(algo)
444447
Z_PARAM_STRING(data, data_len)
445448
Z_PARAM_OPTIONAL
446449
Z_PARAM_BOOL(raw_output)
450+
Z_PARAM_ARRAY_HT(args)
447451
ZEND_PARSE_PARAMETERS_END();
448452

449-
php_hash_do_hash(return_value, algo, data, data_len, raw_output, 1);
453+
php_hash_do_hash(return_value, algo, data, data_len, raw_output, 1, args);
450454
}
451455
/* }}} */
452456

@@ -468,7 +472,7 @@ static inline void php_hash_hmac_prep_key(unsigned char *K, const php_hash_ops *
468472
memset(K, 0, ops->block_size);
469473
if (key_len > ops->block_size) {
470474
/* Reduce the key first */
471-
ops->hash_init(context);
475+
ops->hash_init(context, NULL);
472476
ops->hash_update(context, key, key_len);
473477
ops->hash_final(K, context);
474478
} else {
@@ -479,7 +483,7 @@ static inline void php_hash_hmac_prep_key(unsigned char *K, const php_hash_ops *
479483
}
480484

481485
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 zend_long data_size) {
482-
ops->hash_init(context);
486+
ops->hash_init(context, NULL);
483487
ops->hash_update(context, key, ops->block_size);
484488
ops->hash_update(context, data, data_size);
485489
ops->hash_final(final, context);
@@ -522,7 +526,7 @@ static void php_hash_do_hash_hmac(
522526
if (isfilename) {
523527
char buf[1024];
524528
ssize_t n;
525-
ops->hash_init(context);
529+
ops->hash_init(context, NULL);
526530
ops->hash_update(context, K, ops->block_size);
527531
while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
528532
ops->hash_update(context, (unsigned char *) buf, n);
@@ -605,8 +609,9 @@ PHP_FUNCTION(hash_init)
605609
void *context;
606610
const php_hash_ops *ops;
607611
php_hashcontext_object *hash;
612+
HashTable *args = NULL;
608613

609-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|lS", &algo, &options, &key) == FAILURE) {
614+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|lSh", &algo, &options, &key, &args) == FAILURE) {
610615
RETURN_THROWS();
611616
}
612617

@@ -632,7 +637,7 @@ PHP_FUNCTION(hash_init)
632637
hash = php_hashcontext_from_object(Z_OBJ_P(return_value));
633638

634639
context = php_hash_alloc_context(ops);
635-
ops->hash_init(context);
640+
ops->hash_init(context, args);
636641

637642
hash->ops = ops;
638643
hash->context = context;
@@ -650,7 +655,7 @@ PHP_FUNCTION(hash_init)
650655
ops->hash_update(context, (unsigned char *) ZSTR_VAL(key), ZSTR_LEN(key));
651656
ops->hash_final((unsigned char *) K, context);
652657
/* Make the context ready to start over */
653-
ops->hash_init(context);
658+
ops->hash_init(context, args);
654659
} else {
655660
memcpy(K, ZSTR_VAL(key), ZSTR_LEN(key));
656661
}
@@ -792,7 +797,7 @@ PHP_FUNCTION(hash_final)
792797
}
793798

794799
/* Feed this result into the outer hash */
795-
hash->ops->hash_init(hash->context);
800+
hash->ops->hash_init(hash->context, NULL);
796801
hash->ops->hash_update(hash->context, hash->key, hash->ops->block_size);
797802
hash->ops->hash_update(hash->context, (unsigned char *) ZSTR_VAL(digest), hash->ops->digest_size);
798803
hash->ops->hash_final((unsigned char *) ZSTR_VAL(digest), hash->context);
@@ -915,7 +920,7 @@ PHP_FUNCTION(hash_hkdf)
915920
context = php_hash_alloc_context(ops);
916921

917922
// Extract
918-
ops->hash_init(context);
923+
ops->hash_init(context, NULL);
919924
K = emalloc(ops->block_size);
920925
php_hash_hmac_prep_key(K, ops, context,
921926
(unsigned char *) (salt ? ZSTR_VAL(salt) : ""), salt ? ZSTR_LEN(salt) : 0);
@@ -935,7 +940,7 @@ PHP_FUNCTION(hash_hkdf)
935940
c[0] = (i & 0xFF);
936941

937942
php_hash_hmac_prep_key(K, ops, context, prk, ops->digest_size);
938-
ops->hash_init(context);
943+
ops->hash_init(context, NULL);
939944
ops->hash_update(context, K, ops->block_size);
940945

941946
if (i > 1) {
@@ -980,8 +985,9 @@ PHP_FUNCTION(hash_pbkdf2)
980985
zend_bool raw_output = 0;
981986
const php_hash_ops *ops;
982987
void *context;
988+
HashTable *args;
983989

984-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|lb", &algo, &pass, &pass_len, &salt, &salt_len, &iterations, &length, &raw_output) == FAILURE) {
990+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|lbh", &algo, &pass, &pass_len, &salt, &salt_len, &iterations, &length, &raw_output, &args) == FAILURE) {
985991
RETURN_THROWS();
986992
}
987993

@@ -1007,7 +1013,7 @@ PHP_FUNCTION(hash_pbkdf2)
10071013
}
10081014

10091015
context = php_hash_alloc_context(ops);
1010-
ops->hash_init(context);
1016+
ops->hash_init(context, args);
10111017

10121018
K1 = emalloc(ops->block_size);
10131019
K2 = emalloc(ops->block_size);
@@ -1212,7 +1218,7 @@ PHP_FUNCTION(mhash)
12121218
if (key) {
12131219
php_hash_do_hash_hmac(return_value, algo, data, data_len, key, key_len, 1, 0);
12141220
} else {
1215-
php_hash_do_hash(return_value, algo, data, data_len, 1, 0);
1221+
php_hash_do_hash(return_value, algo, data, data_len, 1, 0, NULL);
12161222
}
12171223

12181224
if (algo) {
@@ -1319,13 +1325,13 @@ PHP_FUNCTION(mhash_keygen_s2k)
13191325
}
13201326

13211327
context = php_hash_alloc_context(ops);
1322-
ops->hash_init(context);
1328+
ops->hash_init(context, NULL);
13231329

13241330
key = ecalloc(1, times * block_size);
13251331
digest = emalloc(ops->digest_size + 1);
13261332

13271333
for (i = 0; i < times; i++) {
1328-
ops->hash_init(context);
1334+
ops->hash_init(context, NULL);
13291335

13301336
for (j=0;j<i;j++) {
13311337
ops->hash_update(context, &null, 1);
@@ -1392,7 +1398,7 @@ static zend_object *php_hashcontext_clone(zend_object *zobj) {
13921398
newobj->ops = oldobj->ops;
13931399
newobj->options = oldobj->options;
13941400
newobj->context = php_hash_alloc_context(newobj->ops);
1395-
newobj->ops->hash_init(newobj->context);
1401+
newobj->ops->hash_init(newobj->context, NULL);
13961402

13971403
if (SUCCESS != newobj->ops->hash_copy(newobj->ops, oldobj->context, newobj->context)) {
13981404
efree(newobj->context);
@@ -1529,8 +1535,8 @@ PHP_METHOD(HashContext, __unserialize)
15291535

15301536
hash->ops = ops;
15311537
hash->context = php_hash_alloc_context(ops);
1532-
ops->hash_init(hash->context);
15331538
hash->options = options;
1539+
ops->hash_init(hash->context, NULL);
15341540

15351541
unserialize_result = ops->hash_unserialize(hash, magic, hash_zv);
15361542
if (unserialize_result != SUCCESS) {

ext/hash/hash.stub.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
/** @generate-function-entries */
44

5-
function hash(string $algo, string $data, bool $binary = false): string|false {}
5+
function hash(string $algo, string $data, bool $binary = false, array $options = []): string|false {}
66

7-
function hash_file(string $algo, string $filename, bool $binary = false): string|false {}
7+
function hash_file(string $algo, string $filename, bool $binary = false, array $options = []): string|false {}
88

99
function hash_hmac(string $algo, string $data, string $key, bool $binary = false): string|false {}
1010

1111
function hash_hmac_file(string $algo, string $data, string $key, bool $binary = false): string|false {}
1212

13-
function hash_init(string $algo, int $flags = 0, string $key = ""): HashContext {}
13+
function hash_init(string $algo, int $flags = 0, string $key = "", array $options = []): HashContext {}
1414

1515
function hash_update(HashContext $context, string $data): bool {}
1616

ext/hash/hash_adler32.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include "php_hash.h"
1919
#include "php_hash_adler32.h"
2020

21-
PHP_HASH_API void PHP_ADLER32Init(PHP_ADLER32_CTX *context)
21+
PHP_HASH_API void PHP_ADLER32Init(PHP_ADLER32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
2222
{
2323
context->state = 1;
2424
}

ext/hash/hash_arginfo.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 9352e0ac98e2ac53dc15d5024f9ef0c8092c4e9c */
2+
* Stub hash: e8466049fca2eae179adbc19bb67e71f6486ec4e */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_hash, 0, 2, MAY_BE_STRING|MAY_BE_FALSE)
55
ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0)
66
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
77
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, binary, _IS_BOOL, 0, "false")
8+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
89
ZEND_END_ARG_INFO()
910

1011
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_hash_file, 0, 2, MAY_BE_STRING|MAY_BE_FALSE)
1112
ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0)
1213
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
1314
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, binary, _IS_BOOL, 0, "false")
15+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
1416
ZEND_END_ARG_INFO()
1517

1618
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_hash_hmac, 0, 3, MAY_BE_STRING|MAY_BE_FALSE)
@@ -26,6 +28,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_hash_init, 0, 1, HashContext, 0)
2628
ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0)
2729
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
2830
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, key, IS_STRING, 0, "\"\"")
31+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
2932
ZEND_END_ARG_INFO()
3033

3134
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_hash_update, 0, 2, _IS_BOOL, 0)

ext/hash/hash_crc32.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "php_hash_crc32_tables.h"
2121
#include "ext/standard/crc32_x86.h"
2222

23-
PHP_HASH_API void PHP_CRC32Init(PHP_CRC32_CTX *context)
23+
PHP_HASH_API void PHP_CRC32Init(PHP_CRC32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
2424
{
2525
context->state = ~0;
2626
}

ext/hash/hash_fnv.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const php_hash_ops php_hash_fnv1a64_ops = {
8383
/* {{{ PHP_FNV132Init
8484
* 32-bit FNV-1 hash initialisation
8585
*/
86-
PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context)
86+
PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
8787
{
8888
context->state = PHP_FNV1_32_INIT;
8989
}
@@ -118,7 +118,7 @@ PHP_HASH_API void PHP_FNV132Final(unsigned char digest[4], PHP_FNV132_CTX * cont
118118
/* {{{ PHP_FNV164Init
119119
* 64-bit FNV-1 hash initialisation
120120
*/
121-
PHP_HASH_API void PHP_FNV164Init(PHP_FNV164_CTX *context)
121+
PHP_HASH_API void PHP_FNV164Init(PHP_FNV164_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
122122
{
123123
context->state = PHP_FNV1_64_INIT;
124124
}

ext/hash/hash_gost.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,15 @@ static inline void GostTransform(PHP_GOST_CTX *context, const unsigned char inpu
235235
Gost(context, data);
236236
}
237237

238-
PHP_HASH_API void PHP_GOSTInit(PHP_GOST_CTX *context)
238+
PHP_HASH_API void PHP_GOSTInit(PHP_GOST_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
239239
{
240240
memset(context, 0, sizeof(*context));
241241
context->tables = &tables_test;
242242
}
243243

244-
PHP_HASH_API void PHP_GOSTInitCrypto(PHP_GOST_CTX *context)
244+
PHP_HASH_API void PHP_GOSTInitCrypto(PHP_GOST_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
245245
{
246-
PHP_GOSTInit(context);
246+
PHP_GOSTInit(context, NULL);
247247
context->tables = &tables_crypto;
248248
}
249249

ext/hash/hash_haval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ const php_hash_ops php_hash_##p##haval##b##_ops = { \
253253
php_hash_unserialize, \
254254
PHP_HAVAL_SPEC, \
255255
((b) / 8), 128, sizeof(PHP_HAVAL_CTX), 1 }; \
256-
PHP_HASH_API void PHP_##p##HAVAL##b##Init(PHP_HAVAL_CTX *context) \
256+
PHP_HASH_API void PHP_##p##HAVAL##b##Init(PHP_HAVAL_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) \
257257
{ int i; context->count[0] = context->count[1] = 0; \
258258
for(i = 0; i < 8; i++) context->state[i] = D0[i]; \
259259
context->passes = p; context->output = b; \

ext/hash/hash_joaat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const php_hash_ops php_hash_joaat_ops = {
3636
0
3737
};
3838

39-
PHP_HASH_API void PHP_JOAATInit(PHP_JOAAT_CTX *context)
39+
PHP_HASH_API void PHP_JOAATInit(PHP_JOAAT_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
4040
{
4141
context->state = 0;
4242
}

ext/hash/hash_md.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
const php_hash_ops php_hash_md5_ops = {
2121
"md5",
22-
(php_hash_init_func_t) PHP_MD5Init,
22+
(php_hash_init_func_t) PHP_MD5InitArgs,
2323
(php_hash_update_func_t) PHP_MD5Update,
2424
(php_hash_final_func_t) PHP_MD5Final,
2525
php_hash_copy,
@@ -34,7 +34,7 @@ const php_hash_ops php_hash_md5_ops = {
3434

3535
const php_hash_ops php_hash_md4_ops = {
3636
"md4",
37-
(php_hash_init_func_t) PHP_MD4Init,
37+
(php_hash_init_func_t) PHP_MD4InitArgs,
3838
(php_hash_update_func_t) PHP_MD4Update,
3939
(php_hash_final_func_t) PHP_MD4Final,
4040
php_hash_copy,
@@ -51,7 +51,7 @@ static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, co
5151

5252
const php_hash_ops php_hash_md2_ops = {
5353
"md2",
54-
(php_hash_init_func_t) PHP_MD2Init,
54+
(php_hash_init_func_t) PHP_MD2InitArgs,
5555
(php_hash_update_func_t) PHP_MD2Update,
5656
(php_hash_final_func_t) PHP_MD2Final,
5757
php_hash_copy,
@@ -182,10 +182,10 @@ static void MD4Transform(uint32_t state[4], const unsigned char block[64])
182182
state[3] += d;
183183
}
184184

185-
/* {{{ PHP_MD4Init
185+
/* {{{ PHP_MD4InitArgs
186186
* MD4 initialization. Begins an MD4 operation, writing a new context.
187187
*/
188-
PHP_HASH_API void PHP_MD4Init(PHP_MD4_CTX * context)
188+
PHP_HASH_API void PHP_MD4InitArgs(PHP_MD4_CTX * context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
189189
{
190190
context->count[0] = context->count[1] = 0;
191191
/* Load magic initialization constants.
@@ -287,7 +287,7 @@ static const unsigned char MD2_S[256] = {
287287
242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
288288
49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
289289

290-
PHP_HASH_API void PHP_MD2Init(PHP_MD2_CTX *context)
290+
PHP_HASH_API void PHP_MD2InitArgs(PHP_MD2_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
291291
{
292292
memset(context, 0, sizeof(PHP_MD2_CTX));
293293
}

0 commit comments

Comments
 (0)