From 6fd3259560eeb19e64c350571ae126492648ec00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 29 Aug 2019 13:59:52 +0200 Subject: [PATCH 1/3] Fix alignment issues in the native implementation of isc_siphash24() The native implementation's conversion from the uint8_t buffers to uint64_t now follows the reference implementation that doesn't require aligned buffers. --- lib/isc/include/isc/siphash.h | 2 +- lib/isc/siphash.c | 108 ++++++++++++++++++++++------------ lib/isc/tests/siphash_test.c | 56 +++++++++++++++++- 3 files changed, 123 insertions(+), 43 deletions(-) diff --git a/lib/isc/include/isc/siphash.h b/lib/isc/include/isc/siphash.h index 472e8f2253..1dd5318a8a 100644 --- a/lib/isc/include/isc/siphash.h +++ b/lib/isc/include/isc/siphash.h @@ -25,7 +25,7 @@ ISC_LANG_BEGINDECLS void isc_siphash24(const uint8_t *key, - const uint8_t *in, size_t inlen, + const uint8_t *in, const size_t inlen, uint8_t *out); ISC_LANG_ENDDECLS diff --git a/lib/isc/siphash.c b/lib/isc/siphash.c index 0b22ea8634..6319333c54 100644 --- a/lib/isc/siphash.c +++ b/lib/isc/siphash.c @@ -13,83 +13,114 @@ #include #include -#include - #include #include #include +/* + * The implementation is based on SipHash reference C implementation by + * + * Copyright (c) 2012-2016 Jean-Philippe Aumasson + * Copyright (c) 2012-2014 Daniel J. Bernstein + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. You should + * have received a copy of the CC0 Public Domain Dedication along with this + * software. If not, see . + */ + +#define cROUNDS 2 +#define dROUNDS 4 + #define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) -#define HALF_ROUND(a, b, c, d, s, t) \ - a += b; c += d; \ - b = ROTATE(b, s) ^ a; \ - d = ROTATE(d, t) ^ c; \ +#define HALF_ROUND(a, b, c, d, s, t) \ + a += b; c += d; \ + b = ROTATE(b, s) ^ a; \ + d = ROTATE(d, t) ^ c; \ a = ROTATE(a, 32); -#define FULL_ROUND(v0, v1, v2, v3) \ - HALF_ROUND(v0, v1, v2, v3, 13, 16); \ +#define FULL_ROUND(v0, v1, v2, v3) \ + HALF_ROUND(v0, v1, v2, v3, 13, 16); \ HALF_ROUND(v2, v1, v0, v3, 17, 21); -#define DOUBLE_ROUND(v0, v1, v2, v3) \ +#define DOUBLE_ROUND(v0, v1, v2, v3) \ FULL_ROUND(v0, v1, v2, v3) \ FULL_ROUND(v0, v1, v2, v3) #define SIPROUND FULL_ROUND +#define U32TO8_LE(p, v) \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (uint32_t)((v))); \ + U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ + ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ + ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ + ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) + void -isc_siphash24(const uint8_t *k, const uint8_t *in, size_t inlen, uint8_t *out) +isc_siphash24(const uint8_t *k, + const uint8_t *in, const size_t inlen, + uint8_t *out) { - const uint64_t *key = (const uint64_t *)k; - uint64_t k0 = le64toh(key[0]); - uint64_t k1 = le64toh(key[1]); + REQUIRE(k != NULL); + REQUIRE(out != NULL); + + uint64_t k0 = U8TO64_LE(k); + uint64_t k1 = U8TO64_LE(k + 8); uint64_t v0 = 0x736f6d6570736575ULL ^ k0; uint64_t v1 = 0x646f72616e646f6dULL ^ k1; uint64_t v2 = 0x6c7967656e657261ULL ^ k0; uint64_t v3 = 0x7465646279746573ULL ^ k1; - size_t left = inlen; - uint64_t b = ((uint64_t)inlen) << 56; - const uint64_t *inbuf = (const uint64_t *)in; - while (left >= 8) { - uint64_t m = le64toh(*inbuf); + const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); + const size_t left = inlen & 7; + + for (; in != end; in += 8) { + uint64_t m = U8TO64_LE(in); v3 ^= m; - SIPROUND(v0, v1, v2, v3); - SIPROUND(v0, v1, v2, v3); + for (size_t i = 0; i < cROUNDS; ++i) { + SIPROUND(v0, v1, v2, v3); + } v0 ^= m; - - inbuf++; left -= 8; } - const uint8_t *end = in + (inlen - left); - switch (left) { case 7: - b |= ((uint64_t)end[6]) << 48; + b |= ((uint64_t)in[6]) << 48; /* FALLTHROUGH */ case 6: - b |= ((uint64_t)end[5]) << 40; + b |= ((uint64_t)in[5]) << 40; /* FALLTHROUGH */ case 5: - b |= ((uint64_t)end[4]) << 32; + b |= ((uint64_t)in[4]) << 32; /* FALLTHROUGH */ case 4: - b |= ((uint64_t)end[3]) << 24; + b |= ((uint64_t)in[3]) << 24; /* FALLTHROUGH */ case 3: - b |= ((uint64_t)end[2]) << 16; + b |= ((uint64_t)in[2]) << 16; /* FALLTHROUGH */ case 2: - b |= ((uint64_t)end[1]) << 8; + b |= ((uint64_t)in[1]) << 8; /* FALLTHROUGH */ case 1: - b |= ((uint64_t)end[0]); + b |= ((uint64_t)in[0]); /* FALLTHROUGH */ case 0: break; @@ -100,20 +131,19 @@ isc_siphash24(const uint8_t *k, const uint8_t *in, size_t inlen, uint8_t *out) v3 ^= b; - SIPROUND(v0, v1, v2, v3); - SIPROUND(v0, v1, v2, v3); + for (size_t i = 0; i < cROUNDS; ++i) { + SIPROUND(v0, v1, v2, v3); + } v0 ^= b; v2 ^= 0xff; - SIPROUND(v0, v1, v2, v3); - SIPROUND(v0, v1, v2, v3); - SIPROUND(v0, v1, v2, v3); - SIPROUND(v0, v1, v2, v3); + for (size_t i = 0; i < dROUNDS; ++i) { + SIPROUND(v0, v1, v2, v3); + } b = v0 ^ v1 ^ v2 ^ v3; - uint64_t *outbuf = (uint64_t *)out; - *outbuf = htole64(b); + U64TO8_LE(out, b); } diff --git a/lib/isc/tests/siphash_test.c b/lib/isc/tests/siphash_test.c index b454741042..60ee8c4158 100644 --- a/lib/isc/tests/siphash_test.c +++ b/lib/isc/tests/siphash_test.c @@ -15,6 +15,7 @@ #include #include +#include #include #define UNIT_TESTING @@ -22,7 +23,35 @@ #include +void +native_isc_siphash24(const uint8_t *, + const uint8_t *, const size_t, + uint8_t *); + +#if HAVE_OPENSSL_SIPHASH + +void +openssl_isc_siphash24(const uint8_t *, + const uint8_t *, const size_t, + uint8_t *); + +#undef HAVE_OPENSSL_SIPHASH +#define isc_siphash24 native_isc_siphash24 #include "../siphash.c" +#undef isc_siphash24 + +#define HAVE_OPENSSL_SIPHASH 1 +#define isc_siphash24 openssl_isc_siphash24 +#include "../siphash.c" +#undef isc_siphash24 + +#else + +#define isc_siphash24 native_isc_siphash24 +#include "../siphash.c" +#undef isc_siphash24 + +#endif const uint8_t vectors[64][8] = { { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, @@ -91,8 +120,9 @@ const uint8_t vectors[64][8] = { { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }, }; +#if HAVE_OPENSSL_SIPHASH static void -isc_siphash24_test(void **state) { +openssl_isc_siphash24_test(void **state) { UNUSED(state); uint8_t in[64], out[8], key[16]; @@ -102,14 +132,34 @@ isc_siphash24_test(void **state) { for (int i = 0; i < 64; i++) { in[i] = i; - isc_siphash24(key, in, i, out); + openssl_isc_siphash24(key, in, i, out); + assert_memory_equal(out, vectors[i], 8); + } +} +#endif + +static void +native_isc_siphash24_test(void **state) { + UNUSED(state); + + uint8_t in[64], out[8], key[16]; + for (int i = 0; i < 16; i++) { + key[i] = i; + } + + for (int i = 0; i < 64; i++) { + in[i] = i; + native_isc_siphash24(key, in, i, out); assert_memory_equal(out, vectors[i], 8); } } int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test(isc_siphash24_test), +#if HAVE_OPENSSL_SIPHASH + cmocka_unit_test(openssl_isc_siphash24_test), +#endif + cmocka_unit_test(native_isc_siphash24_test), }; return (cmocka_run_group_tests(tests, NULL, NULL)); From 9b6c6f57d88232def3e76aaea862767f85ef669f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Fri, 30 Aug 2019 15:32:11 +0200 Subject: [PATCH 2/3] configure.ac: Add OpenSSL SipHash support detection Add check for creating new EVP_PKEY with EVP_PKEY_SIPHASH, but disable SipHash on OpenSSL 1.1.1 as the hash length initialization is broken before OpenSSL 1.1.1a release. --- config.h.in | 3 +++ configure | 30 ++++++++++++++++++++++++++++++ configure.ac | 13 +++++++++++++ 3 files changed, 46 insertions(+) diff --git a/config.h.in b/config.h.in index eeba105ec6..e2cf7e911e 100644 --- a/config.h.in +++ b/config.h.in @@ -279,6 +279,9 @@ /* define if OpenSSL supports Ed448 */ #undef HAVE_OPENSSL_ED448 +/* define if OpenSSL supports SipHash */ +#undef HAVE_OPENSSL_SIPHASH + /* Define to 1 if you have the `processor_bind' function. */ #undef HAVE_PROCESSOR_BIND diff --git a/configure b/configure index 757dacb06e..33f4fd8a3c 100755 --- a/configure +++ b/configure @@ -16596,6 +16596,36 @@ $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SipHash support" >&5 +$as_echo_n "checking for SipHash support... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include +int +main () +{ +#if OPENSSL_VERSION_NUMBER < 0x10101010L + #error OpenSSL >= 1.1.1a required for working SipHash initialization + #endif + EVP_PKEY *key = EVP_PKEY_new_raw_private_key( + EVP_PKEY_SIPHASH, NULL, NULL, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_OPENSSL_SIPHASH 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + # # Check for OpenSSL SHA-1 support # diff --git a/configure.ac b/configure.ac index b04c651966..9dacb39aa5 100644 --- a/configure.ac +++ b/configure.ac @@ -776,6 +776,19 @@ AC_COMPILE_IFELSE( AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) +AC_MSG_CHECKING([for SipHash support]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include + #include ]], + [[#if OPENSSL_VERSION_NUMBER < 0x10101010L + #error OpenSSL >= 1.1.1a required for working SipHash initialization + #endif + EVP_PKEY *key = EVP_PKEY_new_raw_private_key( + EVP_PKEY_SIPHASH, NULL, NULL, 0);]])], + [AC_DEFINE([HAVE_OPENSSL_SIPHASH], [1], [define if OpenSSL supports SipHash]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + # # Check for OpenSSL SHA-1 support # From 30b716d220331fe3d1e4110b097b728af58b394a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 29 Aug 2019 13:59:52 +0200 Subject: [PATCH 3/3] Add OpenSSL based isc_siphash24() implementation This commits adds an OpenSSL based isc_siphash24() implementation, which is preferred when available. The siphash_test has been modified to test both implementation with a trick that renames the isc_siphash24() to openssl_ or native_ prefixed name and includes the ../siphash.c two times (when the OpenSSL implementation is available). --- lib/isc/siphash.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lib/isc/siphash.c b/lib/isc/siphash.c index 6319333c54..23fff75192 100644 --- a/lib/isc/siphash.c +++ b/lib/isc/siphash.c @@ -17,6 +17,57 @@ #include #include +#if HAVE_OPENSSL_SIPHASH +#include + +void +isc_siphash24(const uint8_t *k, + const uint8_t *in, const size_t inlen, + uint8_t *out) +{ + REQUIRE(k != NULL); + REQUIRE(out != NULL); + size_t outlen = 8; + EVP_PKEY_CTX *pctx = NULL; + + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + EVP_PKEY *key = EVP_PKEY_new_raw_private_key(EVP_PKEY_SIPHASH, NULL, + k, 16); + RUNTIME_CHECK(mctx != NULL); + RUNTIME_CHECK(key != NULL); + + RUNTIME_CHECK(EVP_DigestSignInit(mctx, &pctx, NULL, NULL, key) == 1); + RUNTIME_CHECK(EVP_PKEY_CTX_ctrl(pctx, EVP_PKEY_SIPHASH, + EVP_PKEY_OP_SIGNCTX, + EVP_PKEY_CTRL_SET_DIGEST_SIZE, outlen, + NULL) == 1); + RUNTIME_CHECK(EVP_DigestSignUpdate(mctx, in, inlen) == 1); + RUNTIME_CHECK(EVP_DigestSignFinal(mctx, out, &outlen) == 1); + + ENSURE(outlen == 8); + + EVP_PKEY_free(key); + EVP_MD_CTX_free(mctx); +} + +#else /* HAVE_OPENSSL_SIPHASH */ + +/* + * The fallback implementation is based on SipHash reference C implementation by + * + * Copyright (c) 2012-2016 Jean-Philippe Aumasson + * Copyright (c) 2012-2014 Daniel J. Bernstein + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. You should + * have received a copy of the CC0 Public Domain Dedication along with this + * software. If not, see . + */ + +#define cROUNDS 2 +#define dROUNDS 4 + /* * The implementation is based on SipHash reference C implementation by * @@ -147,3 +198,4 @@ isc_siphash24(const uint8_t *k, U64TO8_LE(out, b); } +#endif /* HAVE_OPENSSL_SIPHASH */