[Openvpn-devel,1/3] Add siphash reference implementation

Message ID 20230227125023.2561379-1-arne@rfc2549.org
State New
Headers show
Series [Openvpn-devel,1/3] Add siphash reference implementation | expand

Commit Message

Arne Schwabe Feb. 27, 2023, 12:50 p.m. UTC
OpenSSL only supports SIPHASH with OpenSSL 3.1 and newer. The source code of
siphash is quite small and has very liberal CC0 license, so include it instead
of pulling an extra library for it.

Change-Id: I1292894fe7f537049a97bee97af4419e5e854a00
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
---
 src/openvpn/siphash.c | 212 ++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/siphash.h |  31 ++++++
 2 files changed, 243 insertions(+)
 create mode 100644 src/openvpn/siphash.c
 create mode 100644 src/openvpn/siphash.h

Patch

diff --git a/src/openvpn/siphash.c b/src/openvpn/siphash.c
new file mode 100644
index 000000000..b8a7bbc11
--- /dev/null
+++ b/src/openvpn/siphash.c
@@ -0,0 +1,212 @@ 
+/*
+ * SipHash reference C implementation
+ *
+ * Copyright (c) 2012-2022 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/>.
+ */
+
+#include "siphash.h"
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* default: SipHash-2-4 */
+#ifndef cROUNDS
+#define cROUNDS 2
+#endif
+#ifndef dROUNDS
+#define dROUNDS 4
+#endif
+
+#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+
+#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))
+
+#define SIPROUND                                                               \
+    do {                                                                       \
+        v0 += v1;                                                              \
+        v1 = ROTL(v1, 13);                                                     \
+        v1 ^= v0;                                                              \
+        v0 = ROTL(v0, 32);                                                     \
+        v2 += v3;                                                              \
+        v3 = ROTL(v3, 16);                                                     \
+        v3 ^= v2;                                                              \
+        v0 += v3;                                                              \
+        v3 = ROTL(v3, 21);                                                     \
+        v3 ^= v0;                                                              \
+        v2 += v1;                                                              \
+        v1 = ROTL(v1, 17);                                                     \
+        v1 ^= v2;                                                              \
+        v2 = ROTL(v2, 32);                                                     \
+    } while (0)
+
+#ifdef DEBUG_SIPHASH
+#include <stdio.h>
+
+#define TRACE                                                                  \
+    do {                                                                       \
+        printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0);                       \
+        printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1);                       \
+        printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2);                       \
+        printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3);                       \
+    } while (0)
+#else  /* ifdef DEBUG_SIPHASH */
+#define TRACE
+#endif
+
+/*
+ *  Computes a SipHash value
+ * in: pointer to input data (read-only)
+ *  inlen: input data length in bytes (any size_t value)
+ * k: pointer to the key data (read-only), must be 16 bytes
+ * out: pointer to output data (write-only), outlen bytes must be allocated
+ *  outlen: length of the output in bytes, must be 8 or 16
+ */
+int
+siphash(const void *in, const size_t inlen, const void *k, uint8_t *out,
+        const size_t outlen)
+{
+
+    const unsigned char *ni = (const unsigned char *)in;
+    const unsigned char *kk = (const unsigned char *)k;
+
+    assert((outlen == 8) || (outlen == 16));
+    uint64_t v0 = UINT64_C(0x736f6d6570736575);
+    uint64_t v1 = UINT64_C(0x646f72616e646f6d);
+    uint64_t v2 = UINT64_C(0x6c7967656e657261);
+    uint64_t v3 = UINT64_C(0x7465646279746573);
+    uint64_t k0 = U8TO64_LE(kk);
+    uint64_t k1 = U8TO64_LE(kk + 8);
+    uint64_t m;
+    int i;
+    const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
+    const int left = inlen & 7;
+    uint64_t b = ((uint64_t)inlen) << 56;
+    v3 ^= k1;
+    v2 ^= k0;
+    v1 ^= k1;
+    v0 ^= k0;
+
+    if (outlen == 16)
+    {
+        v1 ^= 0xee;
+    }
+
+    for (; ni != end; ni += 8)
+    {
+        m = U8TO64_LE(ni);
+        v3 ^= m;
+
+        TRACE;
+        for (i = 0; i < cROUNDS; ++i)
+        {
+            SIPROUND;
+        }
+
+        v0 ^= m;
+    }
+
+    switch (left)
+    {
+        case 7:
+            b |= ((uint64_t)ni[6]) << 48;
+
+        /* FALLTHRU */
+        case 6:
+            b |= ((uint64_t)ni[5]) << 40;
+
+        /* FALLTHRU */
+        case 5:
+            b |= ((uint64_t)ni[4]) << 32;
+
+        /* FALLTHRU */
+        case 4:
+            b |= ((uint64_t)ni[3]) << 24;
+
+        /* FALLTHRU */
+        case 3:
+            b |= ((uint64_t)ni[2]) << 16;
+
+        /* FALLTHRU */
+        case 2:
+            b |= ((uint64_t)ni[1]) << 8;
+
+        /* FALLTHRU */
+        case 1:
+            b |= ((uint64_t)ni[0]);
+            break;
+
+        case 0:
+            break;
+    }
+
+    v3 ^= b;
+
+    TRACE;
+    for (i = 0; i < cROUNDS; ++i)
+    {
+        SIPROUND;
+    }
+
+    v0 ^= b;
+
+    if (outlen == 16)
+    {
+        v2 ^= 0xee;
+    }
+    else
+    {
+        v2 ^= 0xff;
+    }
+
+    TRACE;
+    for (i = 0; i < dROUNDS; ++i)
+    {
+        SIPROUND;
+    }
+
+    b = v0 ^ v1 ^ v2 ^ v3;
+    U64TO8_LE(out, b);
+
+    if (outlen == 8)
+    {
+        return 0;
+    }
+
+    v1 ^= 0xdd;
+
+    TRACE;
+    for (i = 0; i < dROUNDS; ++i)
+    {
+        SIPROUND;
+    }
+
+    b = v0 ^ v1 ^ v2 ^ v3;
+    U64TO8_LE(out + 8, b);
+
+    return 0;
+}
diff --git a/src/openvpn/siphash.h b/src/openvpn/siphash.h
new file mode 100644
index 000000000..d26ee36ec
--- /dev/null
+++ b/src/openvpn/siphash.h
@@ -0,0 +1,31 @@ 
+/*
+ * SipHash reference C implementation
+ *
+ * Copyright (c) 2012-2021 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/>.
+ */
+
+#ifndef SIPHASH_H
+#define SIPHASH_H
+
+#include <inttypes.h>
+#include <string.h>
+
+int siphash(const void *in, size_t inlen, const void *k, uint8_t *out,
+            size_t outlen);
+
+/* siphash always uses 128-bit keys */
+#define SIPHASH_KEY_SIZE    16
+#define SIPHASH_HASH_SIZE   16
+
+#endif