diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7473f15..9e1dde1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -572,6 +572,8 @@
     src/openvpn/shaper.h
     src/openvpn/sig.c
     src/openvpn/sig.h
+    src/openvpn/siphash.h
+    src/openvpn/siphash_reference.c
     src/openvpn/socket.c
     src/openvpn/socket.h
     src/openvpn/socket_util.c
@@ -784,6 +786,7 @@
         )
 
     target_sources(test_crypto PRIVATE
+        tests/unit_tests/openvpn/siphash_openssl.c
         src/openvpn/crypto_mbedtls.c
         src/openvpn/crypto_openssl.c
         src/openvpn/crypto_epoch.c
@@ -792,6 +795,7 @@
         src/openvpn/packet_id.c
         src/openvpn/mtu.c
         src/openvpn/mss.c
+        src/openvpn/siphash_reference.c
         )
 
     target_sources(test_ssl PRIVATE
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index ff8cc54..1f77384 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -128,6 +128,7 @@
 	session_id.c session_id.h \
 	shaper.c shaper.h \
 	sig.c sig.h \
+	siphash_reference.c siphash.h \
 	socket.c socket.h \
 	socket_util.c socket_util.h \
 	socks.c socks.h \
diff --git a/src/openvpn/siphash.h b/src/openvpn/siphash.h
index ef61110..bddddc3 100644
--- a/src/openvpn/siphash.h
+++ b/src/openvpn/siphash.h
@@ -18,12 +18,26 @@
 #ifndef SIPHASH_H
 #define SIPHASH_H
 
-#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
 
 /* siphash always uses 128-bit keys */
 #define SIPHASH_KEY_SIZE 16
 
-int siphash(const void *in, size_t inlen, const void *k, uint8_t *out,
-            size_t outlen);
+/**
+ * Calculates SIPHASH using the reference implementation
+ */
+int
+siphash_reference(const void *in, size_t inlen, const void *k,
+                  uint8_t *out, size_t outlen);
 
-#endif
+
+static inline int
+siphash(const void *in, size_t inlen, const void *k,
+        uint8_t *out, size_t outlen)
+{
+    return siphash_reference(in, inlen, k, out, outlen);
+}
+
+#endif /* ifndef SIPHASH_H */
\ No newline at end of file
diff --git a/src/openvpn/siphash_reference.c b/src/openvpn/siphash_reference.c
index b21a86e..ad19a51 100644
--- a/src/openvpn/siphash_reference.c
+++ b/src/openvpn/siphash_reference.c
@@ -100,8 +100,8 @@
  *  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)
+siphash_reference(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;
diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am
index d861ef9..ae15759 100644
--- a/tests/unit_tests/openvpn/Makefile.am
+++ b/tests/unit_tests/openvpn/Makefile.am
@@ -73,6 +73,7 @@
 crypto_testdriver_LDFLAGS = @TEST_LDFLAGS@
 crypto_testdriver_SOURCES = test_crypto.c \
 	mock_msg.c mock_msg.h test_common.h \
+	siphash_openssl.c siphash_openssl.h \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/crypto.c \
 	$(top_srcdir)/src/openvpn/crypto_mbedtls.c \
@@ -84,7 +85,8 @@
 	$(top_srcdir)/src/openvpn/platform.c \
 	$(top_srcdir)/src/openvpn/mtu.c \
 	$(top_srcdir)/src/openvpn/win32-util.c \
-	$(top_srcdir)/src/openvpn/mss.c
+	$(top_srcdir)/src/openvpn/mss.c \
+	$(top_srcdir)/src/openvpn/siphash_reference.c
 
 dhcp_testdriver_CFLAGS  = -I$(top_srcdir)/src/openvpn -I$(top_srcdir)/src/compat @TEST_CFLAGS@ -DDHCP_UNIT_TEST
 dhcp_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(top_srcdir)/src/openvpn
diff --git a/tests/unit_tests/openvpn/siphash_openssl.c b/tests/unit_tests/openvpn/siphash_openssl.c
new file mode 100644
index 0000000..c301f2d
--- /dev/null
+++ b/tests/unit_tests/openvpn/siphash_openssl.c
@@ -0,0 +1,144 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2026 OpenVPN Inc <sales@openvpn.net>
+ *  Copyright (C) 2026 Arne Schwabe <arne@rfc2549.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  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.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "siphash.h"
+
+#ifdef ENABLE_CRYPTO_OPENSSL
+#include <openssl/opensslv.h>
+#endif
+
+/* OpenSSL siphash is currently 2-3 times slower than the reference
+ * implementation, so we only use it for unit testing that our implementation
+ * and OpenSSL agree */
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/evp.h>
+#include "crypto_openssl.h"
+#include "crypto_backend.h"
+#include "buffer.h"
+
+struct siphash_context
+{
+    EVP_MAC *mac;
+    EVP_MAC_CTX *ctx;
+    size_t size;
+    OSSL_PARAM params[3];
+};
+
+/*
+ *  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_openssl(void *sip_context, const void *in, const size_t inlen,
+                const void *k, uint8_t *out, const size_t outlen)
+{
+    struct siphash_context *sip = sip_context;
+
+
+    sip->params[1] = OSSL_PARAM_construct_octet_string("key", (void *)k,
+                                                       SIPHASH_KEY_SIZE);
+    if (!EVP_MAC_init(sip->ctx, NULL, 0, sip->params))
+    {
+        crypto_msg(M_FATAL, "EVP_MAC_init failed");
+    }
+    EVP_MAC_update(sip->ctx, in, inlen);
+
+    size_t outl = 0;
+    EVP_MAC_final(sip->ctx, out, &outl, outlen);
+    return 0;
+}
+
+void *
+siphash_openssl_init(size_t hash_size)
+{
+    struct siphash_context *sip;
+    ALLOC_OBJ(sip, struct siphash_context);
+
+    sip->mac = EVP_MAC_fetch(NULL, "SIPHASH", NULL);
+    if (!sip->mac)
+    {
+        /* Our OpenSSL library does not support SIPHASH */
+        return sip;
+    }
+    sip->ctx = EVP_MAC_CTX_new(sip->mac);
+
+    /* OpenSSL will truly hold a pointer to an int in that parameter */
+    sip->size = hash_size;
+    sip->params[0] = OSSL_PARAM_construct_size_t("size", &sip->size);
+    /* params[1] will hold the key that changes which each invocation */
+    sip->params[2] = OSSL_PARAM_construct_end();
+    return sip;
+}
+
+bool
+siphash_openssl_available(void *sip_context)
+{
+    struct siphash_context *sip = sip_context;
+
+    return (bool)(sip->mac);
+}
+
+void
+siphash_openssl_uninit(void *sip_context)
+{
+    struct siphash_context *sip = sip_context;
+    EVP_MAC_CTX_free(sip->ctx);
+    EVP_MAC_free(sip->mac);
+    free(sip_context);
+}
+#else
+/* Do avoid a lot more ifdefs in the test we put dummy functions here */
+int
+siphash_openssl(void *sip_context, const void *in, const size_t inlen,
+                const void *k, uint8_t *out, const size_t outlen)
+{
+    return -1;
+}
+
+bool
+siphash_openssl_available(void *sip_context)
+{
+    return false;
+}
+
+void *
+siphash_openssl_init(size_t hash_size)
+{
+    return NULL;
+}
+
+void
+siphash_openssl_uninit(void *sip_context)
+{
+}
+
+
+#endif /* if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x30000000L */
diff --git a/tests/unit_tests/openvpn/siphash_openssl.h b/tests/unit_tests/openvpn/siphash_openssl.h
new file mode 100644
index 0000000..0f1d329
--- /dev/null
+++ b/tests/unit_tests/openvpn/siphash_openssl.h
@@ -0,0 +1,64 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2026 OpenVPN Inc <sales@openvpn.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  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.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef SIPHASH_OPENSSL_H
+#define SIPHASH_OPENSSL_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+
+/* Prototypes for an implementation of SIPHASH in a crypto library */
+/**
+ *
+ * @param hash_size the size of the output hash size
+ * @return initialised context for siphash
+ */
+void *
+siphash_openssl_init(size_t hash_size);
+
+
+/**
+ * Calculates SIPHASH using the crypto library function.
+ */
+int
+siphash_openssl(void *sip_context, const void *in, size_t inlen,
+                const void *k, uint8_t *out, size_t outlen);
+
+/**
+ * Free the siphash context used for the crypto library
+ * @param sip_context
+ */
+void
+siphash_openssl_uninit(void *sip_context);
+
+/**
+ * Returns if the crypto library is available (and should be used)
+ *
+ * This returns if there is a crypto library version of Siphash24 is
+ * available and should be used (OpenSSL 3/4 version is quite slow, so
+ * we prefer the reference implementation)
+ *
+ */
+bool
+siphash_openssl_available(void *sip_context);
+#endif /* ifndef SIPHASH_OPENSSL_H */
\ No newline at end of file
diff --git a/tests/unit_tests/openvpn/test_crypto.c b/tests/unit_tests/openvpn/test_crypto.c
index cb4eaa2..77cf295 100644
--- a/tests/unit_tests/openvpn/test_crypto.c
+++ b/tests/unit_tests/openvpn/test_crypto.c
@@ -31,12 +31,15 @@
 #include <stdarg.h>
 #include <string.h>
 #include <setjmp.h>
+#include <inttypes.h>
 #include <cmocka.h>
 
 #include "crypto.h"
 #include "crypto_epoch.h"
 #include "options.h"
 #include "ssl_backend.h"
+#include "siphash.h"
+#include "siphash_openssl.h"
 
 #include "mss.h"
 #include "test_common.h"
@@ -923,6 +926,69 @@
     assert_memory_equal(key_parameters.hmac, exp_impl_iv, sizeof(exp_impl_iv));
 }
 
+/* Use a define here since some c compilers don't like array initialisation
+ * with an integer */
+#define UT_SIPHASH_HASH_SIZE 16
+
+static const char *ut_message = "Look behind you, a Three-Headed Monkey!";
+static const uint8_t ut_key[SIPHASH_KEY_SIZE] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+const uint8_t expected_hash[UT_SIPHASH_HASH_SIZE] = { 0x3e, 0xea, 0x95, 0xb2, 0x6d, 0x5c, 0x4e, 0xfa,
+                                                      0x20, 0x47, 0x65, 0x7e, 0xdd, 0xcd, 0x62, 0x51 };
+
+static void
+test_siphash(void **state)
+{
+    uint8_t out[UT_SIPHASH_HASH_SIZE] = { 0 };
+    siphash_reference(ut_message, strlen(ut_message), ut_key, out, UT_SIPHASH_HASH_SIZE);
+    assert_memory_equal(out, expected_hash, UT_SIPHASH_HASH_SIZE);
+}
+
+static void
+test_siphash_openssl(void **state)
+{
+    void *sipctx = siphash_openssl_init(UT_SIPHASH_HASH_SIZE);
+
+    if (!siphash_openssl_available(sipctx))
+    {
+        siphash_openssl_uninit(sipctx);
+        skip();
+    }
+
+    uint8_t out[UT_SIPHASH_HASH_SIZE] = { 0 };
+
+    siphash_openssl(sipctx, ut_message, strlen(ut_message), ut_key, out,
+                    UT_SIPHASH_HASH_SIZE);
+    assert_memory_equal(out, expected_hash, UT_SIPHASH_HASH_SIZE);
+
+    /* check that calling the function twice is safe */
+    siphash_openssl(sipctx, ut_message, strlen(ut_message), ut_key, out,
+                    UT_SIPHASH_HASH_SIZE);
+    assert_memory_equal(out, expected_hash, UT_SIPHASH_HASH_SIZE);
+
+    /* Test a few random strings and ensure that our implementation behave the
+     * same */
+    for (int i = 0; i < 1000; i++)
+    {
+        size_t len = random() % 1000u;
+        uint8_t buf[1024] = { 0 };
+        uint8_t key[SIPHASH_KEY_SIZE] = { 0 };
+
+        assert_true(rand_bytes(buf, (int)len));
+        assert_true(rand_bytes(key, sizeof(key)));
+
+
+        siphash_openssl(sipctx, buf, len, key, out, UT_SIPHASH_HASH_SIZE);
+
+        uint8_t outref[UT_SIPHASH_HASH_SIZE] = { 0 };
+        siphash_reference(buf, len, key, outref, UT_SIPHASH_HASH_SIZE);
+
+        assert_memory_equal(out, outref, UT_SIPHASH_HASH_SIZE);
+    }
+
+    siphash_openssl_uninit(sipctx);
+}
+
+
 int
 main(void)
 {
@@ -960,7 +1026,9 @@
         cmocka_unit_test_prestate_setup_teardown(crypto_test_epoch_edge,
                                                  crypto_test_epoch_setup,
                                                  crypto_test_epoch_teardown, &prestate_num13),
-        cmocka_unit_test(epoch_test_derive_data_key)
+        cmocka_unit_test(epoch_test_derive_data_key),
+        cmocka_unit_test(test_siphash),
+        cmocka_unit_test(test_siphash_openssl)
     };
 
     return cmocka_run_group_tests_name("crypto tests", tests, NULL, NULL);
