chunk: Add predictable hash function
authorTobias Brunner <tobias@strongswan.org>
Fri, 28 Jun 2013 10:12:41 +0000 (12:12 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 28 Jun 2013 15:00:29 +0000 (17:00 +0200)
Since chunk_hash() is randomized its output is not predictable, that is,
it is only within the same process.

src/libstrongswan/tests/test_chunk.c
src/libstrongswan/utils/chunk.c
src/libstrongswan/utils/chunk.h

index 4f60dab..7f07d05 100644 (file)
@@ -698,7 +698,6 @@ START_TEST(test_chunk_mac)
 }
 END_TEST
 
-
 /*******************************************************************************
  * test for chunk_hash[_inc]()
  */
@@ -722,6 +721,35 @@ START_TEST(test_chunk_hash)
 END_TEST
 
 /*******************************************************************************
+ * test for chunk_hash_static[_inc]()
+ */
+
+START_TEST(test_chunk_hash_static)
+{
+       chunk_t in;
+       u_int32_t out, hash_a, hash_b, hash_inc = 0x7b891a95;
+       int i, count;
+
+       count = countof(sip_vectors);
+       in = chunk_alloca(count);
+
+       for (i = 0; i < count; ++i)
+       {
+               in.ptr[i] = i;
+               in.len = i;
+               /* compared to chunk_mac() we only get half the value back */
+               out = chunk_hash_static(in);
+               fail_unless(memeq(&out, sip_vectors[i], 4),
+                                       "test vector failed for %d bytes", i);
+       }
+       hash_a = chunk_hash_static_inc(in, out);
+       ck_assert_int_eq(hash_a, hash_inc);
+       hash_b = chunk_hash_static_inc(in, out);
+       ck_assert_int_eq(hash_a, hash_b);
+}
+END_TEST
+
+/*******************************************************************************
  * printf_hook tests
  */
 
@@ -822,6 +850,10 @@ Suite *chunk_suite_create()
        tcase_add_test(tc, test_chunk_hash);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("chunk_hash_static");
+       tcase_add_test(tc, test_chunk_hash_static);
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("printf_hook");
        tcase_add_loop_test(tc, test_printf_hook_hash, 0, countof(printf_hook_data));
        tcase_add_loop_test(tc, test_printf_hook, 0, countof(printf_hook_data));
index 61c7bd5..04f3eea 100644 (file)
@@ -706,6 +706,12 @@ u_int64_t chunk_mac(chunk_t chunk, u_char *key)
 static u_char key[16];
 
 /**
+ * Static key used in case predictable hash values are required.
+ */
+static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                                                         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+
+/**
  * Only allocate the key once
  */
 static pthread_once_t key_allocated = PTHREAD_ONCE_INIT;
@@ -767,6 +773,22 @@ u_int32_t chunk_hash(chunk_t chunk)
 /**
  * Described in header.
  */
+u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash)
+{      /* we could use a mac of the previous hash, but this is faster */
+       return chunk_mac_inc(chunk, static_key, ((u_int64_t)hash) << 32 | hash);
+}
+
+/**
+ * Described in header.
+ */
+u_int32_t chunk_hash_static(chunk_t chunk)
+{
+       return chunk_mac(chunk, static_key);
+}
+
+/**
+ * Described in header.
+ */
 int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
                                          const void *const *args)
 {
index b9f2bf2..34ba773 100644 (file)
@@ -302,7 +302,13 @@ bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace);
 /**
  * Computes a 32 bit hash of the given chunk.
  *
- * @note This hash is only intended for hash tables not for cryptographic purposes.
+ * @note The output of this function is randomized, that is, it will only
+ * produce the same output for the same input when calling it from the same
+ * process.  For a more predictable hash function use chunk_hash_static()
+ * instead.
+ *
+ * @note This hash is only intended for hash tables not for cryptographic
+ * purposes.
  *
  * @param chunk                        data to hash
  * @return                             hash value
@@ -319,6 +325,30 @@ u_int32_t chunk_hash(chunk_t chunk);
 u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash);
 
 /**
+ * Computes a 32 bit hash of the given chunk.
+ *
+ * Compared to chunk_hash() this will always calculate the same output for the
+ * same input.  Therefore, it should not be used for hash tables (to prevent
+ * hash flooding).
+ *
+ * @note This hash is not intended for cryptographic purposes.
+ *
+ * @param chunk                        data to hash
+ * @return                             hash value
+ */
+u_int32_t chunk_hash_static(chunk_t chunk);
+
+/**
+ * Incremental version of chunk_hash_static(). Use this to hash two or more
+ * chunks in a predictable way.
+ *
+ * @param chunk                        data to hash
+ * @param hash                 previous hash value
+ * @return                             hash value
+ */
+u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash);
+
+/**
  * Computes a quick MAC from the given chunk and key using SipHash.
  *
  * The key must have a length of 128-bit (16 bytes).