]> granicus.if.org Git - php/commitdiff
Make HashContexts serializable.
authorEddie Kohler <ekohler@gmail.com>
Mon, 8 Jun 2020 12:29:42 +0000 (08:29 -0400)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 30 Jun 2020 12:30:33 +0000 (14:30 +0200)
* Modify php_hash_ops to contain the algorithm name and
  serialize and unserialize methods.

* Implement __serialize and __unserialize magic methods on
  HashContext.

Note that serialized HashContexts are not necessarily portable
between PHP versions or from architecture to architecture.
(Most are, though Keccak and slow SHA3s are not.)

An exception is thrown when an unsupported serialization is
attempted.

Because of security concerns, HASH_HMAC contexts are not
currently serializable; attempting to serialize one throws
an exception.

Serialization exposes the state of HashContext memory, so ensure
that memory is zeroed before use by allocating it with a new
php_hash_alloc_context function. Performance impact is
negligible.

Some hash internal states have logical pointers into a buffer,
or sponge, that absorbs input provided in bytes rather than
chunks. The unserialize functions for these hash functions
must validate that the logical pointers are all within bounds,
lest future hash operations cause out-of-bounds memory accesses.

* Adler32, CRC32, FNV, joaat: simple state, no buffer positions
* Gost, MD2, SHA3, Snefru, Tiger, Whirlpool: buffer positions
  must be validated
* MD4, MD5, SHA1, SHA2, haval, ripemd: buffer positions encoded
  bitwise, forced to within bounds on use; no need to validate

40 files changed:
UPGRADING
ext/hash/hash.c
ext/hash/hash.stub.php
ext/hash/hash_adler32.c
ext/hash/hash_arginfo.h
ext/hash/hash_crc32.c
ext/hash/hash_fnv.c
ext/hash/hash_gost.c
ext/hash/hash_haval.c
ext/hash/hash_joaat.c
ext/hash/hash_md.c
ext/hash/hash_ripemd.c
ext/hash/hash_sha.c
ext/hash/hash_sha3.c
ext/hash/hash_snefru.c
ext/hash/hash_tiger.c
ext/hash/hash_whirlpool.c
ext/hash/php_hash.h
ext/hash/php_hash_adler32.h
ext/hash/php_hash_crc32.h
ext/hash/php_hash_fnv.h
ext/hash/php_hash_gost.h
ext/hash/php_hash_haval.h
ext/hash/php_hash_joaat.h
ext/hash/php_hash_md.h
ext/hash/php_hash_ripemd.h
ext/hash/php_hash_sha.h
ext/hash/php_hash_sha3.h
ext/hash/php_hash_snefru.h
ext/hash/php_hash_tiger.h
ext/hash/php_hash_whirlpool.h
ext/hash/sha3/generic32lc/KeccakHash.h
ext/hash/sha3/generic64lc/KeccakHash.h
ext/hash/tests/hash_serialize_001.phpt [new file with mode: 0644]
ext/hash/tests/hash_serialize_002.phpt [new file with mode: 0644]
ext/hash/tests/hash_serialize_003.phpt [new file with mode: 0644]
ext/hash/tests/hash_serialize_004.phpt [new file with mode: 0644]
ext/hash/tests/serialize-context.phpt [deleted file]
ext/standard/md5.h
ext/standard/sha1.h

index de0eebd055832ce367aec0dd473b359f12c2457c..f662a6625aa363f0fa8ef9f709165d4acb45391d 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -568,14 +568,18 @@ PHP 8.0 UPGRADE NOTES
   . Added DateTime::createFromInterface() and
     DateTimeImmutable::createFromInterface().
 
+- Dom:
+  . Introduce DOMParentNode and DOMChildNode with new traversal and
+    manipulation APIs.
+    RFC: https://wiki.php.net/rfc/dom_living_standard_api
+
 - Enchant:
   . enchant_dict_add()
   . enchant_dict_is_added()
   . LIBENCHANT_VERSION macro
 
-- dom:
-  . Introduce DOMParentNode and DOMChildNode with new traversal and manipulation APIs
-    RFC: https://wiki.php.net/rfc/dom_living_standard_api
+- Hash:
+  . HashContext objects can now be serialized.
 
 - Opcache:
   . If the opcache.record_warnings ini setting is enabled, opcache will record
index 2d356b613398fb501526bd86813e4ddf8021e7bc..469d91e34bfc20022f5fce15b030bcb09d9b6d9e 100644 (file)
 #include "php_hash.h"
 #include "ext/standard/info.h"
 #include "ext/standard/file.h"
+#include "ext/standard/php_var.h"
+#include "ext/spl/spl_exceptions.h"
 
 #include "zend_interfaces.h"
 #include "zend_exceptions.h"
+#include "zend_smart_str.h"
 
 #include "hash_arginfo.h"
 
+#ifdef PHP_WIN32
+# define __alignof__ __alignof
+#else
+# ifndef HAVE_ALIGNOF
+#  include <stddef.h>
+#  define __alignof__(type) offsetof (struct { char c; type member;}, member)
+# endif
+#endif
+
 HashTable php_hash_hashtable;
 zend_class_entry *php_hashcontext_ce;
 static zend_object_handlers php_hashcontext_handlers;
@@ -111,6 +123,226 @@ PHP_HASH_API int php_hash_copy(const void *ops, void *orig_context, void *dest_c
 }
 /* }}} */
 
+
+static inline size_t align_to(size_t pos, size_t alignment) {
+       size_t offset = pos & (alignment - 1);
+       return pos + (offset ? alignment - offset : 0);
+}
+
+static size_t parse_serialize_spec(
+               const char **specp, size_t *pos, size_t *sz, size_t *max_alignment) {
+       size_t count, alignment;
+       const char *spec = *specp;
+       /* parse size */
+       if (*spec == 's' || *spec == 'S') {
+               *sz = 2;
+               alignment = __alignof__(uint16_t); /* usually 2 */
+       } else if (*spec == 'l' || *spec == 'L') {
+               *sz = 4;
+               alignment = __alignof__(uint32_t); /* usually 4 */
+       } else if (*spec == 'q' || *spec == 'Q') {
+               *sz = 8;
+               alignment = __alignof__(uint64_t); /* usually 8 */
+       } else if (*spec == 'i' || *spec == 'I') {
+               *sz = sizeof(int);
+               alignment = __alignof__(int);      /* usually 4 */
+       } else {
+               ZEND_ASSERT(*spec == 'b' || *spec == 'B');
+               *sz = 1;
+               alignment = 1;
+       }
+       /* process alignment */
+       *pos = align_to(*pos, alignment);
+       *max_alignment = *max_alignment < alignment ? alignment : *max_alignment;
+       /* parse count */
+       ++spec;
+       if (isdigit((unsigned char) *spec)) {
+               count = 0;
+               while (isdigit((unsigned char) *spec)) {
+                       count = 10 * count + *spec - '0';
+                       ++spec;
+               }
+       } else {
+               count = 1;
+       }
+       *specp = spec;
+       return count;
+}
+
+static uint64_t one_from_buffer(size_t sz, const unsigned char *buf) {
+       if (sz == 2) {
+               const uint16_t *x = (const uint16_t *) buf;
+               return *x;
+       } else if (sz == 4) {
+               const uint32_t *x = (const uint32_t *) buf;
+               return *x;
+       } else if (sz == 8) {
+               const uint64_t *x = (const uint64_t *) buf;
+               return *x;
+       } else {
+               ZEND_ASSERT(sz == 1);
+               return *buf;
+       }
+}
+
+static void one_to_buffer(size_t sz, unsigned char *buf, uint64_t val) {
+       if (sz == 2) {
+               uint16_t *x = (uint16_t *) buf;
+               *x = val;
+       } else if (sz == 4) {
+               uint32_t *x = (uint32_t *) buf;
+               *x = val;
+       } else if (sz == 8) {
+               uint64_t *x = (uint64_t *) buf;
+               *x = val;
+       } else {
+               ZEND_ASSERT(sz == 1);
+               *buf = val;
+       }
+}
+
+/* Serialize a hash context according to a `spec` string.
+   Spec contents:
+   b[COUNT] -- serialize COUNT bytes
+   s[COUNT] -- serialize COUNT 16-bit integers
+   l[COUNT] -- serialize COUNT 32-bit integers
+   q[COUNT] -- serialize COUNT 64-bit integers
+   i[COUNT] -- serialize COUNT `int`s
+   B[COUNT] -- skip COUNT bytes
+   S[COUNT], L[COUNT], etc. -- uppercase versions skip instead of read
+   . (must be last character) -- assert that the hash context has exactly
+       this size
+   Example: "llllllb64l16." is the spec for an MD5 context: 6 32-bit
+   integers, followed by 64 bytes, then 16 32-bit integers, and that's
+   exactly the size of the context.
+
+   The serialization result is an array. Each integer is serialized as a
+   32-bit integer, except that a run of 2 or more bytes is encoded as a
+   string, and each 64-bit integer is serialized as two 32-bit integers, least
+   significant bits first. This allows 32-bit and 64-bit architectures to
+   interchange serialized HashContexts. */
+
+PHP_HASH_API int php_hash_serialize_spec(const php_hashcontext_object *hash, zval *zv, const char *spec) /* {{{ */
+{
+       size_t pos = 0, max_alignment = 1;
+       unsigned char *buf = (unsigned char *) hash->context;
+       zval tmp;
+       array_init(zv);
+       while (*spec != '\0' && *spec != '.') {
+               char spec_ch = *spec;
+               size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment);
+               if (pos + count * sz > hash->ops->context_size) {
+                       return FAILURE;
+               }
+               if (isupper((unsigned char) spec_ch)) {
+                       pos += count * sz;
+               } else if (sz == 1 && count > 1) {
+                       ZVAL_STRINGL(&tmp, (char *) buf + pos, count);
+                       zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp);
+                       pos += count;
+               } else {
+                       while (count > 0) {
+                               uint64_t val = one_from_buffer(sz, buf + pos);
+                               pos += sz;
+                               ZVAL_LONG(&tmp, (int32_t) val);
+                               zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp);
+                               if (sz == 8) {
+                                       ZVAL_LONG(&tmp, (int32_t) (val >> 32));
+                                       zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp);
+                               }
+                               --count;
+                       }
+               }
+       }
+       if (*spec == '.' && align_to(pos, max_alignment) != hash->ops->context_size) {
+               return FAILURE;
+       }
+       return SUCCESS;
+}
+/* }}} */
+
+/* Unserialize a hash context serialized by `php_hash_serialize_spec` with `spec`.
+   Returns SUCCESS on success and a negative error code on failure.
+   Codes: FAILURE (-1) == generic failure
+   -999 == spec wrong size for context
+   -1000 - POS == problem at byte offset POS */
+
+PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec) /* {{{ */
+{
+       size_t pos = 0, max_alignment = 1, j = 0;
+       unsigned char *buf = (unsigned char *) hash->context;
+       zval *elt;
+       if (Z_TYPE_P(zv) != IS_ARRAY) {
+               return FAILURE;
+       }
+       while (*spec != '\0' && *spec != '.') {
+               char spec_ch = *spec;
+               size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment);
+               if (pos + count * sz > hash->ops->context_size) {
+                       return -999;
+               }
+               if (isupper((unsigned char) spec_ch)) {
+                       pos += count * sz;
+               } else if (sz == 1 && count > 1) {
+                       elt = zend_hash_index_find(Z_ARRVAL_P(zv), j);
+                       if (!elt || Z_TYPE_P(elt) != IS_STRING || Z_STRLEN_P(elt) != count) {
+                               return -1000 - pos;
+                       }
+                       ++j;
+                       memcpy(buf + pos, Z_STRVAL_P(elt), count);
+                       pos += count;
+               } else {
+                       while (count > 0) {
+                               uint64_t val;
+                               elt = zend_hash_index_find(Z_ARRVAL_P(zv), j);
+                               if (!elt || Z_TYPE_P(elt) != IS_LONG) {
+                                       return -1000 - pos;
+                               }
+                               ++j;
+                               val = (uint32_t) Z_LVAL_P(elt);
+                               if (sz == 8) {
+                                       elt = zend_hash_index_find(Z_ARRVAL_P(zv), j);
+                                       if (!elt || Z_TYPE_P(elt) != IS_LONG) {
+                                               return -1000 - pos;
+                                       }
+                                       ++j;
+                                       val += ((uint64_t) Z_LVAL_P(elt)) << 32;
+                               }
+                               one_to_buffer(sz, buf + pos, val);
+                               pos += sz;
+                               --count;
+                       }
+               }
+       }
+       if (*spec == '.' && align_to(pos, max_alignment) != hash->ops->context_size) {
+               return -999;
+       }
+       return SUCCESS;
+}
+/* }}} */
+
+PHP_HASH_API int php_hash_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) /* {{{ */
+{
+       if (hash->ops->serialize_spec) {
+               *magic = PHP_HASH_SERIALIZE_MAGIC_SPEC;
+               return php_hash_serialize_spec(hash, zv, hash->ops->serialize_spec);
+       } else {
+               return FAILURE;
+       }
+}
+/* }}} */
+
+PHP_HASH_API int php_hash_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) /* {{{ */
+{
+       if (hash->ops->serialize_spec
+               && magic == PHP_HASH_SERIALIZE_MAGIC_SPEC) {
+               return php_hash_unserialize_spec(hash, zv, hash->ops->serialize_spec);
+       } else {
+               return FAILURE;
+       }
+}
+/* }}} */
+
 /* Userspace */
 
 static void php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
@@ -147,7 +379,7 @@ static void php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_
                }
        }
 
-       context = emalloc(ops->context_size);
+       context = php_hash_alloc_context(ops);
        ops->hash_init(context);
 
        if (isfilename) {
@@ -271,7 +503,7 @@ static void php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS, int isfilename,
                }
        }
 
-       context = emalloc(ops->context_size);
+       context = php_hash_alloc_context(ops);
 
        K = emalloc(ops->block_size);
        digest = zend_string_alloc(ops->digest_size, 0);
@@ -375,7 +607,7 @@ PHP_FUNCTION(hash_init)
        object_init_ex(return_value, php_hashcontext_ce);
        hash = php_hashcontext_from_object(Z_OBJ_P(return_value));
 
-       context = emalloc(ops->context_size);
+       context = php_hash_alloc_context(ops);
        ops->hash_init(context);
 
        hash->ops = ops;
@@ -664,7 +896,7 @@ PHP_FUNCTION(hash_hkdf)
                RETURN_THROWS();
        }
 
-       context = emalloc(ops->context_size);
+       context = php_hash_alloc_context(ops);
 
        // Extract
        ops->hash_init(context);
@@ -759,7 +991,7 @@ PHP_FUNCTION(hash_pbkdf2)
                RETURN_THROWS();
        }
 
-       context = emalloc(ops->context_size);
+       context = php_hash_alloc_context(ops);
        ops->hash_init(context);
 
        K1 = emalloc(ops->block_size);
@@ -1075,7 +1307,7 @@ PHP_FUNCTION(mhash_keygen_s2k)
                                        times++;
                                }
 
-                               context = emalloc(ops->context_size);
+                               context = php_hash_alloc_context(ops);
                                ops->hash_init(context);
 
                                key = ecalloc(1, times * block_size);
@@ -1148,7 +1380,7 @@ static zend_object *php_hashcontext_clone(zend_object *zobj) {
 
        newobj->ops = oldobj->ops;
        newobj->options = oldobj->options;
-       newobj->context = emalloc(newobj->ops->context_size);
+       newobj->context = php_hash_alloc_context(newobj->ops);
        newobj->ops->hash_init(newobj->context);
 
        if (SUCCESS != newobj->ops->hash_copy(newobj->ops, oldobj->context, newobj->context)) {
@@ -1166,6 +1398,144 @@ static zend_object *php_hashcontext_clone(zend_object *zobj) {
 }
 /* }}} */
 
+/* Serialization format: 5-element array
+   Index 0: hash algorithm (string)
+   Index 1: options (long, 0)
+   Index 2: hash-determined serialization of context state (usually array)
+   Index 3: magic number defining layout of context state (long, usually 2)
+   Index 4: properties (array)
+
+   HashContext serializations are not necessarily portable between architectures or
+   PHP versions. If the format of a serialized hash context changes, that should
+   be reflected in either a different value of `magic` or a different format of
+   the serialized context state. Most context states are unparsed and parsed using
+   a spec string, such as "llb128.", using the format defined by
+   `php_hash_serialize_spec`/`php_hash_unserialize_spec`. Some hash algorithms must
+   also check the unserialized state for validity, to ensure that using an
+   unserialized context is safe from memory errors.
+
+   Currently HASH_HMAC contexts cannot be serialized, because serializing them
+   would require serializing the HMAC key in plaintext. */
+
+/* {{{ proto array HashContext::__serialize()
+   Serialize the object */
+PHP_METHOD(HashContext, __serialize)
+{
+       zval *object = ZEND_THIS;
+       php_hashcontext_object *hash = php_hashcontext_from_object(Z_OBJ_P(object));
+       zend_long magic = 0;
+       zval tmp;
+
+       if (zend_parse_parameters_none() == FAILURE) {
+               RETURN_THROWS();
+       }
+
+       array_init(return_value);
+
+       if (!hash->ops->hash_serialize) {
+               goto serialize_failure;
+       } else if (hash->options & PHP_HASH_HMAC) {
+               zend_throw_exception(NULL, "HashContext with HASH_HMAC option cannot be serialized", 0);
+               RETURN_THROWS();
+       }
+
+       ZVAL_STRING(&tmp, hash->ops->algo);
+       zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
+
+       ZVAL_LONG(&tmp, hash->options);
+       zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
+
+       if (hash->ops->hash_serialize(hash, &magic, &tmp) != SUCCESS) {
+               goto serialize_failure;
+       }
+       zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
+
+       ZVAL_LONG(&tmp, magic);
+       zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
+
+       /* members */
+       ZVAL_ARR(&tmp, zend_std_get_properties(&hash->std));
+       Z_TRY_ADDREF(tmp);
+       zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
+
+       return;
+
+serialize_failure:
+       zend_throw_exception_ex(NULL, 0, "HashContext for algorithm \"%s\" cannot be serialized", hash->ops->algo);
+       RETURN_THROWS();
+}
+/* }}} */
+
+/* {{{ proto void HashContext::__unserialize(array serialized)
+ * unserialize the object
+ */
+PHP_METHOD(HashContext, __unserialize)
+{
+       zval *object = ZEND_THIS;
+       php_hashcontext_object *hash = php_hashcontext_from_object(Z_OBJ_P(object));
+       HashTable *data;
+       zval *algo_zv, *magic_zv, *options_zv, *hash_zv, *members_zv;
+       zend_long magic, options;
+       int unserialize_result;
+       const php_hash_ops *ops;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
+               RETURN_THROWS();
+       }
+
+       if (hash->context) {
+               zend_throw_exception(NULL, "HashContext::__unserialize called on initialized object", 0);
+               RETURN_THROWS();
+       }
+
+       algo_zv = zend_hash_index_find(data, 0);
+       options_zv = zend_hash_index_find(data, 1);
+       hash_zv = zend_hash_index_find(data, 2);
+       magic_zv = zend_hash_index_find(data, 3);
+       members_zv = zend_hash_index_find(data, 4);
+
+       if (!algo_zv || Z_TYPE_P(algo_zv) != IS_STRING
+               || !magic_zv || Z_TYPE_P(magic_zv) != IS_LONG
+               || !options_zv || Z_TYPE_P(options_zv) != IS_LONG
+               || !hash_zv
+               || !members_zv || Z_TYPE_P(members_zv) != IS_ARRAY) {
+               zend_throw_exception(NULL, "Incomplete or ill-formed serialization data", 0);
+               RETURN_THROWS();
+       }
+
+       magic = Z_LVAL_P(magic_zv);
+       options = Z_LVAL_P(options_zv);
+       if (options & PHP_HASH_HMAC) {
+               zend_throw_exception(NULL, "HashContext with HASH_HMAC option cannot be serialized", 0);
+               RETURN_THROWS();
+       }
+
+       ops = php_hash_fetch_ops(Z_STR_P(algo_zv));
+       if (!ops) {
+               zend_throw_exception(NULL, "Unknown hash algorithm", 0);
+               RETURN_THROWS();
+       } else if (!ops->hash_unserialize) {
+               zend_throw_exception_ex(NULL, 0, "Hash algorithm \"%s\" cannot be unserialized", ops->algo);
+               RETURN_THROWS();
+       }
+
+       hash->ops = ops;
+       hash->context = php_hash_alloc_context(ops);
+       ops->hash_init(hash->context);
+       hash->options = options;
+
+       unserialize_result = ops->hash_unserialize(hash, magic, hash_zv);
+       if (unserialize_result != SUCCESS) {
+               zend_throw_exception_ex(NULL, 0, "Incomplete or ill-formed serialization data (\"%s\" code %d)", ops->algo, unserialize_result);
+               /* free context */
+               php_hashcontext_dtor(Z_OBJ_P(object));
+               RETURN_THROWS();
+       }
+
+       object_properties_load(&hash->std, Z_ARRVAL_P(members_zv));
+}
+/* }}} */
+
 /* {{{ PHP_MINIT_FUNCTION
  */
 PHP_MINIT_FUNCTION(hash)
@@ -1237,8 +1607,6 @@ PHP_MINIT_FUNCTION(hash)
        php_hashcontext_ce = zend_register_internal_class(&ce);
        php_hashcontext_ce->ce_flags |= ZEND_ACC_FINAL;
        php_hashcontext_ce->create_object = php_hashcontext_create;
-       php_hashcontext_ce->serialize = zend_class_serialize_deny;
-       php_hashcontext_ce->unserialize = zend_class_unserialize_deny;
 
        memcpy(&php_hashcontext_handlers, &std_object_handlers,
               sizeof(zend_object_handlers));
index 32465415fcbff7614443d426a0293b234fd29461..f8788ed61ed51b2cae47c475ab510f2c8d7325f0 100644 (file)
@@ -53,4 +53,8 @@ function mhash(int $hash, string $data, string $key = UNKNOWN): string|false {}
 final class HashContext
 {
     private function __construct() {}
+
+    public function __serialize(): array {}
+
+    public function __unserialize(array $serialized): void {}
 }
index 8d2d2fcb9365cdfa8eea6514121b108ba03b86cc..d45012f8e6d515e481bdc037b4e4a652f037db11 100644 (file)
@@ -59,10 +59,14 @@ PHP_HASH_API int PHP_ADLER32Copy(const php_hash_ops *ops, PHP_ADLER32_CTX *orig_
 }
 
 const php_hash_ops php_hash_adler32_ops = {
+       "adler32",
        (php_hash_init_func_t) PHP_ADLER32Init,
        (php_hash_update_func_t) PHP_ADLER32Update,
        (php_hash_final_func_t) PHP_ADLER32Final,
        (php_hash_copy_func_t) PHP_ADLER32Copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_ADLER32_SPEC,
        4, /* what to say here? */
        4,
        sizeof(PHP_ADLER32_CTX),
index c09fd12001627cd07bef575f72ace94e59fe926e..7ba3fca9d72263898aa51eed92ca00a98bace0f8 100644 (file)
@@ -118,6 +118,12 @@ ZEND_END_ARG_INFO()
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_HashContext___construct, 0, 0, 0)
 ZEND_END_ARG_INFO()
 
+#define arginfo_class_HashContext___serialize arginfo_hash_algos
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_HashContext___unserialize, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, serialized, IS_ARRAY, 0)
+ZEND_END_ARG_INFO()
+
 
 ZEND_FUNCTION(hash);
 ZEND_FUNCTION(hash_file);
@@ -150,6 +156,8 @@ ZEND_FUNCTION(mhash_count);
 ZEND_FUNCTION(mhash);
 #endif
 ZEND_METHOD(HashContext, __construct);
+ZEND_METHOD(HashContext, __serialize);
+ZEND_METHOD(HashContext, __unserialize);
 
 
 static const zend_function_entry ext_functions[] = {
@@ -189,5 +197,7 @@ static const zend_function_entry ext_functions[] = {
 
 static const zend_function_entry class_HashContext_methods[] = {
        ZEND_ME(HashContext, __construct, arginfo_class_HashContext___construct, ZEND_ACC_PRIVATE)
+       ZEND_ME(HashContext, __serialize, arginfo_class_HashContext___serialize, ZEND_ACC_PUBLIC)
+       ZEND_ME(HashContext, __unserialize, arginfo_class_HashContext___unserialize, ZEND_ACC_PUBLIC)
        ZEND_FE_END
 };
index 52c67717ffbdea45e91d06c795c8cbc35036bb99..de270522d7e27bcd962f1a9c1685e6c4c20e85e9 100644 (file)
@@ -78,10 +78,14 @@ PHP_HASH_API int PHP_CRC32Copy(const php_hash_ops *ops, PHP_CRC32_CTX *orig_cont
 }
 
 const php_hash_ops php_hash_crc32_ops = {
+       "crc32",
        (php_hash_init_func_t) PHP_CRC32Init,
        (php_hash_update_func_t) PHP_CRC32Update,
        (php_hash_final_func_t) PHP_CRC32LEFinal,
        (php_hash_copy_func_t) PHP_CRC32Copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_CRC32_SPEC,
        4, /* what to say here? */
        4,
        sizeof(PHP_CRC32_CTX),
@@ -89,10 +93,14 @@ const php_hash_ops php_hash_crc32_ops = {
 };
 
 const php_hash_ops php_hash_crc32b_ops = {
+       "crc32b",
        (php_hash_init_func_t) PHP_CRC32Init,
        (php_hash_update_func_t) PHP_CRC32BUpdate,
        (php_hash_final_func_t) PHP_CRC32BEFinal,
        (php_hash_copy_func_t) PHP_CRC32Copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_CRC32_SPEC,
        4, /* what to say here? */
        4,
        sizeof(PHP_CRC32_CTX),
@@ -100,10 +108,14 @@ const php_hash_ops php_hash_crc32b_ops = {
 };
 
 const php_hash_ops php_hash_crc32c_ops = {
+       "crc32c",
        (php_hash_init_func_t) PHP_CRC32Init,
        (php_hash_update_func_t) PHP_CRC32CUpdate,
        (php_hash_final_func_t) PHP_CRC32BEFinal,
        (php_hash_copy_func_t) PHP_CRC32Copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_CRC32_SPEC,
        4, /* what to say here? */
        4,
        sizeof(PHP_CRC32_CTX),
index 976c53b5272886c798c7d8872c09521b163ee574..2ee81b9c8601b11ba69f813b6a97b0dc492efad8 100644 (file)
 #include "php_hash_fnv.h"
 
 const php_hash_ops php_hash_fnv132_ops = {
+       "fnv132",
        (php_hash_init_func_t) PHP_FNV132Init,
        (php_hash_update_func_t) PHP_FNV132Update,
        (php_hash_final_func_t) PHP_FNV132Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_FNV132_SPEC,
        4,
        4,
        sizeof(PHP_FNV132_CTX),
@@ -32,10 +36,14 @@ const php_hash_ops php_hash_fnv132_ops = {
 };
 
 const php_hash_ops php_hash_fnv1a32_ops = {
+       "fnv1a32",
        (php_hash_init_func_t) PHP_FNV132Init,
        (php_hash_update_func_t) PHP_FNV1a32Update,
-       (php_hash_final_func_t) PHP_FNV132Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       (php_hash_final_func_t) PHP_FNV132Final,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_FNV132_SPEC,
        4,
        4,
        sizeof(PHP_FNV132_CTX),
@@ -43,10 +51,14 @@ const php_hash_ops php_hash_fnv1a32_ops = {
 };
 
 const php_hash_ops php_hash_fnv164_ops = {
+       "fnv164",
        (php_hash_init_func_t) PHP_FNV164Init,
        (php_hash_update_func_t) PHP_FNV164Update,
        (php_hash_final_func_t) PHP_FNV164Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_FNV164_SPEC,
        8,
        4,
        sizeof(PHP_FNV164_CTX),
@@ -54,10 +66,14 @@ const php_hash_ops php_hash_fnv164_ops = {
 };
 
 const php_hash_ops php_hash_fnv1a64_ops = {
+       "fnv1a64",
        (php_hash_init_func_t) PHP_FNV164Init,
        (php_hash_update_func_t) PHP_FNV1a64Update,
-       (php_hash_final_func_t) PHP_FNV164Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       (php_hash_final_func_t) PHP_FNV164Final,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_FNV164_SPEC,
        8,
        4,
        sizeof(PHP_FNV164_CTX),
index a9e689de16ce2de773bcf9c0d30d3f10c58170e7..46ea032c32e300362adedbbfa1c04610fb66ee0a 100644 (file)
@@ -304,11 +304,28 @@ PHP_HASH_API void PHP_GOSTFinal(unsigned char digest[32], PHP_GOST_CTX *context)
        ZEND_SECURE_ZERO(context, sizeof(*context));
 }
 
+static int php_gost_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
+{
+       PHP_GOST_CTX *ctx = (PHP_GOST_CTX *) hash->context;
+       int r = FAILURE;
+       if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
+               && (r = php_hash_unserialize_spec(hash, zv, PHP_GOST_SPEC)) == SUCCESS
+               && ctx->length < sizeof(ctx->buffer)) {
+               return SUCCESS;
+       } else {
+               return r != SUCCESS ? r : -2000;
+       }
+}
+
 const php_hash_ops php_hash_gost_ops = {
+       "gost",
        (php_hash_init_func_t) PHP_GOSTInit,
        (php_hash_update_func_t) PHP_GOSTUpdate,
        (php_hash_final_func_t) PHP_GOSTFinal,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_gost_unserialize,
+       PHP_GOST_SPEC,
        32,
        32,
        sizeof(PHP_GOST_CTX),
@@ -316,10 +333,14 @@ const php_hash_ops php_hash_gost_ops = {
 };
 
 const php_hash_ops php_hash_gost_crypto_ops = {
+       "gost-crypto",
        (php_hash_init_func_t) PHP_GOSTInitCrypto,
        (php_hash_update_func_t) PHP_GOSTUpdate,
        (php_hash_final_func_t) PHP_GOSTFinal,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_gost_unserialize,
+       PHP_GOST_SPEC,
        32,
        32,
        sizeof(PHP_GOST_CTX),
index 62f63cbee1534e7168be6145fbb53a4b0a13b0e5..34210a8992aaea9dcf987cfc9d99833095fc57c6 100644 (file)
@@ -247,10 +247,14 @@ static void PHP_5HAVALTransform(uint32_t state[8], const unsigned char block[128
 
 #define PHP_HASH_HAVAL_INIT(p,b) \
 const php_hash_ops php_hash_##p##haval##b##_ops = { \
+       "haval" #b "," #p, \
        (php_hash_init_func_t) PHP_##p##HAVAL##b##Init, \
        (php_hash_update_func_t) PHP_HAVALUpdate, \
        (php_hash_final_func_t) PHP_HAVAL##b##Final, \
-       (php_hash_copy_func_t) php_hash_copy, \
+       php_hash_copy, \
+       php_hash_serialize, \
+       php_hash_unserialize, \
+       PHP_HAVAL_SPEC, \
        ((b) / 8), 128, sizeof(PHP_HAVAL_CTX), 1 }; \
 PHP_HASH_API void PHP_##p##HAVAL##b##Init(PHP_HAVAL_CTX *context) \
 {      int i; context->count[0] =      context->count[1] =     0; \
index 10c3ca2748f5d4adfcb947bdd812099db5189d7f..5d5a2e53b9b39522ce7a1bec7bcfb90024095cd9 100644 (file)
 #include "php_hash_joaat.h"
 
 const php_hash_ops php_hash_joaat_ops = {
+       "joaat",
        (php_hash_init_func_t) PHP_JOAATInit,
        (php_hash_update_func_t) PHP_JOAATUpdate,
        (php_hash_final_func_t) PHP_JOAATFinal,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_JOAAT_SPEC,
        4,
        4,
        sizeof(PHP_JOAAT_CTX),
index e5cbb49b01302e5f613a5093e6b5e66a2684e303..94fafbbf798a81321cc974d0c18a49252106eacd 100644 (file)
 #include "php_hash_md.h"
 
 const php_hash_ops php_hash_md5_ops = {
+       "md5",
        (php_hash_init_func_t) PHP_MD5Init,
        (php_hash_update_func_t) PHP_MD5Update,
        (php_hash_final_func_t) PHP_MD5Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_MD5_SPEC,
        16,
        64,
        sizeof(PHP_MD5_CTX),
@@ -29,21 +33,31 @@ const php_hash_ops php_hash_md5_ops = {
 };
 
 const php_hash_ops php_hash_md4_ops = {
+       "md4",
        (php_hash_init_func_t) PHP_MD4Init,
        (php_hash_update_func_t) PHP_MD4Update,
        (php_hash_final_func_t) PHP_MD4Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_MD4_SPEC,
        16,
        64,
        sizeof(PHP_MD4_CTX),
        1
 };
 
+static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv);
+
 const php_hash_ops php_hash_md2_ops = {
+       "md2",
        (php_hash_init_func_t) PHP_MD2Init,
        (php_hash_update_func_t) PHP_MD2Update,
        (php_hash_final_func_t) PHP_MD2Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_md2_unserialize,
+       PHP_MD2_SPEC,
        16,
        16,
        sizeof(PHP_MD2_CTX),
@@ -340,3 +354,16 @@ PHP_HASH_API void PHP_MD2Final(unsigned char output[16], PHP_MD2_CTX *context)
 
        memcpy(output, context->state, 16);
 }
+
+static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
+{
+       PHP_MD2_CTX *ctx = (PHP_MD2_CTX *) hash->context;
+       int r = FAILURE;
+       if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
+               && (r = php_hash_unserialize_spec(hash, zv, PHP_MD2_SPEC)) == SUCCESS
+               && (unsigned char) ctx->in_buffer < sizeof(ctx->buffer)) {
+               return SUCCESS;
+       } else {
+               return r != SUCCESS ? r : -2000;
+       }
+}
index 84a29f64868c8f2ccd1b7f3e740144efb7004078..db1d1dc02b9e2656ce4d2a25d5550e12e6e71106 100644 (file)
 #include "php_hash_ripemd.h"
 
 const php_hash_ops php_hash_ripemd128_ops = {
+       "ripemd128",
        (php_hash_init_func_t) PHP_RIPEMD128Init,
        (php_hash_update_func_t) PHP_RIPEMD128Update,
        (php_hash_final_func_t) PHP_RIPEMD128Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_RIPEMD128_SPEC,
        16,
        64,
        sizeof(PHP_RIPEMD128_CTX),
@@ -33,10 +37,14 @@ const php_hash_ops php_hash_ripemd128_ops = {
 };
 
 const php_hash_ops php_hash_ripemd160_ops = {
+       "ripemd160",
        (php_hash_init_func_t) PHP_RIPEMD160Init,
        (php_hash_update_func_t) PHP_RIPEMD160Update,
        (php_hash_final_func_t) PHP_RIPEMD160Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_RIPEMD160_SPEC,
        20,
        64,
        sizeof(PHP_RIPEMD160_CTX),
@@ -44,10 +52,14 @@ const php_hash_ops php_hash_ripemd160_ops = {
 };
 
 const php_hash_ops php_hash_ripemd256_ops = {
+       "ripemd256",
        (php_hash_init_func_t) PHP_RIPEMD256Init,
        (php_hash_update_func_t) PHP_RIPEMD256Update,
        (php_hash_final_func_t) PHP_RIPEMD256Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_RIPEMD256_SPEC,
        32,
        64,
        sizeof(PHP_RIPEMD256_CTX),
@@ -55,10 +67,14 @@ const php_hash_ops php_hash_ripemd256_ops = {
 };
 
 const php_hash_ops php_hash_ripemd320_ops = {
+       "ripemd320",
        (php_hash_init_func_t) PHP_RIPEMD320Init,
        (php_hash_update_func_t) PHP_RIPEMD320Update,
        (php_hash_final_func_t) PHP_RIPEMD320Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_RIPEMD320_SPEC,
        40,
        64,
        sizeof(PHP_RIPEMD320_CTX),
index 30ab0d22adf7dddbee10129c1a2ab888e71d18dc..4ea5b768d703c50fd080cb21e6e4ef36c3be1c29 100644 (file)
@@ -63,10 +63,14 @@ static void SHADecode32(uint32_t *output, const unsigned char *input, unsigned i
 /* }}} */
 
 const php_hash_ops php_hash_sha1_ops = {
+       "sha1",
        (php_hash_init_func_t) PHP_SHA1Init,
        (php_hash_update_func_t) PHP_SHA1Update,
        (php_hash_final_func_t) PHP_SHA1Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_SHA1_SPEC,
        20,
        64,
        sizeof(PHP_SHA1_CTX),
@@ -76,10 +80,14 @@ const php_hash_ops php_hash_sha1_ops = {
 /* sha224/sha256 */
 
 const php_hash_ops php_hash_sha256_ops = {
+       "sha256",
        (php_hash_init_func_t) PHP_SHA256Init,
        (php_hash_update_func_t) PHP_SHA256Update,
        (php_hash_final_func_t) PHP_SHA256Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_SHA256_SPEC,
        32,
        64,
        sizeof(PHP_SHA256_CTX),
@@ -87,10 +95,14 @@ const php_hash_ops php_hash_sha256_ops = {
 };
 
 const php_hash_ops php_hash_sha224_ops = {
+       "sha224",
        (php_hash_init_func_t) PHP_SHA224Init,
        (php_hash_update_func_t) PHP_SHA224Update,
        (php_hash_final_func_t) PHP_SHA224Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_SHA224_SPEC,
        28,
        64,
        sizeof(PHP_SHA224_CTX),
@@ -578,10 +590,14 @@ PHP_HASH_API void PHP_SHA384Final(unsigned char digest[48], PHP_SHA384_CTX * con
 /* }}} */
 
 const php_hash_ops php_hash_sha384_ops = {
+       "sha384",
        (php_hash_init_func_t) PHP_SHA384Init,
        (php_hash_update_func_t) PHP_SHA384Update,
        (php_hash_final_func_t) PHP_SHA384Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_SHA384_SPEC,
        48,
        128,
        sizeof(PHP_SHA384_CTX),
@@ -751,10 +767,14 @@ PHP_HASH_API void PHP_SHA512_224Final(unsigned char digest[28], PHP_SHA512_CTX *
 /* }}} */
 
 const php_hash_ops php_hash_sha512_ops = {
+       "sha512",
        (php_hash_init_func_t) PHP_SHA512Init,
        (php_hash_update_func_t) PHP_SHA512Update,
        (php_hash_final_func_t) PHP_SHA512Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_SHA512_SPEC,
        64,
        128,
        sizeof(PHP_SHA512_CTX),
@@ -762,10 +782,14 @@ const php_hash_ops php_hash_sha512_ops = {
 };
 
 const php_hash_ops php_hash_sha512_256_ops = {
+       "sha512/256",
        (php_hash_init_func_t) PHP_SHA512_256Init,
        (php_hash_update_func_t) PHP_SHA512_256Update,
        (php_hash_final_func_t) PHP_SHA512_256Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_SHA512_SPEC,
        32,
        128,
        sizeof(PHP_SHA512_CTX),
@@ -773,10 +797,14 @@ const php_hash_ops php_hash_sha512_256_ops = {
 };
 
 const php_hash_ops php_hash_sha512_224_ops = {
+       "sha512/224",
        (php_hash_init_func_t) PHP_SHA512_224Init,
        (php_hash_update_func_t) PHP_SHA512_224Update,
        (php_hash_final_func_t) PHP_SHA512_224Final,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_hash_unserialize,
+       PHP_SHA512_SPEC,
        28,
        128,
        sizeof(PHP_SHA512_CTX),
index 32621514a8f5e3178fe28ac317e3bfb420acf5b2..52bd495f9df60317b8c09c44abb05d7358e1d0f2 100644 (file)
@@ -201,6 +201,22 @@ static void PHP_SHA3_Final(unsigned char* digest,
        ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX));
 }
 
+static int php_sha3_unserialize(php_hashcontext_object *hash,
+                               zend_long magic,
+                               const zval *zv,
+                               size_t block_size)
+{
+       PHP_SHA3_CTX *ctx = (PHP_SHA3_CTX *) hash->context;
+       int r = FAILURE;
+       if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
+               && (r = php_hash_unserialize_spec(hash, zv, PHP_SHA3_SPEC)) == SUCCESS
+               && ctx->pos < block_size) {
+               return SUCCESS;
+       } else {
+               return r != SUCCESS ? r : -2000;
+       }
+}
+
 // ==========================================================================
 
 #define DECLARE_SHA3_OPS(bits) \
@@ -219,11 +235,20 @@ void PHP_SHA3##bits##Final(unsigned char* digest, \
                    (1600 - (2 * bits)) >> 3, \
                    bits >> 3); \
 } \
+static int php_sha3##bits##_unserialize(php_hashcontext_object *hash, \
+                                       zend_long magic, \
+                                       const zval *zv) { \
+       return php_sha3_unserialize(hash, magic, zv, (1600 - (2 * bits)) >> 3); \
+} \
 const php_hash_ops php_hash_sha3_##bits##_ops = { \
+       "sha3-" #bits, \
        (php_hash_init_func_t) PHP_SHA3##bits##Init, \
        (php_hash_update_func_t) PHP_SHA3##bits##Update, \
        (php_hash_final_func_t) PHP_SHA3##bits##Final, \
        php_hash_copy, \
+       php_hash_serialize, \
+       php_sha3##bits##_unserialize, \
+       PHP_SHA3_SPEC, \
        bits >> 3, \
        (1600 - (2 * bits)) >> 3, \
        sizeof(PHP_SHA3_##bits##_CTX), \
@@ -237,6 +262,55 @@ const php_hash_ops php_hash_sha3_##bits##_ops = { \
 #define SUCCESS SHA3_SUCCESS /* Avoid conflict between KeccacHash.h and zend_types.h */
 #include "KeccakHash.h"
 
+/* KECCAK SERIALIZATION
+
+   Keccak_HashInstance consists of:
+       KeccakWidth1600_SpongeInstance {
+               unsigned char state[200];
+               unsigned int rate;         -- fixed for digest size
+               unsigned int byteIOIndex;  -- in range [0, rate/8)
+               int squeezing;             -- 0 normally, 1 only during finalize
+       } sponge;
+       unsigned int fixedOutputLength;    -- fixed for digest size
+       unsigned char delimitedSuffix;     -- fixed for digest size
+
+   NB If the external sha3/ library is updated, the serialization code
+   may need to be updated.
+
+   The simpler SHA3 code's serialization states are not interchangeable with
+   Keccak. Furthermore, the Keccak sponge state is sensitive to architecture
+   -- 32-bit and 64-bit implementations produce different states. It does not
+   appear that the state is sensitive to endianness. */
+
+#if Keccak_HashInstance_ImplType == 64
+/* corresponds to sha3/generic64lc */
+# define PHP_HASH_SERIALIZE_MAGIC_KECCAK 100
+#elif Keccak_HashInstance_ImplType == 32
+/* corresponds to sha3/generic32lc */
+# define PHP_HASH_SERIALIZE_MAGIC_KECCAK 101
+#else
+# error "Unknown Keccak_HashInstance_ImplType"
+#endif
+#define PHP_KECCAK_SPEC "b200IiIIB"
+
+static int php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv)
+{
+       *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK;
+       return php_hash_serialize_spec(hash, zv, PHP_KECCAK_SPEC);
+}
+
+static int php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
+{
+       Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context;
+       int r = FAILURE;
+       if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK
+               && (r = php_hash_unserialize_spec(hash, zv, PHP_KECCAK_SPEC)) == SUCCESS
+               && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) {
+               return SUCCESS;
+       } else {
+               return r != SUCCESS ? r : -2000;
+       }
+}
 
 // ==========================================================================
 
@@ -255,10 +329,14 @@ void PHP_SHA3##bits##Final(unsigned char* digest, \
        Keccak_HashFinal((Keccak_HashInstance *)ctx, digest); \
 } \
 const php_hash_ops php_hash_sha3_##bits##_ops = { \
+       "sha3-" #bits, \
        (php_hash_init_func_t) PHP_SHA3##bits##Init, \
        (php_hash_update_func_t) PHP_SHA3##bits##Update, \
        (php_hash_final_func_t) PHP_SHA3##bits##Final, \
        php_hash_copy, \
+       php_keccak_serialize, \
+       php_keccak_unserialize, \
+       PHP_KECCAK_SPEC, \
        bits >> 3, \
        (1600 - (2 * bits)) >> 3, \
        sizeof(PHP_SHA3_CTX), \
index fae767f2feec3e7eba643d0599be82625c6c1b2c..292bfef2cb8da57a7955eb93255cf15c038fd95d 100644 (file)
@@ -189,11 +189,28 @@ PHP_HASH_API void PHP_SNEFRUFinal(unsigned char digest[32], PHP_SNEFRU_CTX *cont
        ZEND_SECURE_ZERO(context, sizeof(*context));
 }
 
+static int php_snefru_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
+{
+       PHP_SNEFRU_CTX *ctx = (PHP_SNEFRU_CTX *) hash->context;
+       int r = FAILURE;
+       if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
+               && (r = php_hash_unserialize_spec(hash, zv, PHP_SNEFRU_SPEC)) == SUCCESS
+               && ctx->length < sizeof(ctx->buffer)) {
+               return SUCCESS;
+       } else {
+               return r != SUCCESS ? r : -2000;
+       }
+}
+
 const php_hash_ops php_hash_snefru_ops = {
+       "snefru",
        (php_hash_init_func_t) PHP_SNEFRUInit,
        (php_hash_update_func_t) PHP_SNEFRUUpdate,
        (php_hash_final_func_t) PHP_SNEFRUFinal,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_snefru_unserialize,
+       PHP_SNEFRU_SPEC,
        32,
        32,
        sizeof(PHP_SNEFRU_CTX),
index 399e95af0e3bc0ea7800fe832db7dc24800bdcb5..8e0f365dc49ebe510a00b509b78d912a6bf90427 100644 (file)
@@ -239,12 +239,29 @@ PHP_HASH_API void PHP_TIGER192Final(unsigned char digest[24], PHP_TIGER_CTX *con
        ZEND_SECURE_ZERO(context, sizeof(*context));
 }
 
+static int php_tiger_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
+{
+       PHP_TIGER_CTX *ctx = (PHP_TIGER_CTX *) hash->context;
+       int r = FAILURE;
+       if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
+               && (r = php_hash_unserialize_spec(hash, zv, PHP_TIGER_SPEC)) == SUCCESS
+               && ctx->length < sizeof(ctx->buffer)) {
+               return SUCCESS;
+       } else {
+               return r != SUCCESS ? r : -2000;
+       }
+}
+
 #define PHP_HASH_TIGER_OPS(p, b) \
        const php_hash_ops php_hash_##p##tiger##b##_ops = { \
+               "tiger" #b "," #p, \
                (php_hash_init_func_t) PHP_##p##TIGERInit, \
                (php_hash_update_func_t) PHP_TIGERUpdate, \
                (php_hash_final_func_t) PHP_TIGER##b##Final, \
-               (php_hash_copy_func_t) php_hash_copy, \
+               php_hash_copy, \
+               php_hash_serialize, \
+               php_tiger_unserialize, \
+               PHP_TIGER_SPEC, \
                b/8, \
                64, \
                sizeof(PHP_TIGER_CTX), \
index 5be7f80eea0728d6cc83968bb4cbb38ff3c38be5..8d5cbb77370a89f8b79681ce960a656fe94a56fa 100644 (file)
@@ -429,11 +429,31 @@ PHP_HASH_API void PHP_WHIRLPOOLFinal(unsigned char digest[64], PHP_WHIRLPOOL_CTX
     ZEND_SECURE_ZERO(context, sizeof(*context));
 }
 
+static int php_whirlpool_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
+{
+    PHP_WHIRLPOOL_CTX *ctx = (PHP_WHIRLPOOL_CTX *) hash->context;
+    int r = FAILURE;
+    if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
+        && (r = php_hash_unserialize_spec(hash, zv, PHP_WHIRLPOOL_SPEC)) == SUCCESS
+        && ctx->buffer.pos >= 0
+        && ctx->buffer.pos < (int) sizeof(ctx->buffer.data)
+        && ctx->buffer.bits >= ctx->buffer.pos * 8
+        && ctx->buffer.bits < ctx->buffer.pos * 8 + 8) {
+        return SUCCESS;
+    } else {
+        return r != SUCCESS ? r : -2000;
+    }
+}
+
 const php_hash_ops php_hash_whirlpool_ops = {
+       "whirlpool",
        (php_hash_init_func_t) PHP_WHIRLPOOLInit,
        (php_hash_update_func_t) PHP_WHIRLPOOLUpdate,
        (php_hash_final_func_t) PHP_WHIRLPOOLFinal,
-       (php_hash_copy_func_t) php_hash_copy,
+       php_hash_copy,
+       php_hash_serialize,
+       php_whirlpool_unserialize,
+       PHP_WHIRLPOOL_SPEC,
        64,
        64,
        sizeof(PHP_WHIRLPOOL_CTX),
index 79bbc066d6c83f1f78dbb30cb497ef5a03bf0941..33cc6a473a7a1b09af557c5dd6585a770e3e3b17 100644 (file)
 
 #define PHP_HASH_HMAC          0x0001
 
+#define PHP_HASH_SERIALIZE_MAGIC_SPEC          2
+
 #define L64 INT64_C
 
+typedef struct _php_hashcontext_object php_hashcontext_object;
+
 typedef void (*php_hash_init_func_t)(void *context);
 typedef void (*php_hash_update_func_t)(void *context, const unsigned char *buf, size_t count);
 typedef void (*php_hash_final_func_t)(unsigned char *digest, void *context);
 typedef int  (*php_hash_copy_func_t)(const void *ops, void *orig_context, void *dest_context);
+typedef int  (*php_hash_serialize_func_t)(const php_hashcontext_object *hash, zend_long *magic, zval *zv);
+typedef int  (*php_hash_unserialize_func_t)(php_hashcontext_object *hash, zend_long magic, const zval *zv);
 
 typedef struct _php_hash_ops {
+       const char *algo;
        php_hash_init_func_t hash_init;
        php_hash_update_func_t hash_update;
        php_hash_final_func_t hash_final;
        php_hash_copy_func_t hash_copy;
+       php_hash_serialize_func_t hash_serialize;
+       php_hash_unserialize_func_t hash_unserialize;
+       const char *serialize_spec;
 
        size_t digest_size;
        size_t block_size;
@@ -44,7 +54,7 @@ typedef struct _php_hash_ops {
        unsigned is_crypto: 1;
 } php_hash_ops;
 
-typedef struct _php_hashcontext_object {
+struct _php_hashcontext_object {
        const php_hash_ops *ops;
        void *context;
 
@@ -52,7 +62,7 @@ typedef struct _php_hashcontext_object {
        unsigned char *key;
 
        zend_object std;
-} php_hashcontext_object;
+};
 
 static inline php_hashcontext_object *php_hashcontext_from_object(zend_object *obj) {
        return ((php_hashcontext_object*)(obj + 1)) - 1;
@@ -131,6 +141,15 @@ extern PHP_HASH_API zend_class_entry *php_hashcontext_ce;
 PHP_HASH_API const php_hash_ops *php_hash_fetch_ops(zend_string *algo);
 PHP_HASH_API void php_hash_register_algo(const char *algo, const php_hash_ops *ops);
 PHP_HASH_API int php_hash_copy(const void *ops, void *orig_context, void *dest_context);
+PHP_HASH_API int php_hash_serialize(const php_hashcontext_object *context, zend_long *magic, zval *zv);
+PHP_HASH_API int php_hash_unserialize(php_hashcontext_object *context, zend_long magic, const zval *zv);
+PHP_HASH_API int php_hash_serialize_spec(const php_hashcontext_object *context, zval *zv, const char *spec);
+PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec);
+
+static inline void *php_hash_alloc_context(const php_hash_ops *ops) {
+       /* Zero out context memory so serialization doesn't expose internals */
+       return ecalloc(1, ops->context_size);
+}
 
 static inline void php_hash_bin2hex(char *out, const unsigned char *in, size_t in_len)
 {
index 184091c97122b8dc0913edfe6d16787d9aa5e87f..049f16b28e95618a67611c96ce962090d598eae0 100644 (file)
@@ -22,6 +22,7 @@
 typedef struct {
        uint32_t state;
 } PHP_ADLER32_CTX;
+#define PHP_ADLER32_SPEC "l."
 
 PHP_HASH_API void PHP_ADLER32Init(PHP_ADLER32_CTX *context);
 PHP_HASH_API void PHP_ADLER32Update(PHP_ADLER32_CTX *context, const unsigned char *input, size_t len);
index 346011e4176ad84937b571e62750168e01834a85..4c1b0fedc915915b46061aef299fe6f30b0977b5 100644 (file)
@@ -22,6 +22,7 @@
 typedef struct {
        uint32_t state;
 } PHP_CRC32_CTX;
+#define PHP_CRC32_SPEC "l."
 
 PHP_HASH_API void PHP_CRC32Init(PHP_CRC32_CTX *context);
 PHP_HASH_API void PHP_CRC32Update(PHP_CRC32_CTX *context, const unsigned char *input, size_t len);
index 1cb8c78d295d4cd81091245c139f1130713dc4c9..6728b2e90205ea0a6e7c2f8fe52c6d0bff68efa8 100644 (file)
@@ -44,10 +44,12 @@ enum php_fnv_type {
 typedef struct {
        uint32_t state;
 } PHP_FNV132_CTX;
+#define PHP_FNV132_SPEC "l."
 
 typedef struct {
        uint64_t state;
 } PHP_FNV164_CTX;
+#define PHP_FNV164_SPEC "q."
 
 
 PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context);
index 987eb655cb30a763e1c288c606ea3e29115abe49..eb9441faa66a4b9f4edf4fc9986fd3d5ee4213b1 100644 (file)
@@ -27,6 +27,7 @@ typedef struct {
        unsigned char buffer[32];
        const uint32_t (*tables)[4][256];
 } PHP_GOST_CTX;
+#define PHP_GOST_SPEC "l16l2bb32"
 
 PHP_HASH_API void PHP_GOSTInit(PHP_GOST_CTX *);
 PHP_HASH_API void PHP_GOSTUpdate(PHP_GOST_CTX *, const unsigned char *, size_t);
index 8eaaf2d2b74f5bff3590162213e1af9f2c340cb7..43802b41834faf98b7216f80860891b63502d418 100644 (file)
@@ -28,6 +28,7 @@ typedef struct {
        short output;
        void (*Transform)(uint32_t state[8], const unsigned char block[128]);
 } PHP_HAVAL_CTX;
+#define PHP_HAVAL_SPEC "l8l2b128"
 
 #define PHP_HASH_HAVAL_INIT_DECL(p,b)  PHP_HASH_API void PHP_##p##HAVAL##b##Init(PHP_HAVAL_CTX *); \
                                                                                PHP_HASH_API void PHP_HAVAL##b##Final(unsigned char*, PHP_HAVAL_CTX *);
index ede108f1bb23b355f9a06a93832e78e356402284..b0df8a67b38ae631edb179c626ca15d7f2c05847 100644 (file)
@@ -20,6 +20,7 @@
 typedef struct {
        uint32_t state;
 } PHP_JOAAT_CTX;
+#define PHP_JOAAT_SPEC "l."
 
 PHP_HASH_API void PHP_JOAATInit(PHP_JOAAT_CTX *context);
 PHP_HASH_API void PHP_JOAATUpdate(PHP_JOAAT_CTX *context, const unsigned char *input, size_t inputLen);
index aed999261e933552c877d08751a8ab1ce07ec46b..2a677fe54d6621a51c89187ed4c710a9c05b4cb1 100644 (file)
@@ -26,6 +26,7 @@ typedef struct {
        uint32_t count[2];
        unsigned char buffer[64];
 } PHP_MD4_CTX;
+#define PHP_MD4_SPEC "l4l2b64."
 
 PHP_HASH_API void PHP_MD4Init(PHP_MD4_CTX *);
 PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX *context, const unsigned char *, size_t);
@@ -36,8 +37,9 @@ typedef struct {
        unsigned char state[48];
        unsigned char checksum[16];
        unsigned char buffer[16];
-       char in_buffer;
+       unsigned char in_buffer;
 } PHP_MD2_CTX;
+#define PHP_MD2_SPEC "b48b16b16b."
 
 PHP_HASH_API void PHP_MD2Init(PHP_MD2_CTX *context);
 PHP_HASH_API void PHP_MD2Update(PHP_MD2_CTX *context, const unsigned char *, size_t);
index 131dd0ad8f0a151a7cf7dd816ccf24c97b1eea7a..dd9913b85b72ac2b34a990bd7e5f37ce58cdf427 100644 (file)
@@ -24,24 +24,28 @@ typedef struct {
        uint32_t count[2];              /* number of bits, modulo 2^64 (lsb first) */
        unsigned char buffer[64];       /* input buffer */
 } PHP_RIPEMD128_CTX;
+#define PHP_RIPEMD128_SPEC "l4l2b64."
 
 typedef struct {
        uint32_t state[5];              /* state (ABCD) */
        uint32_t count[2];              /* number of bits, modulo 2^64 (lsb first) */
        unsigned char buffer[64];       /* input buffer */
 } PHP_RIPEMD160_CTX;
+#define PHP_RIPEMD160_SPEC "l5l2b64."
 
 typedef struct {
        uint32_t state[8];              /* state (ABCD) */
        uint32_t count[2];              /* number of bits, modulo 2^64 (lsb first) */
        unsigned char buffer[64];       /* input buffer */
 } PHP_RIPEMD256_CTX;
+#define PHP_RIPEMD256_SPEC "l8l2b64."
 
 typedef struct {
        uint32_t state[10];             /* state (ABCD) */
        uint32_t count[2];              /* number of bits, modulo 2^64 (lsb first) */
        unsigned char buffer[64];       /* input buffer */
 } PHP_RIPEMD320_CTX;
+#define PHP_RIPEMD320_SPEC "l10l2b64."
 
 PHP_HASH_API void PHP_RIPEMD128Init(PHP_RIPEMD128_CTX *);
 PHP_HASH_API void PHP_RIPEMD128Update(PHP_RIPEMD128_CTX *, const unsigned char *, size_t);
index 95471e7398b13462c277841dbe35edd95ed949f9..16da9273636a79f0ba46dc1b2e1ba83696eab6aa 100644 (file)
@@ -27,6 +27,7 @@ typedef struct {
        uint32_t count[2];              /* number of bits, modulo 2^64 */
        unsigned char buffer[64];       /* input buffer */
 } PHP_SHA224_CTX;
+#define PHP_SHA224_SPEC "l8l2b64."
 
 PHP_HASH_API void PHP_SHA224Init(PHP_SHA224_CTX *);
 PHP_HASH_API void PHP_SHA224Update(PHP_SHA224_CTX *, const unsigned char *, size_t);
@@ -38,6 +39,7 @@ typedef struct {
        uint32_t count[2];              /* number of bits, modulo 2^64 */
        unsigned char buffer[64];       /* input buffer */
 } PHP_SHA256_CTX;
+#define PHP_SHA256_SPEC "l8l2b64."
 
 PHP_HASH_API void PHP_SHA256Init(PHP_SHA256_CTX *);
 PHP_HASH_API void PHP_SHA256Update(PHP_SHA256_CTX *, const unsigned char *, size_t);
@@ -49,6 +51,7 @@ typedef struct {
        uint64_t count[2];      /* number of bits, modulo 2^128 */
        unsigned char buffer[128];      /* input buffer */
 } PHP_SHA384_CTX;
+#define PHP_SHA384_SPEC "q8q2b128."
 
 PHP_HASH_API void PHP_SHA384Init(PHP_SHA384_CTX *);
 PHP_HASH_API void PHP_SHA384Update(PHP_SHA384_CTX *, const unsigned char *, size_t);
@@ -60,6 +63,7 @@ typedef struct {
        uint64_t count[2];      /* number of bits, modulo 2^128 */
        unsigned char buffer[128];      /* input buffer */
 } PHP_SHA512_CTX;
+#define PHP_SHA512_SPEC "q8q2b128."
 
 PHP_HASH_API void PHP_SHA512Init(PHP_SHA512_CTX *);
 PHP_HASH_API void PHP_SHA512Update(PHP_SHA512_CTX *, const unsigned char *, size_t);
index bb392c0ab0943b522fb06a4a269d7e8a400ad4e9..f75191f339fc67357405dd2e7154959cefdeb0dc 100644 (file)
@@ -27,6 +27,9 @@ typedef struct {
        unsigned char state[224]; // this must fit a Keccak_HashInstance
 #endif
 } PHP_SHA3_CTX;
+#ifdef HAVE_SLOW_HASH3
+#define PHP_SHA3_SPEC "b200l."
+#endif
 
 typedef PHP_SHA3_CTX PHP_SHA3_224_CTX;
 typedef PHP_SHA3_CTX PHP_SHA3_256_CTX;
index 25ba1183e3bcfceacbc7c6791349466dff4bf8ef..0f339e93090ab507c7736534334059d5c32efb7c 100644 (file)
@@ -30,6 +30,7 @@ typedef struct {
        unsigned char length;
        unsigned char buffer[32];
 } PHP_SNEFRU_CTX;
+#define PHP_SNEFRU_SPEC "l16l2bb32"
 
 PHP_HASH_API void PHP_SNEFRUInit(PHP_SNEFRU_CTX *);
 PHP_HASH_API void PHP_SNEFRUUpdate(PHP_SNEFRU_CTX *, const unsigned char *, size_t);
index 4476639040a6e332656acbd142f3efbfb8c64ce8..d30276ddeaa29f758d27203faa7b0e98562fbdf2 100644 (file)
@@ -22,9 +22,10 @@ typedef struct {
        uint64_t state[3];
        uint64_t passed;
        unsigned char buffer[64];
+       uint32_t length;
        unsigned int passes:1;
-       size_t length;
 } PHP_TIGER_CTX;
+#define PHP_TIGER_SPEC "q3qb64l"
 
 PHP_HASH_API void PHP_3TIGERInit(PHP_TIGER_CTX *context);
 PHP_HASH_API void PHP_4TIGERInit(PHP_TIGER_CTX *context);
index f96da414a531564412e9807fea10fb929b55d07b..fbd5948a4817bbdd070bb2a8d1038bedde1ee6b0 100644 (file)
@@ -27,6 +27,7 @@ typedef struct {
                unsigned char data[64];
        } buffer;
 } PHP_WHIRLPOOL_CTX;
+#define PHP_WHIRLPOOL_SPEC "q8b32iib64."
 
 PHP_HASH_API void PHP_WHIRLPOOLInit(PHP_WHIRLPOOL_CTX *);
 PHP_HASH_API void PHP_WHIRLPOOLUpdate(PHP_WHIRLPOOL_CTX *, const unsigned char *, size_t);
index ec35d3dab252450e6ada96b8158ef7ece55050bf..d53ac1c587aeca47fbc52788b2d5828bf3eb7253 100644 (file)
@@ -108,6 +108,8 @@ HashReturn Keccak_HashFinal(Keccak_HashInstance *hashInstance, BitSequence *hash
   */
 HashReturn Keccak_HashSqueeze(Keccak_HashInstance *hashInstance, BitSequence *data, DataLength databitlen);
 
+#define Keccak_HashInstance_ImplType 32
+
 #endif
 
 #endif
index ec35d3dab252450e6ada96b8158ef7ece55050bf..6afe6c8c9a85a4bb5b2f7009df5da89ab01091f3 100644 (file)
@@ -108,6 +108,8 @@ HashReturn Keccak_HashFinal(Keccak_HashInstance *hashInstance, BitSequence *hash
   */
 HashReturn Keccak_HashSqueeze(Keccak_HashInstance *hashInstance, BitSequence *data, DataLength databitlen);
 
+#define Keccak_HashInstance_ImplType 64
+
 #endif
 
 #endif
diff --git a/ext/hash/tests/hash_serialize_001.phpt b/ext/hash/tests/hash_serialize_001.phpt
new file mode 100644 (file)
index 0000000..d515d2c
--- /dev/null
@@ -0,0 +1,361 @@
+--TEST--
+Hash: serialize()/unserialize()
+--FILE--
+<?php
+
+$algos = hash_algos();
+
+foreach ($algos as $algo) {
+    var_dump($algo);
+    $ctx0 = hash_init($algo);
+    $serial = serialize($ctx0);
+    assert(is_string($serial));
+
+    $ctx1 = unserialize($serial);
+    hash_update($ctx1, "I can't remember anything");
+    $serial = serialize($ctx1);
+    assert(is_string($serial));
+    var_dump(hash_final($ctx1));
+
+    $ctx2 = unserialize($serial);
+    var_dump(hash_final($ctx2));
+}
+
+// serialize/unserialize produces same results as all-on-one
+foreach ($algos as $algo) {
+    var_dump($algo);
+    $orig = hash_init($algo);
+    hash_update($orig, "I can't remember anything");
+    $serial = serialize($orig);
+
+    $fresh = hash_init($algo);
+    hash_update($fresh, "I can't remember anythingCan’t tell if this is true or dream");
+    var_dump(hash_final($fresh));
+
+    $copy = unserialize($serial);
+    hash_update($copy, "Can’t tell if this is true or dream");
+    var_dump(hash_final($copy));
+}
+
+echo "Done\n";
+?>
+--EXPECT--
+string(3) "md2"
+string(32) "d5ac4ffd08f6a57b9bd402b8068392ff"
+string(32) "d5ac4ffd08f6a57b9bd402b8068392ff"
+string(3) "md4"
+string(32) "302c45586b53a984bd3a1237cb81c15f"
+string(32) "302c45586b53a984bd3a1237cb81c15f"
+string(3) "md5"
+string(32) "e35759f6ea35db254e415b5332269435"
+string(32) "e35759f6ea35db254e415b5332269435"
+string(4) "sha1"
+string(40) "29f62a228f726cd728efa7a0ac6a2aba318baf15"
+string(40) "29f62a228f726cd728efa7a0ac6a2aba318baf15"
+string(6) "sha224"
+string(56) "51fd0aa76a00b4a86103895cad5c7c2651ec7da9f4fc1e50c43ede29"
+string(56) "51fd0aa76a00b4a86103895cad5c7c2651ec7da9f4fc1e50c43ede29"
+string(6) "sha256"
+string(64) "d3a13cf52af8e9390caed78b77b6b1e06e102204e3555d111dfd149bc5d54dba"
+string(64) "d3a13cf52af8e9390caed78b77b6b1e06e102204e3555d111dfd149bc5d54dba"
+string(6) "sha384"
+string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b4433d6e554e11e40a7cdcf510ea3"
+string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b4433d6e554e11e40a7cdcf510ea3"
+string(10) "sha512/224"
+string(56) "a2573d0e3f6c3e2d174c935a35a8ea31032f04e9e83499ac3ceda568"
+string(56) "a2573d0e3f6c3e2d174c935a35a8ea31032f04e9e83499ac3ceda568"
+string(10) "sha512/256"
+string(64) "fddacab80b3a610ba024c9d75a5fe0cafe5ae7c789f829b3c5fbea8ef11ccc1a"
+string(64) "fddacab80b3a610ba024c9d75a5fe0cafe5ae7c789f829b3c5fbea8ef11ccc1a"
+string(6) "sha512"
+string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
+string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
+string(8) "sha3-224"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(8) "sha3-256"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(8) "sha3-384"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(8) "sha3-512"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
+string(9) "ripemd128"
+string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
+string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
+string(9) "ripemd160"
+string(40) "02a2a535ee10404c6b5cf9acb178a04fbed67269"
+string(40) "02a2a535ee10404c6b5cf9acb178a04fbed67269"
+string(9) "ripemd256"
+string(64) "547d2ed85ca0a0e3208b5ecf4fc6a7fc1e64db8ff13493e4beaf11e4d71648e2"
+string(64) "547d2ed85ca0a0e3208b5ecf4fc6a7fc1e64db8ff13493e4beaf11e4d71648e2"
+string(9) "ripemd320"
+string(80) "785a7df56858f550966cddfd59ce14b13bf4b18e7892c4c1ad91bf23bf67639bd2c96749ba29cfa6"
+string(80) "785a7df56858f550966cddfd59ce14b13bf4b18e7892c4c1ad91bf23bf67639bd2c96749ba29cfa6"
+string(9) "whirlpool"
+string(128) "6e60597340640e621e25f975cef2b000b0c4c09a7af7d240a52d193002b0a8426fa7da7acc5b37ed9608016d4f396db834a0ea2f2c35f900461c9ac7e5604082"
+string(128) "6e60597340640e621e25f975cef2b000b0c4c09a7af7d240a52d193002b0a8426fa7da7acc5b37ed9608016d4f396db834a0ea2f2c35f900461c9ac7e5604082"
+string(10) "tiger128,3"
+string(32) "8d68e78bc5e62ba925a67aa48595cfc6"
+string(32) "8d68e78bc5e62ba925a67aa48595cfc6"
+string(10) "tiger160,3"
+string(40) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e0"
+string(40) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e0"
+string(10) "tiger192,3"
+string(48) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e08224fc35"
+string(48) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e08224fc35"
+string(10) "tiger128,4"
+string(32) "a26ca3f58e74fb32ee44b099cb1b5122"
+string(32) "a26ca3f58e74fb32ee44b099cb1b5122"
+string(10) "tiger160,4"
+string(40) "a26ca3f58e74fb32ee44b099cb1b512203375900"
+string(40) "a26ca3f58e74fb32ee44b099cb1b512203375900"
+string(10) "tiger192,4"
+string(48) "a26ca3f58e74fb32ee44b099cb1b512203375900f30b741d"
+string(48) "a26ca3f58e74fb32ee44b099cb1b512203375900f30b741d"
+string(6) "snefru"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(9) "snefru256"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(4) "gost"
+string(64) "5820c7c4a0650587538b30ef4099f2b5993069758d5c847a552e6ef7360766a5"
+string(64) "5820c7c4a0650587538b30ef4099f2b5993069758d5c847a552e6ef7360766a5"
+string(11) "gost-crypto"
+string(64) "f7c4e35548d66aabe2b106f20515d289fde90969225d3d7b83f6dd12d694f043"
+string(64) "f7c4e35548d66aabe2b106f20515d289fde90969225d3d7b83f6dd12d694f043"
+string(7) "adler32"
+string(8) "6f7c0928"
+string(8) "6f7c0928"
+string(5) "crc32"
+string(8) "e5cfc160"
+string(8) "e5cfc160"
+string(6) "crc32b"
+string(8) "69147a4e"
+string(8) "69147a4e"
+string(6) "crc32c"
+string(8) "5e405e93"
+string(8) "5e405e93"
+string(6) "fnv132"
+string(8) "98139504"
+string(8) "98139504"
+string(7) "fnv1a32"
+string(8) "aae4e042"
+string(8) "aae4e042"
+string(6) "fnv164"
+string(16) "14522659f8138684"
+string(16) "14522659f8138684"
+string(7) "fnv1a64"
+string(16) "bebc746a33b6ab62"
+string(16) "bebc746a33b6ab62"
+string(5) "joaat"
+string(8) "aaebf370"
+string(8) "aaebf370"
+string(10) "haval128,3"
+string(32) "86362472c8895e68e223ef8b3711d8d9"
+string(32) "86362472c8895e68e223ef8b3711d8d9"
+string(10) "haval160,3"
+string(40) "fabdf6905f3ba18a3c93d6a16b91e31f7222a7a4"
+string(40) "fabdf6905f3ba18a3c93d6a16b91e31f7222a7a4"
+string(10) "haval192,3"
+string(48) "e05d0ff5723028bd5494f32c0c2494cd0b9ccf7540af7b47"
+string(48) "e05d0ff5723028bd5494f32c0c2494cd0b9ccf7540af7b47"
+string(10) "haval224,3"
+string(56) "56b196289d8de8a22296588cf90e5b09cb6fa1b01ce8e92bca40cae2"
+string(56) "56b196289d8de8a22296588cf90e5b09cb6fa1b01ce8e92bca40cae2"
+string(10) "haval256,3"
+string(64) "ff4d7ab0fac2ca437b945461f9b62fd16e71e9103524d5d140445a00e3d49239"
+string(64) "ff4d7ab0fac2ca437b945461f9b62fd16e71e9103524d5d140445a00e3d49239"
+string(10) "haval128,4"
+string(32) "ee44418e0195a0c4a35d112722919a9c"
+string(32) "ee44418e0195a0c4a35d112722919a9c"
+string(10) "haval160,4"
+string(40) "f320cce982d5201a1ccacc1c5ff835a258a97eb1"
+string(40) "f320cce982d5201a1ccacc1c5ff835a258a97eb1"
+string(10) "haval192,4"
+string(48) "a96600107463e8e97a7fe6f260d9bf4f4587a281caafa6db"
+string(48) "a96600107463e8e97a7fe6f260d9bf4f4587a281caafa6db"
+string(10) "haval224,4"
+string(56) "7147c9e1c1e67b942da3229f59a1ab18f121f5d7f5765ca88bc9f200"
+string(56) "7147c9e1c1e67b942da3229f59a1ab18f121f5d7f5765ca88bc9f200"
+string(10) "haval256,4"
+string(64) "82fec42679ed5a77a841962827b88a9cddf7d677736e50bc81f1a14b99f06061"
+string(64) "82fec42679ed5a77a841962827b88a9cddf7d677736e50bc81f1a14b99f06061"
+string(10) "haval128,5"
+string(32) "8d0b157828328ae7d34d60b4b60c1dab"
+string(32) "8d0b157828328ae7d34d60b4b60c1dab"
+string(10) "haval160,5"
+string(40) "54dab5e10dc41503f9b8aa32ffe3bab7cf1da8a3"
+string(40) "54dab5e10dc41503f9b8aa32ffe3bab7cf1da8a3"
+string(10) "haval192,5"
+string(48) "7d91265a1b27698279d8d95a5ee0a20014528070bf6415e7"
+string(48) "7d91265a1b27698279d8d95a5ee0a20014528070bf6415e7"
+string(10) "haval224,5"
+string(56) "7772b2e22f2a3bce917e08cf57ebece46bb33168619a776c6f2f7234"
+string(56) "7772b2e22f2a3bce917e08cf57ebece46bb33168619a776c6f2f7234"
+string(10) "haval256,5"
+string(64) "438a602cb1a761f7bd0a633b7bd8b3ccd0577b524d05174ca1ae1f559b9a2c2a"
+string(64) "438a602cb1a761f7bd0a633b7bd8b3ccd0577b524d05174ca1ae1f559b9a2c2a"
+string(3) "md2"
+string(32) "5c36f61062d091a8324991132c5e8dbd"
+string(32) "5c36f61062d091a8324991132c5e8dbd"
+string(3) "md4"
+string(32) "1d4196526aada3506efb4c7425651584"
+string(32) "1d4196526aada3506efb4c7425651584"
+string(3) "md5"
+string(32) "f255c114bd6ce94aad092b5141c00d46"
+string(32) "f255c114bd6ce94aad092b5141c00d46"
+string(4) "sha1"
+string(40) "a273396f056554dcd491b5dea1e7baa3b89b802b"
+string(40) "a273396f056554dcd491b5dea1e7baa3b89b802b"
+string(6) "sha224"
+string(56) "1aee028400c56ceb5539625dc2f395abf491409336ca0f3e177a50e2"
+string(56) "1aee028400c56ceb5539625dc2f395abf491409336ca0f3e177a50e2"
+string(6) "sha256"
+string(64) "268e7f4cf88504a53fd77136c4c4748169f46ff7150b376569ada9c374836944"
+string(64) "268e7f4cf88504a53fd77136c4c4748169f46ff7150b376569ada9c374836944"
+string(6) "sha384"
+string(96) "0d44981d04bb11b1ef75d5c2932bd0aa2785e7bc454daac954d77e2ca10047879b58997533fc99650b20049c6cb9a6cc"
+string(96) "0d44981d04bb11b1ef75d5c2932bd0aa2785e7bc454daac954d77e2ca10047879b58997533fc99650b20049c6cb9a6cc"
+string(10) "sha512/224"
+string(56) "cbc2bbf0028ed803af785b0f264962c84ec48d8ee0908322ef995ddb"
+string(56) "cbc2bbf0028ed803af785b0f264962c84ec48d8ee0908322ef995ddb"
+string(10) "sha512/256"
+string(64) "2cec704878ffa7128e0c4a61eef87d1f3c823184d364dfa3fed73beb00499b00"
+string(64) "2cec704878ffa7128e0c4a61eef87d1f3c823184d364dfa3fed73beb00499b00"
+string(6) "sha512"
+string(128) "28d7c721433782a880f840af0c3f3ea2cad4ef55de2114dda9d504cedeb110e1cf2519c49e4b5da3da4484bb6ba4fd1621ceadc6408f4410b2ebe9d83a4202c2"
+string(128) "28d7c721433782a880f840af0c3f3ea2cad4ef55de2114dda9d504cedeb110e1cf2519c49e4b5da3da4484bb6ba4fd1621ceadc6408f4410b2ebe9d83a4202c2"
+string(8) "sha3-224"
+string(56) "9a21a5464794c2c9784df50cf89cf72234e11941bddaee93f912753e"
+string(56) "9a21a5464794c2c9784df50cf89cf72234e11941bddaee93f912753e"
+string(8) "sha3-256"
+string(64) "57aa7a90f29b5ab66592760592780da247fd39b4c911773687450f9df8cc8ed0"
+string(64) "57aa7a90f29b5ab66592760592780da247fd39b4c911773687450f9df8cc8ed0"
+string(8) "sha3-384"
+string(96) "5d6d7e42b241288bc707b74c50f90a37d69a4afa854ca72021a22cb379356e53b6233aea1be2f33d393d6effa9b5e36c"
+string(96) "5d6d7e42b241288bc707b74c50f90a37d69a4afa854ca72021a22cb379356e53b6233aea1be2f33d393d6effa9b5e36c"
+string(8) "sha3-512"
+string(128) "9b88c689bc13a36e6983b32e8ee9464d63b619f246ca451d1fe2a6c9670f01e71d0c8eb245f3204d27d27c056f2a0fef76a1e3bc30fb74cccbc984dbd4883ae6"
+string(128) "9b88c689bc13a36e6983b32e8ee9464d63b619f246ca451d1fe2a6c9670f01e71d0c8eb245f3204d27d27c056f2a0fef76a1e3bc30fb74cccbc984dbd4883ae6"
+string(9) "ripemd128"
+string(32) "f95f5e22b8875ee0c48219ae97f0674b"
+string(32) "f95f5e22b8875ee0c48219ae97f0674b"
+string(9) "ripemd160"
+string(40) "900d615c1abe714e340f4ecd6a3d65599fd30ff4"
+string(40) "900d615c1abe714e340f4ecd6a3d65599fd30ff4"
+string(9) "ripemd256"
+string(64) "b9799db40d1af5614118c329169cdcd2c718db6af03bf945ea7f7ba72b8e14f4"
+string(64) "b9799db40d1af5614118c329169cdcd2c718db6af03bf945ea7f7ba72b8e14f4"
+string(9) "ripemd320"
+string(80) "d6d12c1fca7a9c4a59c1be4f40188e92a746a035219e0a6ca1ee53b36a8282527187f7dffaa57ecc"
+string(80) "d6d12c1fca7a9c4a59c1be4f40188e92a746a035219e0a6ca1ee53b36a8282527187f7dffaa57ecc"
+string(9) "whirlpool"
+string(128) "e8c6a921e7d8eac2fd21d4df6054bb27a02321b2beb5b01b6f88c40706164e64d67ec97519bf76c8af8df896745478b78d42a0159f1a0db16777771fd9d420dc"
+string(128) "e8c6a921e7d8eac2fd21d4df6054bb27a02321b2beb5b01b6f88c40706164e64d67ec97519bf76c8af8df896745478b78d42a0159f1a0db16777771fd9d420dc"
+string(10) "tiger128,3"
+string(32) "a99d2c0348d480dc0f3c35852926e0f1"
+string(32) "a99d2c0348d480dc0f3c35852926e0f1"
+string(10) "tiger160,3"
+string(40) "a99d2c0348d480dc0f3c35852926e0f1e1825c16"
+string(40) "a99d2c0348d480dc0f3c35852926e0f1e1825c16"
+string(10) "tiger192,3"
+string(48) "a99d2c0348d480dc0f3c35852926e0f1e1825c1651957ee3"
+string(48) "a99d2c0348d480dc0f3c35852926e0f1e1825c1651957ee3"
+string(10) "tiger128,4"
+string(32) "66e2c0322421c4e5a9208e6aeed481e5"
+string(32) "66e2c0322421c4e5a9208e6aeed481e5"
+string(10) "tiger160,4"
+string(40) "66e2c0322421c4e5a9208e6aeed481e5c4b00448"
+string(40) "66e2c0322421c4e5a9208e6aeed481e5c4b00448"
+string(10) "tiger192,4"
+string(48) "66e2c0322421c4e5a9208e6aeed481e5c4b00448e344d9d0"
+string(48) "66e2c0322421c4e5a9208e6aeed481e5c4b00448e344d9d0"
+string(6) "snefru"
+string(64) "614ca924864fa0e8fa309aa0944e047d5edbfd4964a35858f4d8ec66a0fb88b0"
+string(64) "614ca924864fa0e8fa309aa0944e047d5edbfd4964a35858f4d8ec66a0fb88b0"
+string(9) "snefru256"
+string(64) "614ca924864fa0e8fa309aa0944e047d5edbfd4964a35858f4d8ec66a0fb88b0"
+string(64) "614ca924864fa0e8fa309aa0944e047d5edbfd4964a35858f4d8ec66a0fb88b0"
+string(4) "gost"
+string(64) "a00961e371287c71c527a41c14564f13b6ed12ac7cd9d5f5dfb3542a25e28d3b"
+string(64) "a00961e371287c71c527a41c14564f13b6ed12ac7cd9d5f5dfb3542a25e28d3b"
+string(11) "gost-crypto"
+string(64) "68ca9aea6729dc07d995fbe071a4b5c6490bb27fc4dc65ec0e96200d5e082996"
+string(64) "68ca9aea6729dc07d995fbe071a4b5c6490bb27fc4dc65ec0e96200d5e082996"
+string(7) "adler32"
+string(8) "d9141747"
+string(8) "d9141747"
+string(5) "crc32"
+string(8) "59f8d3d2"
+string(8) "59f8d3d2"
+string(6) "crc32b"
+string(8) "3ee63999"
+string(8) "3ee63999"
+string(6) "crc32c"
+string(8) "516ad412"
+string(8) "516ad412"
+string(6) "fnv132"
+string(8) "59ad036f"
+string(8) "59ad036f"
+string(7) "fnv1a32"
+string(8) "fadc2cef"
+string(8) "fadc2cef"
+string(6) "fnv164"
+string(16) "5e8c64fba6a5ffcf"
+string(16) "5e8c64fba6a5ffcf"
+string(7) "fnv1a64"
+string(16) "893899e4415a920f"
+string(16) "893899e4415a920f"
+string(5) "joaat"
+string(8) "836fb0e5"
+string(8) "836fb0e5"
+string(10) "haval128,3"
+string(32) "ebeeeb05c18af1e53d2d127b561d5e0d"
+string(32) "ebeeeb05c18af1e53d2d127b561d5e0d"
+string(10) "haval160,3"
+string(40) "f1a2c9604fb40899ad502abe0dfcec65115c8a9a"
+string(40) "f1a2c9604fb40899ad502abe0dfcec65115c8a9a"
+string(10) "haval192,3"
+string(48) "d3a7315773a326678208650ed02510ed96cd488d74cd5231"
+string(48) "d3a7315773a326678208650ed02510ed96cd488d74cd5231"
+string(10) "haval224,3"
+string(56) "6d7132fabc83c9ab7913748b79ecf10e25409569d3ed144177f46731"
+string(56) "6d7132fabc83c9ab7913748b79ecf10e25409569d3ed144177f46731"
+string(10) "haval256,3"
+string(64) "7a469868ad4b92891a3a44524c58a2b8d0f3bebb92b4cf47d19bc6aba973eb95"
+string(64) "7a469868ad4b92891a3a44524c58a2b8d0f3bebb92b4cf47d19bc6aba973eb95"
+string(10) "haval128,4"
+string(32) "6ecddb39615f43fd211839287ff38461"
+string(32) "6ecddb39615f43fd211839287ff38461"
+string(10) "haval160,4"
+string(40) "bcd2e7821723ac22e122b8b7cbbd2daaa9a862df"
+string(40) "bcd2e7821723ac22e122b8b7cbbd2daaa9a862df"
+string(10) "haval192,4"
+string(48) "ae74619a88dcec1fbecde28e27f009a65ecc12170824d2cd"
+string(48) "ae74619a88dcec1fbecde28e27f009a65ecc12170824d2cd"
+string(10) "haval224,4"
+string(56) "fdaba6563f1334d40de24e311f14b324577f97c3b78b9439c408cdca"
+string(56) "fdaba6563f1334d40de24e311f14b324577f97c3b78b9439c408cdca"
+string(10) "haval256,4"
+string(64) "289a2ba4820218bdb25a6534fbdf693f9de101362584fdd41e32244c719caa37"
+string(64) "289a2ba4820218bdb25a6534fbdf693f9de101362584fdd41e32244c719caa37"
+string(10) "haval128,5"
+string(32) "ffa7993a4e183b245263fb1f63e27343"
+string(32) "ffa7993a4e183b245263fb1f63e27343"
+string(10) "haval160,5"
+string(40) "375ee5ab3a9bd07a1dbe5d071e07b2afb3165e3b"
+string(40) "375ee5ab3a9bd07a1dbe5d071e07b2afb3165e3b"
+string(10) "haval192,5"
+string(48) "c650585f93c6e041e835caedc621f8c42d8bc6829fb76789"
+string(48) "c650585f93c6e041e835caedc621f8c42d8bc6829fb76789"
+string(10) "haval224,5"
+string(56) "bc674d465a822817d939f19b38edde083fe5668759836c203c56e3e4"
+string(56) "bc674d465a822817d939f19b38edde083fe5668759836c203c56e3e4"
+string(10) "haval256,5"
+string(64) "da70ad9bd09ed7c9675329ea2b5279d57761807c7aeac6340d94b5d494809457"
+string(64) "da70ad9bd09ed7c9675329ea2b5279d57761807c7aeac6340d94b5d494809457"
+Done
diff --git a/ext/hash/tests/hash_serialize_002.phpt b/ext/hash/tests/hash_serialize_002.phpt
new file mode 100644 (file)
index 0000000..b6b4ccf
--- /dev/null
@@ -0,0 +1,116 @@
+--TEST--
+Hash: serialize()/unserialize() with HASH_HMAC
+--FILE--
+<?php
+
+$algos = hash_algos();
+$non_crypto = ["adler32", "crc32", "crc32b", "crc32c", "fnv132", "fnv1a32", "fnv164", "fnv1a64", "joaat"];
+$key = "This is the key that I have";
+
+foreach ($algos as $algo) {
+    if (in_array($algo, $non_crypto)) {
+        continue;
+    }
+
+    var_dump($algo);
+    $ctx0 = hash_init($algo, HASH_HMAC, $key);
+    try {
+        $serial = serialize($ctx0);
+        assert(is_string($serial));
+    } catch (Throwable $e) {
+        echo $e->getMessage(), "\n";
+    }
+}
+
+echo "Done\n";
+?>
+--EXPECT--
+string(3) "md2"
+HashContext with HASH_HMAC option cannot be serialized
+string(3) "md4"
+HashContext with HASH_HMAC option cannot be serialized
+string(3) "md5"
+HashContext with HASH_HMAC option cannot be serialized
+string(4) "sha1"
+HashContext with HASH_HMAC option cannot be serialized
+string(6) "sha224"
+HashContext with HASH_HMAC option cannot be serialized
+string(6) "sha256"
+HashContext with HASH_HMAC option cannot be serialized
+string(6) "sha384"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "sha512/224"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "sha512/256"
+HashContext with HASH_HMAC option cannot be serialized
+string(6) "sha512"
+HashContext with HASH_HMAC option cannot be serialized
+string(8) "sha3-224"
+HashContext with HASH_HMAC option cannot be serialized
+string(8) "sha3-256"
+HashContext with HASH_HMAC option cannot be serialized
+string(8) "sha3-384"
+HashContext with HASH_HMAC option cannot be serialized
+string(8) "sha3-512"
+HashContext with HASH_HMAC option cannot be serialized
+string(9) "ripemd128"
+HashContext with HASH_HMAC option cannot be serialized
+string(9) "ripemd160"
+HashContext with HASH_HMAC option cannot be serialized
+string(9) "ripemd256"
+HashContext with HASH_HMAC option cannot be serialized
+string(9) "ripemd320"
+HashContext with HASH_HMAC option cannot be serialized
+string(9) "whirlpool"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "tiger128,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "tiger160,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "tiger192,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "tiger128,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "tiger160,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "tiger192,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(6) "snefru"
+HashContext with HASH_HMAC option cannot be serialized
+string(9) "snefru256"
+HashContext with HASH_HMAC option cannot be serialized
+string(4) "gost"
+HashContext with HASH_HMAC option cannot be serialized
+string(11) "gost-crypto"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval128,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval160,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval192,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval224,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval256,3"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval128,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval160,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval192,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval224,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval256,4"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval128,5"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval160,5"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval192,5"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval224,5"
+HashContext with HASH_HMAC option cannot be serialized
+string(10) "haval256,5"
+HashContext with HASH_HMAC option cannot be serialized
+Done
diff --git a/ext/hash/tests/hash_serialize_003.phpt b/ext/hash/tests/hash_serialize_003.phpt
new file mode 100644 (file)
index 0000000..a687c2a
--- /dev/null
@@ -0,0 +1,261 @@
+--TEST--
+Hash: serialization formats
+--FILE--
+<?php
+
+$serializations = [
+    [
+        "md2",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjM6Im1kMiI7aToxO2k6MDtpOjI7YTo0OntpOjA7czo0ODoiuyJG48A1rdYMPXAiWBDcbOrPsUaDg8lhMXhr/DQfjaN7dOqrImXTxBykKAln5L8sIjtpOjE7czoxNjoiwrfjcIJR1I8RljMyAxmcSyI7aToyO3M6MTY6IiBhbnl0aGluZwAAAAAAAAAiO2k6MztpOjk7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "md4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjM6Im1kNCI7aToxO2k6MDtpOjI7YTo3OntpOjA7aToxNzMyNTg0MTkzO2k6MTtpOi0yNzE3MzM4Nzk7aToyO2k6LTE3MzI1ODQxOTQ7aTozO2k6MjcxNzMzODc4O2k6NDtpOjIwMDtpOjU7aTowO2k6NjtzOjY0OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "md5",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjM6Im1kNSI7aToxO2k6MDtpOjI7YToyMzp7aTowO2k6MjU7aToxO2k6MDtpOjI7aToxNzMyNTg0MTkzO2k6MztpOi0yNzE3MzM4Nzk7aTo0O2k6LTE3MzI1ODQxOTQ7aTo1O2k6MjcxNzMzODc4O2k6NjtzOjY0OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjtpOjc7aTowO2k6ODtpOjA7aTo5O2k6MDtpOjEwO2k6MDtpOjExO2k6MDtpOjEyO2k6MDtpOjEzO2k6MDtpOjE0O2k6MDtpOjE1O2k6MDtpOjE2O2k6MDtpOjE3O2k6MDtpOjE4O2k6MDtpOjE5O2k6MDtpOjIwO2k6MDtpOjIxO2k6MDtpOjIyO2k6MDt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "sha1",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6InNoYTEiO2k6MTtpOjA7aToyO2E6ODp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aTotMTAwOTU4OTc3NjtpOjU7aToyMDA7aTo2O2k6MDtpOjc7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "sha224",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6InNoYTIyNCI7aToxO2k6MDtpOjI7YToxMTp7aTowO2k6LTEwNTY1OTYyNjQ7aToxO2k6OTE0MTUwNjYzO2k6MjtpOjgxMjcwMjk5OTtpOjM7aTotMTUwMDU0NTk5O2k6NDtpOi00MTkxNDM5O2k6NTtpOjE3NTA2MDMwMjU7aTo2O2k6MTY5NDA3NjgzOTtpOjc7aTotMTA5MDg5MTg2ODtpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6NjQ6IkkgY2FuJ3QgcmVtZW1iZXIgYW55dGhpbmcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO31pOjM7aToyO2k6NDthOjA6e319"
+    ],
+    [
+        "sha256",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6InNoYTI1NiI7aToxO2k6MDtpOjI7YToxMTp7aTowO2k6MTc3OTAzMzcwMztpOjE7aTotMTE1MDgzMzAxOTtpOjI7aToxMDEzOTA0MjQyO2k6MztpOi0xNTIxNDg2NTM0O2k6NDtpOjEzNTk4OTMxMTk7aTo1O2k6LTE2OTQxNDQzNzI7aTo2O2k6NTI4NzM0NjM1O2k6NztpOjE1NDE0NTkyMjU7aTo4O2k6MjAwO2k6OTtpOjA7aToxMDtzOjY0OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "sha384",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6InNoYTM4NCI7aToxO2k6MDtpOjI7YToyMTp7aTowO2k6LTEwNTY1OTYyNjQ7aToxO2k6LTg3Njg5NjkzMTtpOjI7aTo5MTQxNTA2NjM7aTozO2k6MTY1NDI3MDI1MDtpOjQ7aTo4MTI3MDI5OTk7aTo1O2k6LTE4NTY0Mzc5MjY7aTo2O2k6LTE1MDA1NDU5OTtpOjc7aTozNTU0NjIzNjA7aTo4O2k6LTQxOTE0Mzk7aTo5O2k6MTczMTQwNTQxNTtpOjEwO2k6MTc1MDYwMzAyNTtpOjExO2k6LTE5MDA3ODcwNjU7aToxMjtpOjE2OTQwNzY4Mzk7aToxMztpOi02MTk5NTg3NzE7aToxNDtpOi0xMDkwODkxODY4O2k6MTU7aToxMjAzMDYyODEzO2k6MTY7aToyMDA7aToxNztpOjA7aToxODtpOjA7aToxOTtpOjA7aToyMDtzOjEyODoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO31pOjM7aToyO2k6NDthOjA6e319"
+    ],
+    [
+        "sha512/224",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJzaGE1MTIvMjI0IjtpOjE7aTowO2k6MjthOjIxOntpOjA7aTo0MjQ5NTUyOTg7aToxO2k6LTE5NDIxNDUwODA7aToyO2k6LTE5ODIwMTYyOTg7aTozO2k6MTk0NDE2NDcxMDtpOjQ7aTo4NTU2MTI1NDY7aTo1O2k6NTAyOTcwMjg2O2k6NjtpOjE0Nzk1MTYxMTE7aTo3O2k6MTczODM5Njk0ODtpOjg7aToyMDc3NTExMDgwO2k6OTtpOjI1ODgxMjc3NztpOjEwO2k6Nzk5ODkwNTg7aToxMTtpOjIwMTEzOTM5MDc7aToxMjtpOjE3ODAyOTk0NjQ7aToxMztpOjEwNjcyODc5NzY7aToxNDtpOi0xODQ4MjA4NzM1O2k6MTU7aToyODY0NTEzNzM7aToxNjtpOjIwMDtpOjE3O2k6MDtpOjE4O2k6MDtpOjE5O2k6MDtpOjIwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "sha512/256",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJzaGE1MTIvMjU2IjtpOjE7aTowO2k6MjthOjIxOntpOjA7aTotNjQyMjc1NDA7aToxO2k6NTczNjQ1MjA0O2k6MjtpOi05MzQ1MTc1NjY7aTozO2k6LTE2MjE3OTQ5MDk7aTo0O2k6MTg2Nzc1NTg1NztpOjU7aTo1OTY4ODM1NjM7aTo2O2k6MTQ5NzQyNjYyMTtpOjc7aTotMTc3NDY4NDM5MTtpOjg7aTotMTQ2NzAyMzM4OTtpOjk7aTotMTc3NTc0NzM1ODtpOjEwO2k6MTQwMTMwNTQ5MDtpOjExO2k6LTExMDExMjgxNTU7aToxMjtpOjc0Njk2MTA2NjtpOjEzO2k6NzIxNTI1MjQ0O2k6MTQ7aTotMjExNzc4NDQxNDtpOjE1O2k6MjQ2ODg1ODUyO2k6MTY7aToyMDA7aToxNztpOjA7aToxODtpOjA7aToxOTtpOjA7aToyMDtzOjEyODoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO31pOjM7aToyO2k6NDthOjA6e319"
+    ],
+    [
+        "sha512",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6InNoYTUxMiI7aToxO2k6MDtpOjI7YToyMTp7aTowO2k6LTIwNTczMTU3NjtpOjE7aToxNzc5MDMzNzAzO2k6MjtpOi0yMDY3MDkzNzAxO2k6MztpOi0xMTUwODMzMDE5O2k6NDtpOi0yMzc5MTU3MztpOjU7aToxMDEzOTA0MjQyO2k6NjtpOjE1OTU3NTAxMjk7aTo3O2k6LTE1MjE0ODY1MzQ7aTo4O2k6LTEzNzc0MDIxNTk7aTo5O2k6MTM1OTg5MzExOTtpOjEwO2k6NzI1NTExMTk5O2k6MTE7aTotMTY5NDE0NDM3MjtpOjEyO2k6LTc5NTc3NzQ5O2k6MTM7aTo1Mjg3MzQ2MzU7aToxNDtpOjMyNzAzMzIwOTtpOjE1O2k6MTU0MTQ1OTIyNTtpOjE2O2k6MjAwO2k6MTc7aTowO2k6MTg7aTowO2k6MTk7aTowO2k6MjA7czoxMjg6IkkgY2FuJ3QgcmVtZW1iZXIgYW55dGhpbmcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "ripemd128",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjk6InJpcGVtZDEyOCI7aToxO2k6MDtpOjI7YTo3OntpOjA7aToxNzMyNTg0MTkzO2k6MTtpOi0yNzE3MzM4Nzk7aToyO2k6LTE3MzI1ODQxOTQ7aTozO2k6MjcxNzMzODc4O2k6NDtpOjIwMDtpOjU7aTowO2k6NjtzOjY0OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "ripemd160",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjk6InJpcGVtZDE2MCI7aToxO2k6MDtpOjI7YTo4OntpOjA7aToxNzMyNTg0MTkzO2k6MTtpOi0yNzE3MzM4Nzk7aToyO2k6LTE3MzI1ODQxOTQ7aTozO2k6MjcxNzMzODc4O2k6NDtpOi0xMDA5NTg5Nzc2O2k6NTtpOjIwMDtpOjY7aTowO2k6NztzOjY0OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "ripemd256",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjk6InJpcGVtZDI1NiI7aToxO2k6MDtpOjI7YToxMTp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aToxOTg1MjI5MzI4O2k6NTtpOi0xOTA4ODc0NDtpOjY7aTotMTk4NTIyOTMyOTtpOjc7aToxOTA4ODc0MztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6NjQ6IkkgY2FuJ3QgcmVtZW1iZXIgYW55dGhpbmcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO31pOjM7aToyO2k6NDthOjA6e319"
+    ],
+    [
+        "ripemd320",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjk6InJpcGVtZDMyMCI7aToxO2k6MDtpOjI7YToxMzp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aTotMTAwOTU4OTc3NjtpOjU7aToxOTg1MjI5MzI4O2k6NjtpOi0xOTA4ODc0NDtpOjc7aTotMTk4NTIyOTMyOTtpOjg7aToxOTA4ODc0MztpOjk7aToxMDA5NTg5Nzc1O2k6MTA7aToyMDA7aToxMTtpOjA7aToxMjtzOjY0OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "whirlpool",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjk6IndoaXJscG9vbCI7aToxO2k6MDtpOjI7YToyMDp7aTowO2k6MDtpOjE7aTowO2k6MjtpOjA7aTozO2k6MDtpOjQ7aTowO2k6NTtpOjA7aTo2O2k6MDtpOjc7aTowO2k6ODtpOjA7aTo5O2k6MDtpOjEwO2k6MDtpOjExO2k6MDtpOjEyO2k6MDtpOjEzO2k6MDtpOjE0O2k6MDtpOjE1O2k6MDtpOjE2O3M6MzI6IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADIIjtpOjE3O2k6MjU7aToxODtpOjIwMDtpOjE5O3M6NjQ6IkkgY2FuJ3QgcmVtZW1iZXIgYW55dGhpbmcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO31pOjM7aToyO2k6NDthOjA6e319"
+    ],
+    [
+        "tiger128,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJ0aWdlcjEyOCwzIjtpOjE7aTowO2k6MjthOjEwOntpOjA7aTotMTk4NTIyOTMyOTtpOjE7aToxOTA4ODc0MztpOjI7aToxOTg1MjI5MzI4O2k6MztpOi0xOTA4ODc0NDtpOjQ7aTotMTAxMTY4NzAzMztpOjU7aTotMjU4NTYyNjM2O2k6NjtpOjA7aTo3O2k6MDtpOjg7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7aTo5O2k6MjU7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "tiger160,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJ0aWdlcjE2MCwzIjtpOjE7aTowO2k6MjthOjEwOntpOjA7aTotMTk4NTIyOTMyOTtpOjE7aToxOTA4ODc0MztpOjI7aToxOTg1MjI5MzI4O2k6MztpOi0xOTA4ODc0NDtpOjQ7aTotMTAxMTY4NzAzMztpOjU7aTotMjU4NTYyNjM2O2k6NjtpOjA7aTo3O2k6MDtpOjg7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7aTo5O2k6MjU7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "tiger192,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJ0aWdlcjE5MiwzIjtpOjE7aTowO2k6MjthOjEwOntpOjA7aTotMTk4NTIyOTMyOTtpOjE7aToxOTA4ODc0MztpOjI7aToxOTg1MjI5MzI4O2k6MztpOi0xOTA4ODc0NDtpOjQ7aTotMTAxMTY4NzAzMztpOjU7aTotMjU4NTYyNjM2O2k6NjtpOjA7aTo3O2k6MDtpOjg7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7aTo5O2k6MjU7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "tiger128,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJ0aWdlcjEyOCw0IjtpOjE7aTowO2k6MjthOjEwOntpOjA7aTotMTk4NTIyOTMyOTtpOjE7aToxOTA4ODc0MztpOjI7aToxOTg1MjI5MzI4O2k6MztpOi0xOTA4ODc0NDtpOjQ7aTotMTAxMTY4NzAzMztpOjU7aTotMjU4NTYyNjM2O2k6NjtpOjA7aTo3O2k6MDtpOjg7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7aTo5O2k6MjU7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "tiger160,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJ0aWdlcjE2MCw0IjtpOjE7aTowO2k6MjthOjEwOntpOjA7aTotMTk4NTIyOTMyOTtpOjE7aToxOTA4ODc0MztpOjI7aToxOTg1MjI5MzI4O2k6MztpOi0xOTA4ODc0NDtpOjQ7aTotMTAxMTY4NzAzMztpOjU7aTotMjU4NTYyNjM2O2k6NjtpOjA7aTo3O2k6MDtpOjg7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7aTo5O2k6MjU7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "tiger192,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJ0aWdlcjE5Miw0IjtpOjE7aTowO2k6MjthOjEwOntpOjA7aTotMTk4NTIyOTMyOTtpOjE7aToxOTA4ODc0MztpOjI7aToxOTg1MjI5MzI4O2k6MztpOi0xOTA4ODc0NDtpOjQ7aTotMTAxMTY4NzAzMztpOjU7aTotMjU4NTYyNjM2O2k6NjtpOjA7aTo3O2k6MDtpOjg7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7aTo5O2k6MjU7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "snefru",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6InNuZWZydSI7aToxO2k6MDtpOjI7YToyMDp7aTowO2k6MDtpOjE7aTowO2k6MjtpOjA7aTozO2k6MDtpOjQ7aTowO2k6NTtpOjA7aTo2O2k6MDtpOjc7aTowO2k6ODtpOjA7aTo5O2k6MDtpOjEwO2k6MDtpOjExO2k6MDtpOjEyO2k6MDtpOjEzO2k6MDtpOjE0O2k6MDtpOjE1O2k6MDtpOjE2O2k6MDtpOjE3O2k6MjAwO2k6MTg7aToyNTtpOjE5O3M6MzI6IkkgY2FuJ3QgcmVtZW1iZXIgYW55dGhpbmcAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "snefru256",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6InNuZWZydSI7aToxO2k6MDtpOjI7YToyMDp7aTowO2k6MDtpOjE7aTowO2k6MjtpOjA7aTozO2k6MDtpOjQ7aTowO2k6NTtpOjA7aTo2O2k6MDtpOjc7aTowO2k6ODtpOjA7aTo5O2k6MDtpOjEwO2k6MDtpOjExO2k6MDtpOjEyO2k6MDtpOjEzO2k6MDtpOjE0O2k6MDtpOjE1O2k6MDtpOjE2O2k6MDtpOjE3O2k6MjAwO2k6MTg7aToyNTtpOjE5O3M6MzI6IkkgY2FuJ3QgcmVtZW1iZXIgYW55dGhpbmcAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "gost",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6Imdvc3QiO2k6MTtpOjA7aToyO2E6MjA6e2k6MDtpOjA7aToxO2k6MDtpOjI7aTowO2k6MztpOjA7aTo0O2k6MDtpOjU7aTowO2k6NjtpOjA7aTo3O2k6MDtpOjg7aTowO2k6OTtpOjA7aToxMDtpOjA7aToxMTtpOjA7aToxMjtpOjA7aToxMztpOjA7aToxNDtpOjA7aToxNTtpOjA7aToxNjtpOjIwMDtpOjE3O2k6MDtpOjE4O2k6MjU7aToxOTtzOjMyOiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "gost-crypto",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjExOiJnb3N0LWNyeXB0byI7aToxO2k6MDtpOjI7YToyMDp7aTowO2k6MDtpOjE7aTowO2k6MjtpOjA7aTozO2k6MDtpOjQ7aTowO2k6NTtpOjA7aTo2O2k6MDtpOjc7aTowO2k6ODtpOjA7aTo5O2k6MDtpOjEwO2k6MDtpOjExO2k6MDtpOjEyO2k6MDtpOjEzO2k6MDtpOjE0O2k6MDtpOjE1O2k6MDtpOjE2O2k6MjAwO2k6MTc7aTowO2k6MTg7aToyNTtpOjE5O3M6MzI6IkkgY2FuJ3QgcmVtZW1iZXIgYW55dGhpbmcAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "adler32",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjc6ImFkbGVyMzIiO2k6MTtpOjA7aToyO2E6MTp7aTowO2k6MTg3MDM5OTc4NDt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "crc32",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjU6ImNyYzMyIjtpOjE7aTowO2k6MjthOjE6e2k6MDtpOi0xNjIzMzE0NDA2O31pOjM7aToyO2k6NDthOjA6e319"
+    ],
+    [
+        "crc32b",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6ImNyYzMyYiI7aToxO2k6MDtpOjI7YToxOntpOjA7aTotMTc2Mjk0OTcxMTt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "crc32c",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6ImNyYzMyYyI7aToxO2k6MDtpOjI7YToxOntpOjA7aTotMTU4MTI3NjgyMDt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "fnv132",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6ImZudjEzMiI7aToxO2k6MDtpOjI7YToxOntpOjA7aTotMTc0MzU0NzEzMjt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "fnv1a32",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjc6ImZudjFhMzIiO2k6MTtpOjA7aToyO2E6MTp7aTowO2k6LTE0Mjc4NDA5NTg7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "fnv164",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjY6ImZudjE2NCI7aToxO2k6MDtpOjI7YToyOntpOjA7aTotMTMyOTM4MTA4O2k6MTtpOjM0MDkyODA4OTt9aTozO2k6MjtpOjQ7YTowOnt9fQ=="
+    ],
+    [
+        "fnv1a64",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjc6ImZudjFhNjQiO2k6MTtpOjA7aToyO2E6Mjp7aTowO2k6ODY3NjA5NDQyO2k6MTtpOi0xMDk0OTQ1Njg2O31pOjM7aToyO2k6NDthOjA6e319"
+    ],
+    [
+        "joaat",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjU6ImpvYWF0IjtpOjE7aTowO2k6MjthOjE6e2k6MDtpOi0xNDY5OTExMTA7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval128,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDEyOCwzIjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval160,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDE2MCwzIjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval192,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDE5MiwzIjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval224,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDIyNCwzIjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval256,3",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDI1NiwzIjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval128,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDEyOCw0IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval160,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDE2MCw0IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval192,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDE5Miw0IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval224,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDIyNCw0IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval256,4",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDI1Niw0IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval128,5",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDEyOCw1IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval160,5",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDE2MCw1IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval192,5",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDE5Miw1IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval224,5",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDIyNCw1IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "haval256,5",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjEwOiJoYXZhbDI1Niw1IjtpOjE7aTowO2k6MjthOjExOntpOjA7aTo2MDgxMzU4MTY7aToxO2k6LTIwNTI5MTI5NDE7aToyO2k6MzIwNDQwODc4O2k6MztpOjU3NzAxMTg4O2k6NDtpOi0xNTQyODk5Njc4O2k6NTtpOjY5ODI5ODgzMjtpOjY7aToxMzcyOTY1MzY7aTo3O2k6LTMzMDQwNDcyNztpOjg7aToyMDA7aTo5O2k6MDtpOjEwO3M6MTI4OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0="
+    ],
+    [
+        "sha3-224",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMjI0IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCCNmpKakp2ajd+ekYaLl5aRZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDA7aTo0O2E6MDp7fX0=", /* 64-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMjI0IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiCZk6DkJFV0S8u4vLRUZWVJDajqlEZ2R2CwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDE7aTo0O2E6MDp7fX0=", /* 32-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMjI0IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToyO2k6NDthOjA6e319" /* slow */
+    ],
+    [
+        "sha3-256",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMjU2IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCCNmpKakp2ajd+ekYaLl5aRZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDA7aTo0O2E6MDp7fX0=", /* 64-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMjU2IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiCZk6DkJFV0S8u4vLRUZWVJDajqlEZ2R2CwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDE7aTo0O2E6MDp7fX0=", /* 32-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMjU2IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToyO2k6NDthOjA6e319" /* slow */
+    ],
+    [
+        "sha3-384",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMzg0IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCCNmpKakp2ajd+ekYaLl5aRZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDA7aTo0O2E6MDp7fX0=", /* 64-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMzg0IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiCZk6DkJFV0S8u4vLRUZWVJDajqlEZ2R2CwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDE7aTo0O2E6MDp7fX0=", /* 32-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtMzg0IjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToyO2k6NDthOjA6e319" /* slow */
+    ],
+    [
+        "sha3-512",
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtNTEyIjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCCNmpKakp2ajd+ekYaLl5aRZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDA7aTo0O2E6MDp7fX0=", /* 64-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtNTEyIjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiCZk6DkJFV0S8u4vLRUZWVJDajqlEZ2R2CwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToxMDE7aTo0O2E6MDp7fX0=", /* 32-bit fast LE */
+        "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjg6InNoYTMtNTEyIjtpOjE7aTowO2k6MjthOjI6e2k6MDtzOjIwMDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiO2k6MTtpOjI1O31pOjM7aToyO2k6NDthOjA6e319" /* slow */
+    ]
+];
+
+
+function test_serialization($serial, $hash, $algo) {
+    try {
+        $ctx = unserialize(base64_decode($serial));
+        hash_update($ctx, "Can’t tell if this is true or dream");
+        $hash2 = hash_final($ctx);
+        if ($hash !== $hash2) {
+            echo "$algo: unexpected hash $hash2 for serialization {$serial}\n";
+        }
+    } catch (Throwable $e) {
+        echo "$algo: problem with serialization {$serial}\n";
+        echo "  ", $e->getMessage(), "\n", $e->getTraceAsString();
+    }
+}
+
+foreach ($serializations as $slist) {
+    $algo = $slist[0];
+    $hash = hash($algo, "I can't remember anythingCan’t tell if this is true or dream");
+
+    $ctx = hash_init($algo);
+    hash_update($ctx, "I can't remember anything");
+    $serial = base64_encode(serialize($ctx));
+    if (!in_array($serial, $slist)) {
+        echo "$algo: unexpected serialization $serial\n";
+    }
+
+    test_serialization($serial, $hash, $algo);
+}
+
+echo "Done\n";
+?>
+--EXPECT--
+Done
diff --git a/ext/hash/tests/hash_serialize_004.phpt b/ext/hash/tests/hash_serialize_004.phpt
new file mode 100644 (file)
index 0000000..ee5c08f
--- /dev/null
@@ -0,0 +1,45 @@
+--TEST--
+Hash: serialization errors
+--FILE--
+<?php
+
+// cannot unserialize onto an already-initialized object
+$ctx = hash_init("sha256");
+try {
+    $ctx->__unserialize($ctx->__serialize());
+} catch (Exception $e) {
+    echo $e->getMessage(), "\n";
+}
+
+// bad formats
+foreach ([
+    "TzoxMToiSGFzaENvbnRleHQiOjA6e30=", // no contents
+    "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtpOjE7aToxO2k6MDtpOjI7YTo4OntpOjA7aToxNzMyNTg0MTkzO2k6MTtpOi0yNzE3MzM4Nzk7aToyO2k6LTE3MzI1ODQxOTQ7aTozO2k6MjcxNzMzODc4O2k6NDtpOi0xMDA5NTg5Nzc2O2k6NTtpOjIwMDtpOjY7aTowO2k6NztzOjY0OiJJIGNhbid0IHJlbWVtYmVyIGFueXRoaW5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIjt9aTozO2k6MjtpOjQ7YTowOnt9fQ==", // algorithm is int
+    "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6InNoYTEiO2k6MTtzOjA6IiI7aToyO2E6ODp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aTotMTAwOTU4OTc3NjtpOjU7aToyMDA7aTo2O2k6MDtpOjc7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0=", // flags are string
+    "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6InNoYTEiO2k6MTtpOjE7aToyO2E6ODp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aTotMTAwOTU4OTc3NjtpOjU7aToyMDA7aTo2O2k6MDtpOjc7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0=", // flags indicate HASH_HMAC
+    "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6InNoYTEiO2k6MTtpOjI7aToyO3M6MTA6ImFiY2RlZmdoaWoiO2k6MztpOjI7aTo0O2E6MDp7fX0=", // serialization format wrong
+    "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6InNoYTEiO2k6MTtpOjA7aToyO2E6ODp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aTotMTAwOTU4OTc3NjtpOjU7aToyMDA7aTo2O3M6MDoiIjtpOjc7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0=", // serialization internals wrong
+    "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6InNoYTEiO2k6MTtpOjA7aToyO2E6ODp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aTotMTAwOTU4OTc3NjtpOjU7aToyMDA7aTo2O2k6MDtpOjc7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjA7aTo0O2E6MDp7fX0=", // bad magic number
+    "TzoxMToiSGFzaENvbnRleHQiOjU6e2k6MDtzOjQ6Inh4eDEiO2k6MTtpOjA7aToyO2E6ODp7aTowO2k6MTczMjU4NDE5MztpOjE7aTotMjcxNzMzODc5O2k6MjtpOi0xNzMyNTg0MTk0O2k6MztpOjI3MTczMzg3ODtpOjQ7aTotMTAwOTU4OTc3NjtpOjU7aToyMDA7aTo2O2k6MDtpOjc7czo2NDoiSSBjYW4ndCByZW1lbWJlciBhbnl0aGluZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACI7fWk6MztpOjI7aTo0O2E6MDp7fX0=" // bad algorithm
+] as $serial) {
+    try {
+        $ctx = unserialize(base64_decode($serial));
+        echo "Unexpected success\n";
+    } catch (Exception $e) {
+        echo $e->getMessage(), "\n";
+    }
+}
+
+echo "Done\n";
+?>
+--EXPECT--
+HashContext::__unserialize called on initialized object
+Incomplete or ill-formed serialization data
+Incomplete or ill-formed serialization data
+Incomplete or ill-formed serialization data
+HashContext with HASH_HMAC option cannot be serialized
+Incomplete or ill-formed serialization data ("sha1" code -1)
+Incomplete or ill-formed serialization data ("sha1" code -1024)
+Incomplete or ill-formed serialization data ("sha1" code -1)
+Unknown hash algorithm
+Done
diff --git a/ext/hash/tests/serialize-context.phpt b/ext/hash/tests/serialize-context.phpt
deleted file mode 100644 (file)
index 32aa0ab..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
---TEST--
-Hash: Context serialization
---FILE--
-<?php
-
-$h = hash_init('md5');
-try {
-  var_dump(serialize($h));
-} catch (Exception $e) {
-  echo "Exception: {$e->getMessage()}\n";
-}
---EXPECT--
-Exception: Serialization of 'HashContext' is not allowed
index 15417990d7bf79ff09c1a032b78007feb0107c60..ac60d7fca4cdaf1378596f73126ed90583fc74bb 100644 (file)
@@ -40,6 +40,7 @@ typedef struct {
        unsigned char buffer[64];
        uint32_t block[16];
 } PHP_MD5_CTX;
+#define PHP_MD5_SPEC "llllllb64l16."
 
 PHPAPI void PHP_MD5Init(PHP_MD5_CTX *ctx);
 PHPAPI void PHP_MD5Update(PHP_MD5_CTX *ctx, const void *data, size_t size);
index c904969dd36febbaf8ea71deba95a812c381fde2..ef98ecc29cc895da9af0e482fa1effc63a9de944 100644 (file)
@@ -25,6 +25,7 @@ typedef struct {
        uint32_t count[2];              /* number of bits, modulo 2^64 (lsb first) */
        unsigned char buffer[64];       /* input buffer */
 } PHP_SHA1_CTX;
+#define PHP_SHA1_SPEC "l5l2b64."
 
 PHPAPI void PHP_SHA1Init(PHP_SHA1_CTX *);
 PHPAPI void PHP_SHA1Update(PHP_SHA1_CTX *, const unsigned char *, size_t);