From 77a68cbd4cf8b2614980e3be2849ca76c9695526 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] 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 c9f73934ee..bd62a52230 100644 --- a/lib/isc/siphash.c +++ b/lib/isc/siphash.c @@ -31,83 +31,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; @@ -118,20 +149,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 58baa89ab9..ceac73f148 100644 --- a/lib/isc/tests/siphash_test.c +++ b/lib/isc/tests/siphash_test.c @@ -17,6 +17,7 @@ #include #include +#include #include #define UNIT_TESTING @@ -24,7 +25,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, }, @@ -93,8 +122,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]; @@ -104,14 +134,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));