From: Francis Dupont Date: Tue, 20 Feb 2018 15:32:45 +0000 (+0100) Subject: [5502] Added FNV-1a 64 bit hash and replaced MD5 in CQL host dats source X-Git-Tag: trac5525_base~5^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f055186394aed9ff1d58a051d77daeb50fc20aa4;p=thirdparty%2Fkea.git [5502] Added FNV-1a 64 bit hash and replaced MD5 in CQL host dats source --- diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index 037843bdb4..2816ea0279 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -17,7 +17,7 @@ if HAVE_PGSQL AM_CPPFLAGS += $(PGSQL_CPPFLAGS) endif if HAVE_CQL -AM_CPPFLAGS += $(CQL_CPPFLAGS) $(CRYPTO_INCLUDES) +AM_CPPFLAGS += $(CQL_CPPFLAGS) endif AM_CXXFLAGS = $(KEA_CXXFLAGS) diff --git a/src/lib/dhcpsrv/cql_host_data_source.cc b/src/lib/dhcpsrv/cql_host_data_source.cc index 3109794421..e9073848b1 100644 --- a/src/lib/dhcpsrv/cql_host_data_source.cc +++ b/src/lib/dhcpsrv/cql_host_data_source.cc @@ -28,13 +28,10 @@ #include #include #include +#include #include #include -/// @todo: With this include, Cassandra backend requires compilation with openssl. -/// Kea supports two crypto libs: openssl and botan. The abstraction layer provided -/// is via cryptolink. -#include // for MD5_DIGEST_LENGTH #include // for uint64_t #include // for boost::is_any_of @@ -185,9 +182,8 @@ public: /// @brief Create unique hash for storage in table id. /// /// Hash function used for creating a pseudo-unique hash from member - /// values which uniquely determine an entry in the table. Uses OpenSSL's - /// MD5 implementation. - /// @todo: This must be generic and use cryptolink wrapper. See ticket #5502. + /// values which uniquely determine an entry in the table. Uses FNV-1a + /// on 64 bits. /// /// The primary key aggregates: host_ipv4_subnet_id, host_ipv6_subnet_id, /// host_ipv4_address, reserved_ipv6_prefix_address, @@ -859,50 +855,25 @@ CqlHostExchange::createBindForMutation(const HostPtr& host, } } -uint64_t -md5Hash(const std::string& input) { - - /// @todo: Convert this code to cryptolink calls and replace the - /// direct use fromn md5. - - // Prepare structures for MD5(). - const size_t word_size = MD5_DIGEST_LENGTH / sizeof(uint64_t); - uint64_t hash[word_size]; - unsigned char* digest = reinterpret_cast(hash); - unsigned char* string = reinterpret_cast(const_cast(input.c_str())); - std::fill(hash, hash + word_size, 0); - - // Get MD5 hash value. - MD5(string, input.size(), digest); - - // Return the first part of the hash value which still retains all - // properties of the full hash value. - return (hash[0]); -} - cass_int64_t CqlHostExchange::hashIntoId() const { - // Allocates a fixed maximum length in the stringstream for each - // aggregated field to avoid collisions between distinct entries. + // Add a separator between aggregated field to avoid collisions + // between distinct entries. // Get key. std::stringstream key_stream; - key_stream << std::setw(10) << std::setfill('-') << host_ipv4_subnet_id_; - key_stream << std::setw(10) << std::setfill('-') << host_ipv6_subnet_id_; - key_stream << std::setw(V4ADDRESS_TEXT_MAX_LEN) << std::setfill('-') - << host_ipv4_address_; - key_stream << std::setw(V6ADDRESS_TEXT_MAX_LEN) << std::setfill('-') - << reserved_ipv6_prefix_address_; - key_stream << std::setw(4) << std::setfill('-') - << reserved_ipv6_prefix_length_; - key_stream << std::setw(4) << std::setfill('-') << option_code_; - key_stream << std::setw(OPTION_SPACE_MAX_LENGTH) << std::setfill('-') - << option_space_; + key_stream << host_ipv4_subnet_id_ << "-"; + key_stream << host_ipv6_subnet_id_ << "-"; + key_stream << host_ipv4_address_ << "-"; + key_stream << reserved_ipv6_prefix_address_ << "/"; + key_stream << reserved_ipv6_prefix_length_ << "-"; + key_stream << option_code_ << "-"; + key_stream << option_space_; const std::string key = key_stream.str(); - const cass_int64_t md5 = static_cast(md5Hash(key)); + const cass_int64_t hash = static_cast(Hash64::hash(key)); - return (md5); + return (hash); } boost::any @@ -1287,7 +1258,7 @@ private: /// @brief hash function for HostMap /// -/// Returns a 64-bits key value. The key is generated with MD5 hash +/// Returns a 64-bits key value. The key is generated with FNV-1a 64 bit /// algorithm. /// /// @param key being hashed @@ -1298,21 +1269,16 @@ hash_value(const HostKey& key) { // Get key. std::stringstream key_stream; HostIdentifier host_identifier = std::get(key); - key_stream << std::setw(DUID::MAX_DUID_LEN) << std::setfill('0') - << DUID(host_identifier).toText(); - key_stream << std::setw(2) << std::setfill('0') - << std::get(key); - key_stream << std::setw(10) << std::setfill('0') - << std::get(key); - key_stream << std::setw(10) << std::setfill('0') - << std::get(key); - key_stream << std::setw(V4ADDRESS_TEXT_MAX_LEN) << std::setfill('0') - << std::get(key); + key_stream << DUID(host_identifier).toText() << "-"; + key_stream << std::get(key) << "-"; + key_stream << std::get(key) << "-"; + key_stream << std::get(key) << "-"; + key_stream << std::get(key); const std::string key_string = key_stream.str(); - const uint64_t md5 = md5Hash(key_string); + const uint64_t hash = Hash64::hash(key_string); - return (static_cast(md5)); + return (static_cast(hash)); } /// @brief equals operator for HostKey diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am index 7c0bac0096..f2c684f3ca 100644 --- a/src/lib/util/Makefile.am +++ b/src/lib/util/Makefile.am @@ -11,6 +11,7 @@ libkea_util_la_SOURCES = boost_time_utils.h boost_time_utils.cc libkea_util_la_SOURCES += buffer.h io_utilities.h libkea_util_la_SOURCES += csv_file.h csv_file.cc libkea_util_la_SOURCES += filename.h filename.cc +libkea_util_la_SOURCES += hash.h libkea_util_la_SOURCES += labeled_value.h labeled_value.cc libkea_util_la_SOURCES += memory_segment.h libkea_util_la_SOURCES += memory_segment_local.h memory_segment_local.cc @@ -50,6 +51,7 @@ libkea_util_include_HEADERS = \ buffer.h \ csv_file.h \ filename.h \ + hash.h \ io_utilities.h \ labeled_value.h \ memory_segment.h \ diff --git a/src/lib/util/hash.h b/src/lib/util/hash.h new file mode 100644 index 0000000000..45d6ba5998 --- /dev/null +++ b/src/lib/util/hash.h @@ -0,0 +1,57 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef HASH_H +#define HASH_H + +#include +#include +#include + +namespace isc { +namespace util { + +/// @brief Hash implementation based on Fowler-Noll-Vo hash function +/// +struct Hash64 { + /// @brief Compute the hash + /// + /// FNV-1a hash function + /// + /// @param data data to hash + /// @param length length of data + /// @return the hash value + static uint64_t hash(const uint8_t* data, size_t length) { + uint64_t hash = FNV_offset_basis; + for (size_t i = 0; i < length; ++i) { + hash = hash ^ data[i]; + hash = hash * FNV_prime; + } + return (hash); + } + + /// @brief Compute the hash + /// + /// FNV-1a hash function + /// + /// @param str not empty string to hash + /// @return the hash value + static uint64_t hash(const std::string& str) { + return (hash(reinterpret_cast(str.c_str()), + str.size())); + } + + /// @brief Offset basis + static const uint64_t FNV_offset_basis = 14695981039346656037ull; + + /// @brief Prime + static const uint64_t FNV_prime = 1099511628211ull; +}; + +} // end of namespace isc::util +} // end of namespace isc + +#endif diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am index 301d94f2bb..c6b7173bfa 100644 --- a/src/lib/util/tests/Makefile.am +++ b/src/lib/util/tests/Makefile.am @@ -36,6 +36,7 @@ run_unittests_SOURCES += csv_file_unittest.cc run_unittests_SOURCES += fd_share_tests.cc run_unittests_SOURCES += fd_tests.cc run_unittests_SOURCES += filename_unittest.cc +run_unittests_SOURCES += hash_unittest.cc run_unittests_SOURCES += hex_unittest.cc run_unittests_SOURCES += io_utilities_unittest.cc run_unittests_SOURCES += labeled_value_unittest.cc diff --git a/src/lib/util/tests/hash_unittest.cc b/src/lib/util/tests/hash_unittest.cc new file mode 100644 index 0000000000..f789e51a8a --- /dev/null +++ b/src/lib/util/tests/hash_unittest.cc @@ -0,0 +1,34 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include + +#include + +#include +#include + +using namespace isc::util; +using namespace std; + +namespace { + +TEST(HashTest, empty) { + EXPECT_EQ(14695981039346656037ull, Hash64::hash(0, 0)); +} + +TEST(HashTest, foobar) { + EXPECT_EQ(9625390261332436968ull, Hash64::hash(string("foobar"))); +} + +TEST(HashTest, chongo) { + EXPECT_EQ(5080352029159061781ull, + Hash64::hash(string("chongo was here!\n"))); +} + +}