README | 2 + src/base/Makefile.am | 17 ++++-- src/base/hash.cc | 28 +++++++++++ src/base/hash.h | 67 +++++++++++++++++++++++++++ src/base/tests/hash_test.cc | 109 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 217 insertions(+), 6 deletions(-)
Add a function that takes a string as input and returns another string which is a hash of the input string generated using a collision-resistant hash function. diff --git a/README b/README --- a/README +++ b/README @@ -425,6 +425,7 @@ The following software is required to bu * libc6-dev (2.11 or later) * libxml2-dev (2.7 or later) + * libssl-dev (0.9.8 or later) * automake (1.11.1 or later) * m4 * autoconf (2.64 or later) @@ -959,6 +960,7 @@ minimum version requirements of the foll - GNU C Library (Glibc), version 2.11 or later - GNU Compiler Collection (GCC), version 4.8.1 or later - Libxml2, version 2.7 or later +- Libopenssl, version 0.9.8 or later - Libsqlite3, version 3.6 or later (only needed when configuring with --enable-imm-pbe) - OpenHPI, version 2.17.0 or later (only needed when configuring with diff --git a/src/base/Makefile.am b/src/base/Makefile.am --- a/src/base/Makefile.am +++ b/src/base/Makefile.am @@ -35,6 +35,7 @@ lib_libopensaf_core_la_SOURCES += \ src/base/daemon.c \ src/base/file_notify.cc \ src/base/getenv.cc \ + src/base/hash.cc \ src/base/hj_dec.c \ src/base/hj_edp.c \ src/base/hj_edu.c \ @@ -79,6 +80,7 @@ noinst_HEADERS += \ src/base/daemon.h \ src/base/file_notify.h \ src/base/getenv.h \ + src/base/hash.h \ src/base/log_message.h \ src/base/logtrace.h \ src/base/macros.h \ @@ -176,16 +178,19 @@ bin_libbase_test_CPPFLAGS = \ bin_libbase_test_LDFLAGS = \ $(AM_LDFLAGS) \ - src/base/lib_libopensaf_core_la-unix_socket.lo \ - src/base/lib_libopensaf_core_la-unix_server_socket.lo \ + -lcrypto \ + src/base/lib_libopensaf_core_la-file_notify.lo \ src/base/lib_libopensaf_core_la-getenv.lo \ + src/base/lib_libopensaf_core_la-hash.lo \ src/base/lib_libopensaf_core_la-log_message.lo \ src/base/lib_libopensaf_core_la-process.lo \ - src/base/lib_libopensaf_core_la-file_notify.lo + src/base/lib_libopensaf_core_la-unix_server_socket.lo \ + src/base/lib_libopensaf_core_la-unix_socket.lo bin_libbase_test_SOURCES = \ - src/base/tests/unix_socket_test.cc \ + src/base/tests/file_notify_test.cc \ src/base/tests/getenv_test.cc \ + src/base/tests/hash_test.cc \ src/base/tests/log_message_test.cc \ src/base/tests/mock_logtrace.cc \ src/base/tests/mock_osaf_abort.cc \ @@ -193,8 +198,8 @@ bin_libbase_test_SOURCES = \ src/base/tests/time_add_test.cc \ src/base/tests/time_compare_test.cc \ src/base/tests/time_convert_test.cc \ - src/base/tests/file_notify_test.cc \ - src/base/tests/time_subtract_test.cc + src/base/tests/time_subtract_test.cc \ + src/base/tests/unix_socket_test.cc bin_libbase_test_LDADD = \ $(GTEST_DIR)/lib/libgtest.la \ diff --git a/src/base/hash.cc b/src/base/hash.cc new file mode 100644 --- /dev/null +++ b/src/base/hash.cc @@ -0,0 +1,28 @@ +/* -*- OpenSAF -*- + * + * Copyright Ericsson AB 2017 - All Rights Reserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed + * under the GNU Lesser General Public License Version 2.1, February 1999. + * The complete license can be accessed from the following location: + * http://opensource.org/licenses/lgpl-license.php + * See the Copying file included with the OpenSAF distribution for full + * licensing terms. + * + */ + +#include "base/hash.h" + +namespace base { + +const char kHashFunctionAlphabet[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '-', '_' +}; + +} // namespace base diff --git a/src/base/hash.h b/src/base/hash.h new file mode 100644 --- /dev/null +++ b/src/base/hash.h @@ -0,0 +1,67 @@ +/* -*- OpenSAF -*- + * + * Copyright Ericsson AB 2017 - All Rights Reserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed + * under the GNU Lesser General Public License Version 2.1, February 1999. + * The complete license can be accessed from the following location: + * http://opensource.org/licenses/lgpl-license.php + * See the Copying file included with the OpenSAF distribution for full + * licensing terms. + * + */ + +#ifndef BASE_HASH_H_ +#define BASE_HASH_H_ + +#include <openssl/sha.h> +#include <cstdint> +#include <string> + +namespace base { + +extern const char kHashFunctionAlphabet[64]; + +// This function takes an arbitrary string as input parameter and returns +// another string which is a hash of the input string generated using a +// collision-resistant hash function. The probability that two different inputs +// would generate the same output is small enough that it can be safely ignored +// for all practical purposes. +// +// The return value of this function is a string of printable ASCII characters. +// The length of the returned string will always be exactly 32 characters, and +// the returned string is guaranteed to not contain any character that would be +// illegal for use in a file name. +// +// Note: if you use this function you need to link your program with -lcrypto +inline std::string Hash(const std::string& message) { + SHA512_CTX context; + SHA512_Init(&context); + context.h[0] = UINT64_C(0x010176140648b233); + context.h[1] = UINT64_C(0xdb92aeb1eebadd6f); + context.h[2] = UINT64_C(0x83a9e27aa1d5ea62); + context.h[3] = UINT64_C(0xec95f77eb609b4e1); + context.h[4] = UINT64_C(0x71a99185c75caefa); + context.h[5] = UINT64_C(0x006e8f08baf32e3c); + context.h[6] = UINT64_C(0x6a2b21abd2db2aec); + context.h[7] = UINT64_C(0x24926cdbd918a27f); + SHA512_Update(&context, message.data(), message.size()); + unsigned char result[SHA512_DIGEST_LENGTH]; + SHA512_Final(result, &context); + std::string encoded; + encoded.reserve(32); + for (int i = 0; i != 24; i += 3) { + uint64_t a = (result[i] << 16) | (result[i + 1] << 8) | result[i + 2]; + encoded.push_back(kHashFunctionAlphabet[a >> 18]); + encoded.push_back(kHashFunctionAlphabet[(a >> 12) & 63]); + encoded.push_back(kHashFunctionAlphabet[(a >> 6) & 63]); + encoded.push_back(kHashFunctionAlphabet[a & 63]); + } + return encoded; +} + +} // namespace base + +#endif // BASE_HASH_H_ diff --git a/src/base/tests/hash_test.cc b/src/base/tests/hash_test.cc new file mode 100644 --- /dev/null +++ b/src/base/tests/hash_test.cc @@ -0,0 +1,109 @@ +/* -*- OpenSAF -*- + * + * Copyright Ericsson AB 2017 - All Rights Reserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed + * under the GNU Lesser General Public License Version 2.1, February 1999. + * The complete license can be accessed from the following location: + * http://opensource.org/licenses/lgpl-license.php + * See the Copying file included with the OpenSAF distribution for full + * licensing terms. + * + */ + +#include <endian.h> +#include <cstddef> +#include <random> +#include <string> +#include "base/hash.h" +#include "gtest/gtest.h" + +struct TestVector { + const char* key_data; + size_t key_size; + const char* hash_value; +}; + +#define TEST_VECTOR(key, hash) { key, sizeof(key) - 1, hash } + +static const TestVector test_vectors[] = { + TEST_VECTOR("", "mJbyfHPNxOzI7KPhb27rY6_gS2wNOSds"), + TEST_VECTOR("\000", "U-4lHisMY1zsvi2ry5wqlYKUMhhb_MX8"), + TEST_VECTOR("\001", "7R0FXuGlh60oucbCoEIyp97oPDI34hNn"), + TEST_VECTOR("\376", "X-7TtfTMWhw7T9CK1-yk8bRAlF_544MB"), + TEST_VECTOR("\377", "OMGVy2Bhf3bPvd_yYKNVn8AK-EhkSJN4"), + TEST_VECTOR(" ", "LOR-HJ8c_bFoH7LVc45B67zrxvqNp2ih"), + TEST_VECTOR("\t", "jwSZSrsTHsB4kB2nUvpebPSpvDdt8d7V"), + TEST_VECTOR("\n", "WlgTrOkNrltdky0QZv1B3jMG0D73h3YC"), + TEST_VECTOR("\r\n", "pAv_qrHWSbOLxiJmXB2ETosp_FiE-G4H"), + TEST_VECTOR("\\/:", "wyC3ktDwB4tvyzXBO5zx_iH76GKFmjxB"), + TEST_VECTOR("$abc", "xSHQCvFJpVfx4ofdholD-mzgxyJJHjYg"), + TEST_VECTOR("\000\000\000\000\000", "mzklNJ6l6vWVe73PvthH61RRsl90ygC_"), + TEST_VECTOR("123456", "E_7JXvueRDhde3Wq3W5jYSsts_LOWJNZ"), + TEST_VECTOR("1234567", "0cAgD2NO2ASyz39axMrnBdV_VuHn2PhC"), + TEST_VECTOR("12345678", "Uzmag7xvTQg40VBwOumXaugZxFZyRpB8"), + TEST_VECTOR("123456789", "3YfQdE3kVpdmBEaBHM4uCj1feXvixjYA"), + TEST_VECTOR("\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355", + "z2V3p2mUUigcBkYWSEw0yhz2f1v4M8Nb"), + TEST_VECTOR("\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356", + "WprfN6xOSNY9RHaNCkR12yEEx5hGfwHj"), + TEST_VECTOR("\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356" + "\357", + "K3wQd-ZX5k7_AZ7p1qOwrehV5vkaJq9E"), + TEST_VECTOR("\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360", + "O-ERJdo-W-iCV4b2QogLJmtR1gMIhlkx") +}; + +TEST(BaseHash, TestVectors) { + for (size_t i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); ++i) { + std::string key = std::string(test_vectors[i].key_data, + test_vectors[i].key_size); + std::string hash = std::string(test_vectors[i].hash_value); + std::string computed_hash = base::Hash(key); + EXPECT_EQ(hash, computed_hash); + } +} + +TEST(BaseHash, LongRandomString) { + std::string key; + key.reserve(8000); + std::mt19937_64 generator(4711); + for (size_t i = 0; i != 1000; ++i) { + union { + char bytes[sizeof(uint64_t)]; + uint64_t word; + }; + word = htobe64(generator()); + key.append(bytes, sizeof(uint64_t)); + } + std::string hash = std::string("C_r2XVQjnVbnpQTMHO2OQJ2sn0YZi1py"); + std::string computed_hash = base::Hash(key); + EXPECT_EQ(hash, computed_hash); +} ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, SlashDot.org! http://sdm.link/slashdot _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel