]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix alignment issues in the native implementation of isc_siphash24()
authorOndřej Surý <ondrej@sury.org>
Thu, 29 Aug 2019 11:59:52 +0000 (13:59 +0200)
committerOndřej Surý <ondrej@sury.org>
Mon, 2 Sep 2019 11:21:40 +0000 (13:21 +0200)
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
lib/isc/siphash.c
lib/isc/tests/siphash_test.c

index 472e8f225323ecb8dd5d0387eb54ce4189709d53..1dd5318a8a1562476f66a651447f34a38957c29e 100644 (file)
@@ -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
index c9f73934ee45133db1d43b03cc756510def5f082..bd62a52230191eb808b48ae4bf3aad2b9627a807 100644 (file)
 #include <unistd.h>
 #include <string.h>
 
-#include <openssl/opensslv.h>
-
 #include <isc/endian.h>
 #include <isc/util.h>
 #include <isc/siphash.h>
 
+/*
+ * The implementation is based on SipHash reference C implementation by
+ *
+ * Copyright (c) 2012-2016 Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
+ * Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
+ *
+ * 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 <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#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);
 }
index 58baa89ab9ba2b2cd7b20e255f7382bdde6ba649..ceac73f14859b8b89260e51a7362c77c3fd9e0cb 100644 (file)
@@ -17,6 +17,7 @@
 #include <stddef.h>
 #include <setjmp.h>
 
+#include <sched.h>
 #include <stdlib.h>
 
 #define UNIT_TESTING
 
 #include <isc/siphash.h>
 
+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,26 @@ const uint8_t vectors[64][8] = {
     { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, },
 };
 
+#if HAVE_OPENSSL_SIPHASH
+static void
+openssl_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;
+               openssl_isc_siphash24(key, in, i, out);
+               assert_memory_equal(out, vectors[i], 8);
+       }
+}
+#endif
+
 static void
-isc_siphash24_test(void **state) {
+native_isc_siphash24_test(void **state) {
        UNUSED(state);
 
        uint8_t in[64], out[8], key[16];
@@ -104,14 +151,17 @@ isc_siphash24_test(void **state) {
 
        for (int i = 0; i < 64; i++) {
                in[i] = i;
-               isc_siphash24(key, in, i, out);
+               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));