Hi Anders, I have few comments to the patch
The hash function will not work on big endian systems. Do we support only little endian systems or OpenSAF code should work on both endian systems ? Base64 has only encoding function. If something is going to be pushed to base directory, then I think is better to have full implementation, so that it can be used by other OpenSAF code, and not only for LOG. If the hash is for general purposes, then it should not be encoded by base64 at the end. Array of bytes should be returned from the hash. If it's needed, base64 can be done later on the returned array of bytes. BR, Zoran -----Original Message----- From: Anders Widell [mailto:anders.wid...@ericsson.com] Sent: den 21 februari 2017 11:45 To: ramesh.bet...@oracle.com Cc: opensaf-devel@lists.sourceforge.net Subject: [devel] [PATCH 1 of 1] base: Add a collision-resistant hash function [#2266] src/base/Makefile.am | 16 +- src/base/hash.cc | 239 ++++++++++++++++++++++++++++++++++++++++++++ src/base/hash.h | 32 +++++ src/base/tests/hash_test.cc | 109 ++++++++++++++++++++ 4 files changed, 390 insertions(+), 6 deletions(-) Add a function that returns a 32 character string which is generated by computing the SHA-512/192 hash of the message parameter, and encoding the result using Base64 with a URL and filename safe alphabet. For more information about these algorithms, refer to the corresponding standards. SHA-512/192 is defined in FIPS 180-4. Base64 is defined in RFC 4648. 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,18 @@ 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 \ + 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 +197,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,239 @@ +/* -*- 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" +#include <endian.h> +#include <cassert> +#include <cstdint> + +namespace base { + +namespace { + +constexpr uint64_t K[] = { + UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), + UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), + UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), + UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), + UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), + UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), + UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), + UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), + UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), + UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), + UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), + UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), + UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), + UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), + UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), + UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), + UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), + UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), + UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), + UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), + UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), + UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), + UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), + UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), + UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), + UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), + UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), + UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), + UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), + UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), + UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), + UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), + UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), + UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), + UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), + UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), + UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), + UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), + UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), + UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817) +}; + +constexpr inline uint64_t ROTR(int n, uint64_t x) { + return (x >> n) | (x << (64 - n)); +} + +constexpr inline uint64_t Ch(uint64_t x, uint64_t y, uint64_t z) { + return (x & y) ^ (~x & z); +} + +constexpr inline uint64_t Maj(uint64_t x, uint64_t y, uint64_t z) { + return (x & y) ^ (x & z) ^ (y & z); +} + +constexpr inline uint64_t SIGMA_0(uint64_t x) { + return ROTR(28, x) ^ ROTR(34, x) ^ ROTR(39, x); +} + +constexpr inline uint64_t SIGMA_1(uint64_t x) { + return ROTR(14, x) ^ ROTR(18, x) ^ ROTR(41, x); +} + +constexpr inline uint64_t sigma_0(uint64_t x) { + return ROTR(1, x) ^ ROTR(8, x) ^ (x >> 7); +} + +constexpr inline uint64_t sigma_1(uint64_t x) { + return ROTR(19, x) ^ ROTR(61, x) ^ (x >> 6); +} + +std::string CreatePadding(uint64_t message_size_in_bytes) { + assert(message_size_in_bytes < (uint64_t{1} << (64 - 3))); + uint64_t l = 8 * message_size_in_bytes; + uint64_t k = + ((((l + 1) % 1024) <= 896) ? 896 : (1024 + 896)) - ((l + 1) % 1024); + assert(((l + 1 + k + 128) % 1024) == 0); + std::string padding; + padding.reserve((1 + k + 128) / 8); + padding.push_back(static_cast<char>(0x80)); + padding.resize((1 + k + 64) / 8, static_cast<char>(0)); + for (int i = 56; i >= 0; i = i - 8) { + padding.push_back(static_cast<char>((l >> i) & 0xffu)); + } + return padding; +} + +inline uint64_t MessageByte(const std::string& msg, const std::string& padding, + uint64_t index) { + assert(index < (msg.size() + padding.size())); + return index < msg.size() ? static_cast<uint8_t>(msg[index]) : + static_cast<uint8_t>(padding[index - msg.size()]); +} + +inline uint64_t M(const std::string& msg, const std::string& padding, + uint64_t t, uint64_t i) { + assert(t <= 15 && i != 0); + uint64_t index = (i - 1) * 128 + t * 8; + return ((index + 7) < msg.size()) ? + be64toh(*reinterpret_cast<const uint64_t*>(msg.data() + index)) : + ((MessageByte(msg, padding, index + 0) << 56) | + (MessageByte(msg, padding, index + 1) << 48) | + (MessageByte(msg, padding, index + 2) << 40) | + (MessageByte(msg, padding, index + 3) << 32) | + (MessageByte(msg, padding, index + 4) << 24) | + (MessageByte(msg, padding, index + 5) << 16) | + (MessageByte(msg, padding, index + 6) << 8) | + (MessageByte(msg, padding, index + 7) << 0)); +} + +class Base64 { + public: + static std::string Encode(uint64_t H0, uint64_t H1, uint64_t H2) { + Base64 encoder; + encoder.encoded_.reserve(32); + encoder.Append192Bits(H0, H1, H2); + return encoder.encoded_; + } + + private: + static constexpr uint64_t kMask6Bits = (UINT64_C(1) << 6) - 1; + static constexpr uint64_t kMask8Bits = (UINT64_C(1) << 8) - 1; + static constexpr uint64_t kMask16Bits = (UINT64_C(1) << 16) - 1; + static constexpr uint64_t kMask24Bits = (UINT64_C(1) << 24) - 1; + static constexpr char kAlphabet[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', '-', '_' + }; + + void Append6Bits(uint64_t a) { + assert(a < (UINT64_C(1) << 6)); + encoded_.push_back(kAlphabet[a]); + } + + void Append24Bits(uint64_t a) { + assert(a < (UINT64_C(1) << 24)); + Append6Bits(a >> 18); + Append6Bits((a >> 12) & kMask6Bits); + Append6Bits((a >> 6) & kMask6Bits); + Append6Bits(a & kMask6Bits); + } + + void Append192Bits(uint64_t H0, uint64_t H1, uint64_t H2) { + Append24Bits(H0 >> 40); + Append24Bits((H0 >> 16) & kMask24Bits); + Append24Bits(((H0 & kMask16Bits) << 8) | (H1 >> 56)); + Append24Bits((H1 >> 32) & kMask24Bits); + Append24Bits((H1 >> 8) & kMask24Bits); + Append24Bits(((H1 & kMask8Bits) << 16) | (H2 >> 48)); + Append24Bits((H2 >> 24) & kMask24Bits); + Append24Bits(H2 & kMask24Bits); + } + + std::string encoded_{}; +}; + +constexpr char Base64::kAlphabet[64]; + +} // namespace + +std::string Hash(const std::string& message) { + uint64_t H0 = UINT64_C(0x010176140648b233); + uint64_t H1 = UINT64_C(0xdb92aeb1eebadd6f); + uint64_t H2 = UINT64_C(0x83a9e27aa1d5ea62); + uint64_t H3 = UINT64_C(0xec95f77eb609b4e1); + uint64_t H4 = UINT64_C(0x71a99185c75caefa); + uint64_t H5 = UINT64_C(0x006e8f08baf32e3c); + uint64_t H6 = UINT64_C(0x6a2b21abd2db2aec); + uint64_t H7 = UINT64_C(0x24926cdbd918a27f); + + std::string padding = CreatePadding(message.size()); + uint64_t N = (message.size() + padding.size()) / 128; + for (uint64_t i = 1; i <= N; ++i) { + uint64_t W[80]; + uint64_t a = H0; + uint64_t b = H1; + uint64_t c = H2; + uint64_t d = H3; + uint64_t e = H4; + uint64_t f = H5; + uint64_t g = H6; + uint64_t h = H7; + for (uint64_t t = 0; t <= 79; ++t) { + if (t <= 15) { + W[t] = M(message, padding, t, i); + } else { + W[t] = sigma_1(W[t - 2]) + W[t - 7] + sigma_0(W[t - 15]) + W[t - 16]; + } + uint64_t T1 = h + SIGMA_1(e) + Ch(e, f, g) + K[t] + W[t]; + uint64_t T2 = SIGMA_0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } + H0 += a; + H1 += b; + H2 += c; + H3 += d; + H4 += e; + H5 += f; + H6 += g; + H7 += h; + } + return Base64::Encode(H0, H1, H2); +} + +} // 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,32 @@ +/* -*- 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 <string> + +namespace base { + +// Returns a 32 character string which is generated by computing the SHA-512/192 +// hash of the message parameter, and encoding the result using Base64 with a +// URL and filename safe alphabet. For more information about these algorithms, +// refer to the corresponding standards. SHA-512/192 is defined in FIPS +// 180-4. Base64 is defined in RFC 4648. +std::string Hash(const std::string& message); + +} // 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 ------------------------------------------------------------------------------ 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