Add support for parameterized SipHash
authorTodd Short <tshort@akamai.com>
Wed, 11 Jan 2017 21:38:44 +0000 (16:38 -0500)
committerRich Salz <rsalz@openssl.org>
Wed, 1 Feb 2017 19:14:36 +0000 (14:14 -0500)
The core SipHash supports either 8 or 16-byte output and a configurable
number of rounds.
The default behavior, as added to EVP, is to use 16-byte output and
2,4 rounds, which matches the behavior of most implementations.
There is an EVP_PKEY_CTRL that can control the output size.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2216)

27 files changed:
CHANGES
Configure
INSTALL
crypto/asn1/standard_methods.h
crypto/evp/evp_err.c
crypto/evp/p_lib.c
crypto/evp/pmeth_lib.c
crypto/include/internal/asn1_int.h
crypto/include/internal/evp_int.h
crypto/include/internal/siphash.h [new file with mode: 0644]
crypto/objects/obj_dat.h
crypto/objects/obj_mac.num
crypto/objects/objects.txt
crypto/siphash/build.info [new file with mode: 0644]
crypto/siphash/siphash.c [new file with mode: 0644]
crypto/siphash/siphash_ameth.c [new file with mode: 0644]
crypto/siphash/siphash_local.h [new file with mode: 0644]
crypto/siphash/siphash_pmeth.c [new file with mode: 0644]
doc/man3/EVP_PKEY_CTX_ctrl.pod
include/openssl/evp.h
include/openssl/obj_mac.h
test/build.info
test/evp_test.c
test/evptests.txt
test/siphash_internal_test.c [new file with mode: 0644]
util/libcrypto.num
util/mkdef.pl

diff --git a/CHANGES b/CHANGES
index 8b817e35f260c1d7704022c9eaccc57c5043b679..8b27bd56344c2bb0ec5a4ee75491504455260b5b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,9 @@
 
  Changes between 1.1.0a and 1.1.1 [xx XXX xxxx]
 
+  *) Add support for SipHash
+     [Todd Short]
+
   *) OpenSSL now fails if it receives an unrecognised record type in TLS1.0
      or TLS1.1. Previously this only happened in SSLv3 and TLS1.2. This is to
      prevent issues where no progress is being made and the peer continually
index ef532dad78d1530cb520b5db45ad95735874da08..1fe2280fd43b1fa1cd59304186cd694b67643762 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -313,7 +313,7 @@ $config{dirs} = [ "crypto", "ssl", "engines", "apps", "test", "util", "tools", "
 # crypto/ subdirectories to build
 $config{sdirs} = [
     "objects",
-    "md2", "md4", "md5", "sha", "mdc2", "hmac", "ripemd", "whrlpool", "poly1305", "blake2",
+    "md2", "md4", "md5", "sha", "mdc2", "hmac", "ripemd", "whrlpool", "poly1305", "blake2", "siphash",
     "des", "aes", "rc2", "rc4", "rc5", "idea", "bf", "cast", "camellia", "seed", "chacha", "modes",
     "bn", "ec", "rsa", "dsa", "dh", "dso", "engine",
     "buffer", "bio", "stack", "lhash", "rand", "err",
@@ -397,6 +397,7 @@ my @disablables = (
     "sctp",
     "seed",
     "shared",
+    "siphash",
     "sock",
     "srp",
     "srtp",
diff --git a/INSTALL b/INSTALL
index fa50091f84989b9385917cd68497fda2e23d4ca9..26cbe3084f47810403ca60fdddbf170012a76d7e 100644 (file)
--- a/INSTALL
+++ b/INSTALL
                    Build without support for the specified algorithm, where
                    <alg> is one of: bf, blake2, camellia, cast, chacha, cmac,
                    des, dh, dsa, ecdh, ecdsa, idea, md4, mdc2, ocb, poly1305,
-                   rc2, rc4, rmd160, scrypt, seed or whirlpool. The "ripemd"
-                   algorithm is deprecated and if used is synonymous with rmd160.
+                   rc2, rc4, rmd160, scrypt, seed, siphash or whirlpool. The
+                   "ripemd" algorithm is deprecated and if used is synonymous
+                   with rmd160.
 
   -Dxxx, -lxxx, -Lxxx, -fxxx, -mXXX, -Kxxx
                    These system specific options will be passed through to the
index ca38b09feecda75d5095a479932bb761bb7b1713..a0fd881b7a64d2b9dfd007280aa2d2a640e972d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -46,5 +46,8 @@ static const EVP_PKEY_ASN1_METHOD *standard_methods[] = {
 #ifndef OPENSSL_NO_POLY1305
     &poly1305_asn1_meth,
 #endif
+#ifndef OPENSSL_NO_SIPHASH
+    &siphash_asn1_meth,
+#endif
 };
 
index bf090528091a86cd66e5d23b9d61c578df5bcbba..6ff9ec4eae19cf8789393cdf749890750f0ea2a0 100644 (file)
@@ -69,6 +69,7 @@ static ERR_STRING_DATA EVP_str_functs[] = {
     {ERR_FUNC(EVP_F_EVP_PKEY_GET0_HMAC), "EVP_PKEY_get0_hmac"},
     {ERR_FUNC(EVP_F_EVP_PKEY_GET0_POLY1305), "EVP_PKEY_get0_poly1305"},
     {ERR_FUNC(EVP_F_EVP_PKEY_GET0_RSA), "EVP_PKEY_get0_RSA"},
+    {ERR_FUNC(EVP_F_EVP_PKEY_GET0_SIPHASH), "EVP_PKEY_get0_siphash"},
     {ERR_FUNC(EVP_F_EVP_PKEY_KEYGEN), "EVP_PKEY_keygen"},
     {ERR_FUNC(EVP_F_EVP_PKEY_KEYGEN_INIT), "EVP_PKEY_keygen_init"},
     {ERR_FUNC(EVP_F_EVP_PKEY_NEW), "EVP_PKEY_new"},
@@ -119,6 +120,7 @@ static ERR_STRING_DATA EVP_str_reasons[] = {
     {ERR_REASON(EVP_R_EXPECTING_A_DSA_KEY), "expecting a dsa key"},
     {ERR_REASON(EVP_R_EXPECTING_A_EC_KEY), "expecting a ec key"},
     {ERR_REASON(EVP_R_EXPECTING_A_POLY1305_KEY), "expecting a poly1305 key"},
+    {ERR_REASON(EVP_R_EXPECTING_A_SIPHASH_KEY), "expecting a siphash key"},
     {ERR_REASON(EVP_R_FIPS_MODE_NOT_SUPPORTED), "fips mode not supported"},
     {ERR_REASON(EVP_R_ILLEGAL_SCRYPT_PARAMETERS),
      "illegal scrypt parameters"},
index 047e8326374f961c16b3e025339e00a04b9aea48..b5e5206778ffd2d5d1c13e6c0b805ce7b2fc2314 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -263,6 +263,21 @@ const unsigned char *EVP_PKEY_get0_poly1305(const EVP_PKEY *pkey, size_t *len)
 }
 #endif
 
+#ifndef OPENSSL_NO_SIPHASH
+const unsigned char *EVP_PKEY_get0_siphash(const EVP_PKEY *pkey, size_t *len)
+{
+    ASN1_OCTET_STRING *os = NULL;
+
+    if (pkey->type != EVP_PKEY_SIPHASH) {
+        EVPerr(EVP_F_EVP_PKEY_GET0_SIPHASH, EVP_R_EXPECTING_A_SIPHASH_KEY);
+        return NULL;
+    }
+    os = EVP_PKEY_get0(pkey);
+    *len = os->length;
+    return os->data;
+}
+#endif
+
 #ifndef OPENSSL_NO_RSA
 int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key)
 {
index 66e1e08149741cf5e60719db2ac4ef0feba483cf..681e5e06c7f450b03099cf30d3f2b1ab6c3442a2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -52,6 +52,9 @@ static const EVP_PKEY_METHOD *standard_methods[] = {
 #ifndef OPENSSL_NO_POLY1305
     &poly1305_pkey_meth,
 #endif
+#ifndef OPENSSL_NO_SIPHASH
+    &siphash_pkey_meth,
+#endif
 };
 
 DECLARE_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_METHOD *, const EVP_PKEY_METHOD *,
index 554f067740994df903dc6ccaff36ae92a19f77aa..f78ced6dabffd7722c7b2ac65d99f358735f6d41 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -67,6 +67,7 @@ extern const EVP_PKEY_ASN1_METHOD poly1305_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[2];
 extern const EVP_PKEY_ASN1_METHOD rsa_pss_asn1_meth;
+extern const EVP_PKEY_ASN1_METHOD siphash_asn1_meth;
 
 /*
  * These are used internally in the ASN1_OBJECT to keep track of whether the
index b5b6a130048db0a99949fa2d385dbaf30f1c2c71..0b0d87838b436865fb7b558a980f1f5a4870c0dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -88,6 +88,7 @@ extern const EVP_PKEY_METHOD rsa_pss_pkey_meth;
 extern const EVP_PKEY_METHOD tls1_prf_pkey_meth;
 extern const EVP_PKEY_METHOD hkdf_pkey_meth;
 extern const EVP_PKEY_METHOD poly1305_pkey_meth;
+extern const EVP_PKEY_METHOD siphash_pkey_meth;
 
 struct evp_md_st {
     int type;
diff --git a/crypto/include/internal/siphash.h b/crypto/include/internal/siphash.h
new file mode 100644 (file)
index 0000000..e086859
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stddef.h>
+
+#define SIPHASH_BLOCK_SIZE        8
+#define SIPHASH_KEY_SIZE         16
+#define SIPHASH_MIN_DIGEST_SIZE   8
+#define SIPHASH_MAX_DIGEST_SIZE  16
+
+typedef struct siphash_st SIPHASH;
+
+size_t SipHash_ctx_size(void);
+size_t SipHash_hash_size(SIPHASH *ctx);
+int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size,
+                 int crounds, int drounds);
+void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen);
+int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen);
index 5171f568469ff8cb21284516a09e673ec8e1671c..88d371aed0a14de769749698494aa23cd120a900 100644 (file)
@@ -963,7 +963,7 @@ static const unsigned char so[6765] = {
     0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x1C,  /* [ 6753] OBJ_id_ct_xml */
 };
 
-#define NUM_NID 1062
+#define NUM_NID 1063
 static const ASN1_OBJECT nid_objs[NUM_NID] = {
     {"UNDEF", "undefined", NID_undef},
     {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
@@ -2027,9 +2027,10 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
     {"id-smime-ct-authEnvelopedData", "id-smime-ct-authEnvelopedData", NID_id_smime_ct_authEnvelopedData, 11, &so[6742]},
     {"id-ct-xml", "id-ct-xml", NID_id_ct_xml, 11, &so[6753]},
     {"Poly1305", "poly1305", NID_poly1305},
+    {"SipHash", "siphash", NID_siphash},
 };
 
-#define NUM_SN 1053
+#define NUM_SN 1054
 static const unsigned int sn_objs[NUM_SN] = {
      364,    /* "AD_DVCS" */
      419,    /* "AES-128-CBC" */
@@ -2256,6 +2257,7 @@ static const unsigned int sn_objs[NUM_SN] = {
     1006,    /* "SNILS" */
       16,    /* "ST" */
      143,    /* "SXNetID" */
+    1062,    /* "SipHash" */
     1021,    /* "TLS1-PRF" */
      458,    /* "UID" */
        0,    /* "UNDEF" */
@@ -3086,7 +3088,7 @@ static const unsigned int sn_objs[NUM_SN] = {
      160,    /* "x509Crl" */
 };
 
-#define NUM_LN 1053
+#define NUM_LN 1054
 static const unsigned int ln_objs[NUM_LN] = {
      363,    /* "AD Time Stamping" */
      405,    /* "ANSI X9.62" */
@@ -4096,6 +4098,7 @@ static const unsigned int ln_objs[NUM_LN] = {
       52,    /* "signingTime" */
      454,    /* "simpleSecurityObject" */
      496,    /* "singleLevelQuality" */
+    1062,    /* "siphash" */
       16,    /* "stateOrProvinceName" */
      660,    /* "streetAddress" */
      498,    /* "subtreeMaximumQuality" */
index 9aa490b670d09c6a68b407e9be3892404c7d53d7..3793951c62ab9f281bcadc584c7bf87466ba7c6e 100644 (file)
@@ -1059,3 +1059,4 @@ id_smime_ct_contentCollection             1058
 id_smime_ct_authEnvelopedData          1059
 id_ct_xml              1060
 poly1305               1061
+siphash                1062
index 09701af4a1f214a3049ff87f2afb7559219735ba..5b1f2bdac5f17246d63f98d24084b5ad84691e70 100644 (file)
@@ -1484,3 +1484,5 @@ id-pkinit 5                     : pkInitKDC             : Signing KDC Response
                             : AuthNULL     : auth-null
 # NID for Poly1305
                             : Poly1305     : poly1305
+# NID for SipHash
+                            : SipHash      : siphash
diff --git a/crypto/siphash/build.info b/crypto/siphash/build.info
new file mode 100644 (file)
index 0000000..4166344
--- /dev/null
@@ -0,0 +1,5 @@
+LIBS=../../libcrypto
+SOURCE[../../libcrypto]=\
+       siphash.c \
+       siphash_pmeth.c \
+       siphash_ameth.c
diff --git a/crypto/siphash/siphash.c b/crypto/siphash/siphash.c
new file mode 100644 (file)
index 0000000..4bf2382
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Based on https://131002.net/siphash C reference implementation */
+/*
+   SipHash reference C implementation
+
+   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/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/crypto.h>
+
+#include "internal/siphash.h"
+#include "siphash_local.h"
+
+/* default: SipHash-2-4 */
+#define SIPHASH_C_ROUNDS 2
+#define SIPHASH_D_ROUNDS 4
+
+#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)
+
+size_t SipHash_ctx_size(void)
+{
+    return sizeof(SIPHASH);
+}
+
+size_t SipHash_hash_size(SIPHASH *ctx)
+{
+    return ctx->hash_size;
+}
+
+/* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
+int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size, int crounds, int drounds)
+{
+    uint64_t k0 = U8TO64_LE(k);
+    uint64_t k1 = U8TO64_LE(k + 8);
+
+    if (hash_size == 0)
+        hash_size = SIPHASH_MAX_DIGEST_SIZE;
+    else if (hash_size != SIPHASH_MIN_DIGEST_SIZE &&
+             hash_size != SIPHASH_MAX_DIGEST_SIZE)
+        return 0;
+
+    if (drounds == 0)
+        drounds = SIPHASH_D_ROUNDS;
+    if (crounds == 0)
+        crounds = SIPHASH_C_ROUNDS;
+
+    ctx->crounds = crounds;
+    ctx->drounds = drounds;
+    ctx->hash_size = hash_size;
+
+    ctx->len = 0;
+    ctx->total_inlen = 0;
+
+    ctx->v0 = 0x736f6d6570736575ULL ^ k0;
+    ctx->v1 = 0x646f72616e646f6dULL ^ k1;
+    ctx->v2 = 0x6c7967656e657261ULL ^ k0;
+    ctx->v3 = 0x7465646279746573ULL ^ k1;
+
+    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
+        ctx->v1 ^= 0xee;
+
+    return 1;
+}
+
+void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
+{
+    uint64_t m;
+    const uint8_t *end;
+    int left;
+    int i;
+    uint64_t v0 = ctx->v0;
+    uint64_t v1 = ctx->v1;
+    uint64_t v2 = ctx->v2;
+    uint64_t v3 = ctx->v3;
+
+    ctx->total_inlen += inlen;
+
+    if (ctx->len) {
+        /* deal with leavings */
+        size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
+
+        /* not enough to fill leavings */
+        if (inlen < available) {
+            memcpy(&ctx->leavings[ctx->len], in, inlen);
+            ctx->len += inlen;
+            return;
+        }
+
+        /* copy data into leavings and reduce input */
+        memcpy(&ctx->leavings[ctx->len], in, available);
+        inlen -= available;
+        in += available;
+
+        /* process leavings */
+        m = U8TO64_LE(ctx->leavings);
+        v3 ^= m;
+        for (i = 0; i < ctx->crounds; ++i)
+            SIPROUND;
+        v0 ^= m;
+    }
+    left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
+    end = in + inlen - left;
+
+    for (; in != end; in += 8) {
+        m = U8TO64_LE(in);
+        v3 ^= m;
+        for (i = 0; i < ctx->crounds; ++i)
+            SIPROUND;
+        v0 ^= m;
+    }
+
+    /* save leavings and other ctx */
+    if (left)
+        memcpy(ctx->leavings, end, left);
+    ctx->len = left;
+
+    ctx->v0 = v0;
+    ctx->v1 = v1;
+    ctx->v2 = v2;
+    ctx->v3 = v3;
+}
+
+int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
+{
+    /* finalize hash */
+    int i;
+    uint64_t b = ctx->total_inlen << 56;
+    uint64_t v0 = ctx->v0;
+    uint64_t v1 = ctx->v1;
+    uint64_t v2 = ctx->v2;
+    uint64_t v3 = ctx->v3;
+
+    if (outlen != (size_t)ctx->hash_size)
+        return 0;
+
+    switch (ctx->len) {
+    case 7:
+        b |= ((uint64_t)ctx->leavings[6]) << 48;
+    case 6:
+        b |= ((uint64_t)ctx->leavings[5]) << 40;
+    case 5:
+        b |= ((uint64_t)ctx->leavings[4]) << 32;
+    case 4:
+        b |= ((uint64_t)ctx->leavings[3]) << 24;
+    case 3:
+        b |= ((uint64_t)ctx->leavings[2]) << 16;
+    case 2:
+        b |= ((uint64_t)ctx->leavings[1]) <<  8;
+    case 1:
+        b |= ((uint64_t)ctx->leavings[0]);
+    case 0:
+        break;
+    }
+
+    v3 ^= b;
+    for (i = 0; i < ctx->crounds; ++i)
+        SIPROUND;
+    v0 ^= b;
+    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
+        v2 ^= 0xee;
+    else
+        v2 ^= 0xff;
+    for (i = 0; i < ctx->drounds; ++i)
+        SIPROUND;
+    b = v0 ^ v1 ^ v2  ^ v3;
+    U64TO8_LE(out, b);
+    if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
+        return 1;
+    v1 ^= 0xdd;
+    for (i = 0; i < ctx->drounds; ++i)
+        SIPROUND;
+    b = v0 ^ v1 ^ v2  ^ v3;
+    U64TO8_LE(out + 8, b);
+    return 1;
+}
diff --git a/crypto/siphash/siphash_ameth.c b/crypto/siphash/siphash_ameth.c
new file mode 100644 (file)
index 0000000..d819461
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2007-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/evp.h>
+#include "internal/asn1_int.h"
+#include "internal/siphash.h"
+#include "siphash_local.h"
+
+/*
+ * SIPHASH "ASN1" method. This is just here to indicate the maximum
+ * SIPHASH output length and to free up a SIPHASH key.
+ */
+
+static int siphash_size(const EVP_PKEY *pkey)
+{
+    return SIPHASH_MAX_DIGEST_SIZE;
+}
+
+static void siphash_key_free(EVP_PKEY *pkey)
+{
+    ASN1_OCTET_STRING *os = EVP_PKEY_get0(pkey);
+
+    if (os != NULL) {
+        if (os->data != NULL)
+            OPENSSL_cleanse(os->data, os->length);
+        ASN1_OCTET_STRING_free(os);
+    }
+}
+
+static int siphash_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
+{
+    /* nothing (including ASN1_PKEY_CTRL_DEFAULT_MD_NID), is supported */
+    return -2;
+}
+
+static int siphash_pkey_public_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
+{
+    return ASN1_OCTET_STRING_cmp(EVP_PKEY_get0(a), EVP_PKEY_get0(b));
+}
+
+const EVP_PKEY_ASN1_METHOD siphash_asn1_meth = {
+    EVP_PKEY_SIPHASH,
+    EVP_PKEY_SIPHASH,
+    0,
+
+    "SIPHASH",
+    "OpenSSL SIPHASH method",
+
+    0, 0, siphash_pkey_public_cmp, 0,
+
+    0, 0, 0,
+
+    siphash_size,
+    0, 0,
+    0, 0, 0, 0, 0, 0, 0,
+
+    siphash_key_free,
+    siphash_pkey_ctrl,
+    0, 0
+};
diff --git a/crypto/siphash/siphash_local.h b/crypto/siphash/siphash_local.h
new file mode 100644 (file)
index 0000000..5ad3476
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Based on https://131002.net/siphash C reference implementation */
+
+struct siphash_st {
+    uint64_t total_inlen;
+    uint64_t v0;
+    uint64_t v1;
+    uint64_t v2;
+    uint64_t v3;
+    unsigned int len;
+    int hash_size;
+    int crounds;
+    int drounds;
+    unsigned char leavings[SIPHASH_BLOCK_SIZE];
+};
diff --git a/crypto/siphash/siphash_pmeth.c b/crypto/siphash/siphash_pmeth.c
new file mode 100644 (file)
index 0000000..ae16e55
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2007-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/evp.h>
+#include "internal/siphash.h"
+#include "siphash_local.h"
+#include "internal/evp_int.h"
+
+/* SIPHASH pkey context structure */
+
+typedef struct siphash_pkey_ctx_st {
+    ASN1_OCTET_STRING ktmp;     /* Temp storage for key */
+    SIPHASH ctx;
+} SIPHASH_PKEY_CTX;
+
+static int pkey_siphash_init(EVP_PKEY_CTX *ctx)
+{
+    SIPHASH_PKEY_CTX *pctx;
+
+    pctx = OPENSSL_zalloc(sizeof(*pctx));
+    if (pctx == NULL)
+        return 0;
+    pctx->ktmp.type = V_ASN1_OCTET_STRING;
+
+    EVP_PKEY_CTX_set_data(ctx, pctx);
+    EVP_PKEY_CTX_set0_keygen_info(ctx, NULL, 0);
+    return 1;
+}
+
+static void pkey_siphash_cleanup(EVP_PKEY_CTX *ctx)
+{
+    SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx);
+
+    if (pctx != NULL) {
+        OPENSSL_clear_free(pctx->ktmp.data, pctx->ktmp.length);
+        OPENSSL_clear_free(pctx, sizeof(*pctx));
+        EVP_PKEY_CTX_set_data(ctx, NULL);
+    }
+}
+
+static int pkey_siphash_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
+{
+    SIPHASH_PKEY_CTX *sctx, *dctx;
+
+    /* allocate memory for dst->data and a new SIPHASH_CTX in dst->data->ctx */
+    if (!pkey_siphash_init(dst))
+        return 0;
+    sctx = EVP_PKEY_CTX_get_data(src);
+    dctx = EVP_PKEY_CTX_get_data(dst);
+    if (ASN1_STRING_get0_data(&sctx->ktmp) != NULL &&
+        !ASN1_STRING_copy(&dctx->ktmp, &sctx->ktmp)) {
+        /* cleanup and free the SIPHASH_PKEY_CTX in dst->data */
+        pkey_siphash_cleanup(dst);
+        return 0;
+    }
+    memcpy(&dctx->ctx, &sctx->ctx, sizeof(SIPHASH));
+    return 1;
+}
+
+static int pkey_siphash_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
+{
+    ASN1_OCTET_STRING *key;
+    SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx);
+
+    if (ASN1_STRING_get0_data(&pctx->ktmp) == NULL)
+        return 0;
+    key = ASN1_OCTET_STRING_dup(&pctx->ktmp);
+    if (key == NULL)
+        return 0;
+    return EVP_PKEY_assign_SIPHASH(pkey, key);
+}
+
+static int int_update(EVP_MD_CTX *ctx, const void *data, size_t count)
+{
+    SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(EVP_MD_CTX_pkey_ctx(ctx));
+
+    SipHash_Update(&pctx->ctx, data, count);
+    return 1;
+}
+
+static int siphash_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
+{
+    SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx);
+    const unsigned char* key;
+    size_t len;
+    int hash_size;
+
+    key = EVP_PKEY_get0_siphash(EVP_PKEY_CTX_get0_pkey(ctx), &len);
+    if (key == NULL || len != SIPHASH_KEY_SIZE)
+        return 0;
+    EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
+    EVP_MD_CTX_set_update_fn(mctx, int_update);
+    /* use default rounds (2,4) */
+    hash_size = SipHash_hash_size(&pctx->ctx);
+    return SipHash_Init(&pctx->ctx, key, hash_size, 0, 0);
+}
+static int siphash_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+                            EVP_MD_CTX *mctx)
+{
+    SIPHASH_PKEY_CTX *pctx = ctx->data;
+
+    *siglen = SipHash_hash_size(&pctx->ctx);
+    if (sig != NULL)
+        return SipHash_Final(&pctx->ctx, sig, *siglen);
+    return 1;
+}
+
+static int pkey_siphash_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+{
+    SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx);
+    const unsigned char *key;
+    size_t len;
+    int hash_size;
+
+    switch (type) {
+
+    case EVP_PKEY_CTRL_MD:
+        /* ignore */
+        break;
+
+    case EVP_PKEY_CTRL_SET_DIGEST_SIZE:
+        if (p1 != SIPHASH_MIN_DIGEST_SIZE &&
+            p1 != SIPHASH_MAX_DIGEST_SIZE) {
+            return 0;
+        }
+        /* use default rounds (2,4) */
+        return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), p1, 0, 0);
+
+    case EVP_PKEY_CTRL_SET_MAC_KEY:
+    case EVP_PKEY_CTRL_DIGESTINIT:
+        if (type == EVP_PKEY_CTRL_SET_MAC_KEY) {
+            /* user explicitly setting the key */
+            key = p2;
+            len = p1;
+        } else {
+            /* user indirectly setting the key via EVP_DigestSignInit */
+            key = EVP_PKEY_get0_siphash(EVP_PKEY_CTX_get0_pkey(ctx), &len);
+        }
+        if (key == NULL || len != SIPHASH_KEY_SIZE ||
+            !ASN1_OCTET_STRING_set(&pctx->ktmp, key, len))
+            return 0;
+        /* use default rounds (2,4) */
+        hash_size = SipHash_hash_size(&pctx->ctx);
+        return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), hash_size, 0, 0);
+
+    default:
+        return -2;
+
+    }
+    return 1;
+}
+
+static int pkey_siphash_ctrl_str(EVP_PKEY_CTX *ctx,
+                                  const char *type, const char *value)
+{
+    if (value == NULL)
+        return 0;
+    if (strcmp(type, "key") == 0)
+        return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value);
+    if (strcmp(type, "hexkey") == 0)
+        return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value);
+    return -2;
+}
+
+const EVP_PKEY_METHOD siphash_pkey_meth = {
+    EVP_PKEY_SIPHASH,
+    EVP_PKEY_FLAG_SIGCTX_CUSTOM, /* we don't deal with a separate MD */
+    pkey_siphash_init,
+    pkey_siphash_copy,
+    pkey_siphash_cleanup,
+
+    0, 0,
+
+    0,
+    pkey_siphash_keygen,
+
+    0, 0,
+
+    0, 0,
+
+    0, 0,
+
+    siphash_signctx_init,
+    siphash_signctx,
+
+    0, 0,
+
+    0, 0,
+
+    0, 0,
+
+    0, 0,
+
+    pkey_siphash_ctrl,
+    pkey_siphash_ctrl_str
+};
index abe76c80892d83dd008efd235686725aa7591914..0e043f1a72a04e846cc78848c928152466a8306e 100644 (file)
@@ -49,7 +49,7 @@ The control command is indicated in B<cmd> and any additional arguments in
 B<p1> and B<p2>.
 
 For B<cmd> = B<EVP_PKEY_CTRL_SET_MAC_KEY>, B<p1> is the length of the MAC key,
-and B<p2> is MAC key. This is used by Poly1305, HMAC and CMAC.
+and B<p2> is MAC key. This is used by Poly1305, SipHash, HMAC and CMAC.
 
 Applications will not normally call EVP_PKEY_CTX_ctrl() directly but will
 instead call one of the algorithm specific macros below.
index 7f4b2d74883a6008eb7041b18792a21abe554d87..e44521ce23fdec224d0e2f21cc7cba259e90a321 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -54,6 +54,7 @@
 # define EVP_PKEY_TLS1_PRF NID_tls1_prf
 # define EVP_PKEY_HKDF   NID_hkdf
 # define EVP_PKEY_POLY1305 NID_poly1305
+# define EVP_PKEY_SIPHASH NID_siphash
 
 #ifdef  __cplusplus
 extern "C" {
@@ -398,6 +399,10 @@ typedef int (EVP_PBE_KEYGEN) (EVP_CIPHER_CTX *ctx, const char *pass,
 #  define EVP_PKEY_assign_EC_KEY(pkey,eckey) EVP_PKEY_assign((pkey),EVP_PKEY_EC,\
                                         (char *)(eckey))
 # endif
+# ifndef OPENSSL_NO_SIPHASH
+#  define EVP_PKEY_assign_SIPHASH(pkey,shkey) EVP_PKEY_assign((pkey),EVP_PKEY_SIPHASH,\
+                                        (char *)(shkey))
+# endif
 
 # ifndef OPENSSL_NO_POLY1305
 #  define EVP_PKEY_assign_POLY1305(pkey,polykey) EVP_PKEY_assign((pkey),EVP_PKEY_POLY1305,\
@@ -913,6 +918,9 @@ const unsigned char *EVP_PKEY_get0_hmac(const EVP_PKEY *pkey, size_t *len);
 # ifndef OPENSSL_NO_POLY1305
 const unsigned char *EVP_PKEY_get0_poly1305(const EVP_PKEY *pkey, size_t *len);
 # endif
+# ifndef OPENSSL_NO_SIPHASH
+const unsigned char *EVP_PKEY_get0_siphash(const EVP_PKEY *pkey, size_t *len);
+# endif
 
 # ifndef OPENSSL_NO_RSA
 struct rsa_st;
@@ -1185,6 +1193,8 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
 
 # define EVP_PKEY_CTRL_GET_MD            13
 
+# define EVP_PKEY_CTRL_SET_DIGEST_SIZE   14
+
 # define EVP_PKEY_ALG_CTRL               0x1000
 
 # define EVP_PKEY_FLAG_AUTOARGLEN        2
@@ -1514,6 +1524,7 @@ int ERR_load_EVP_strings(void);
 # define EVP_F_EVP_PKEY_GET0_HMAC                         183
 # define EVP_F_EVP_PKEY_GET0_POLY1305                     184
 # define EVP_F_EVP_PKEY_GET0_RSA                          121
+# define EVP_F_EVP_PKEY_GET0_SIPHASH                      172
 # define EVP_F_EVP_PKEY_KEYGEN                            146
 # define EVP_F_EVP_PKEY_KEYGEN_INIT                       147
 # define EVP_F_EVP_PKEY_NEW                               106
@@ -1558,6 +1569,7 @@ int ERR_load_EVP_strings(void);
 # define EVP_R_EXPECTING_A_DSA_KEY                        129
 # define EVP_R_EXPECTING_A_EC_KEY                         142
 # define EVP_R_EXPECTING_A_POLY1305_KEY                   164
+# define EVP_R_EXPECTING_A_SIPHASH_KEY                    175
 # define EVP_R_FIPS_MODE_NOT_SUPPORTED                    167
 # define EVP_R_ILLEGAL_SCRYPT_PARAMETERS                  171
 # define EVP_R_INITIALIZATION_ERROR                       134
index faeb67526fb273769baece4ae0e9c8a14af1ff9b..c8f876e355e7a1edbf0c2b136d649a40f9ec5233 100644 (file)
 #define SN_poly1305             "Poly1305"
 #define LN_poly1305             "poly1305"
 #define NID_poly1305            1061
+
+#define SN_siphash              "SipHash"
+#define LN_siphash              "siphash"
+#define NID_siphash             1062
index a6a5c7ca8428a2bd5121806637fbd6c01fc9bd30..4a43e5bff225a965050eea65bb7bccb05382f73b 100644 (file)
@@ -334,6 +334,9 @@ IF[{- !$disabled{tests} -}]
     IF[{- !$disabled{poly1305} -}]
       PROGRAMS_NO_INST=poly1305_internal_test
     ENDIF
+    IF[{- !$disabled{siphash} -}]
+      PROGRAMS_NO_INST=siphash_internal_test
+    ENDIF
 
     SOURCE[poly1305_internal_test]=poly1305_internal_test.c testutil.c test_main_custom.c
     INCLUDE[poly1305_internal_test]=.. ../include ../crypto/include
@@ -358,6 +361,10 @@ IF[{- !$disabled{tests} -}]
     SOURCE[wpackettest]=wpackettest.c testutil.c test_main_custom.c
     INCLUDE[wpackettest]=../include
     DEPEND[wpackettest]=../libcrypto ../libssl.a
+
+    SOURCE[siphash_internal_test]=siphash_internal_test.c testutil.c test_main_custom.c
+    INCLUDE[siphash_internal_test]=.. ../include ../crypto/include
+    DEPEND[siphash_internal_test]=../libcrypto.a
   ENDIF
 
   IF[{- !$disabled{mdc2} -}]
index b924f833a01f520db0e1df46e3644d7a9a8bc5f6..2f651b6dce570c28e1563e4816faeae4376dcbf6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -1198,6 +1198,13 @@ static int mac_test_init(struct evp_test *t, const char *alg)
 #else
         t->skip = 1;
         return 1;
+#endif
+    } else if (strcmp(alg, "SipHash") == 0) {
+#ifndef OPENSSL_NO_SIPHASH
+        type = EVP_PKEY_SIPHASH;
+#else
+        t->skip = 1;
+        return 1;
 #endif
     } else
         return 0;
index 5dde7a3c89ba895a9723c6ea578f97196bc1e90a..5c5eb24e207f10b9171f5f0445d5bb8f82add6e0 100644 (file)
@@ -1,14 +1,68 @@
 #
-# Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved.
 #
 # Licensed under the OpenSSL license (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
 
-#cipher:key:iv:plaintext:ciphertext:0/1(decrypt/encrypt)
-#aadcipher:key:iv:plaintext:ciphertext:aad:tag:0/1(decrypt/encrypt)
-#digest:::input:output
+# SIPHASH tests - default values: 2,4 rounds, 16-byte mac
+# There are no official test vectors, they are simple vectors 1, 2, 3, etc
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input =
+Output = a3817f04ba25a8e66df67214c7550293
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 00
+Output = da87c1d86b99af44347659119b22fc45
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 0001
+Output = 8177228da4a45dc7fca38bdef60affe4
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 000102
+Output = 9c70b60c5267a94e5f33b6b02985ed51
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 00010203
+Output = f88164c12d9c8faf7d0f6e7c7bcd5579
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 0001020304
+Output = 1368875980776f8854527a07690e9627
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 000102030405
+Output = 14eeca338b208613485ea0308fd7a15e
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 00010203040506
+Output = a1f1ebbed8dbc153c0b84aa61ff08239
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 0001020304050607
+Output = 3b62a9ba6258f5610f83e264f31497b4
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 000102030405060708
+Output = 264499060ad9baabc47f8b02bb6d71ed
+
+MAC = SipHash
+Key = 000102030405060708090A0B0C0D0E0F
+Input = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E
+Output = 5150d1772f50834a503e069a973fbd7c
 
 # BLAKE2 tests, using same inputs as MD5
 # There are no official BLAKE2 test vectors we can use since they all use a key
diff --git a/test/siphash_internal_test.c b/test/siphash_internal_test.c
new file mode 100644 (file)
index 0000000..46b4660
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Internal tests for the siphash module */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include "testutil.h"
+#include "test_main_custom.h"
+#include "internal/siphash.h"
+#include "../crypto/siphash/siphash_local.h"
+#include "e_os.h"
+
+static BIO* b_stderr = NULL;
+static BIO* b_stdout = NULL;
+
+typedef struct {
+    size_t size;
+    unsigned char data[64];
+} SIZED_DATA;
+
+typedef struct {
+    int idx;
+    SIZED_DATA expected;
+} TESTDATA;
+
+/**********************************************************************
+ *
+ * Test of siphash internal functions
+ *
+ ***/
+
+static int benchmark_siphash(void)
+{
+# ifdef OPENSSL_CPUID_OBJ
+    SIPHASH siphash;
+    unsigned char key[SIPHASH_KEY_SIZE];
+    unsigned char buf[8192];
+    unsigned long long stopwatch;
+    unsigned long long OPENSSL_rdtsc();
+    unsigned int i;
+
+    memset (buf,0x55,sizeof(buf));
+    memset (key,0xAA,sizeof(key));
+
+    (void)SipHash_Init(&siphash, key, 0, 0, 0);
+
+    for (i=0;i<100000;i++)
+        SipHash_Update(&siphash, buf, sizeof(buf));
+
+    stopwatch = OPENSSL_rdtsc();
+    for (i=0;i<10000;i++)
+        SipHash_Update(&siphash, buf, sizeof(buf));
+    stopwatch = OPENSSL_rdtsc() - stopwatch;
+
+    BIO_printf(b_stdout, "%g\n",stopwatch/(double)(i*sizeof(buf)));
+
+    stopwatch = OPENSSL_rdtsc();
+    for (i=0;i<10000;i++) {
+        (void)SipHash_Init(&siphash, key, 0, 0, 0);
+        SipHash_Update(&siphash, buf, 16);
+        (void)SipHash_Final(&siphash, buf, SIPHASH_MAX_DIGEST_SIZE);
+    }
+    stopwatch = OPENSSL_rdtsc() - stopwatch;
+
+    BIO_printf(b_stdout, "%g\n",stopwatch/(double)(i));
+# else
+    BIO_printf(b_stderr,
+               "Benchmarking of siphash isn't available on this platform\n");
+# endif
+    return 1;
+}
+
+/* From C reference: https://131002.net/siphash/ */
+
+static TESTDATA tests[] = {
+    { 0, { 8, { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, } } },
+    { 1, { 8, { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, } } },
+    { 2, { 8, { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, } } },
+    { 3, { 8, { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, } } },
+    { 4, { 8, { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, } } },
+    { 5, { 8, { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, } } },
+    { 6, { 8, { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, } } },
+    { 7, { 8, { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, } } },
+    { 8, { 8, { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, } } },
+    { 9, { 8, { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, } } },
+    { 10, { 8, { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, } } },
+    { 11, { 8, { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, } } },
+    { 12, { 8, { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, } } },
+    { 13, { 8, { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, } } },
+    { 14, { 8, { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, } } },
+    { 15, { 8, { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, } } },
+    { 16, { 8, { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, } } },
+    { 17, { 8, { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, } } },
+    { 18, { 8, { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, } } },
+    { 19, { 8, { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, } } },
+    { 20, { 8, { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, } } },
+    { 21, { 8, { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, } } },
+    { 22, { 8, { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, } } },
+    { 23, { 8, { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, } } },
+    { 24, { 8, { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, } } },
+    { 25, { 8, { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, } } },
+    { 26, { 8, { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, } } },
+    { 27, { 8, { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, } } },
+    { 28, { 8, { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, } } },
+    { 29, { 8, { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, } } },
+    { 30, { 8, { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, } } },
+    { 31, { 8, { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, } } },
+    { 32, { 8, { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, } } },
+    { 33, { 8, { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, } } },
+    { 34, { 8, { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, } } },
+    { 35, { 8, { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, } } },
+    { 36, { 8, { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, } } },
+    { 37, { 8, { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, } } },
+    { 38, { 8, { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, } } },
+    { 39, { 8, { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, } } },
+    { 40, { 8, { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, } } },
+    { 41, { 8, { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, } } },
+    { 42, { 8, { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, } } },
+    { 43, { 8, { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, } } },
+    { 44, { 8, { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, } } },
+    { 45, { 8, { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, } } },
+    { 46, { 8, { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, } } },
+    { 47, { 8, { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, } } },
+    { 48, { 8, { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, } } },
+    { 49, { 8, { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, } } },
+    { 50, { 8, { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, } } },
+    { 51, { 8, { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, } } },
+    { 52, { 8, { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, } } },
+    { 53, { 8, { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, } } },
+    { 54, { 8, { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, } } },
+    { 55, { 8, { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, } } },
+    { 56, { 8, { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, } } },
+    { 57, { 8, { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, } } },
+    { 58, { 8, { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, } } },
+    { 59, { 8, { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, } } },
+    { 60, { 8, { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, } } },
+    { 61, { 8, { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, } } },
+    { 62, { 8, { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, } } },
+    { 63, { 8, { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } } },
+    { 0, { 16, { 0xa3, 0x81, 0x7f, 0x04, 0xba, 0x25, 0xa8, 0xe6, 0x6d, 0xf6, 0x72, 0x14, 0xc7, 0x55, 0x02, 0x93, } } },
+    { 1, { 16, { 0xda, 0x87, 0xc1, 0xd8, 0x6b, 0x99, 0xaf, 0x44, 0x34, 0x76, 0x59, 0x11, 0x9b, 0x22, 0xfc, 0x45, } } },
+    { 2, { 16, { 0x81, 0x77, 0x22, 0x8d, 0xa4, 0xa4, 0x5d, 0xc7, 0xfc, 0xa3, 0x8b, 0xde, 0xf6, 0x0a, 0xff, 0xe4, } } },
+    { 3, { 16, { 0x9c, 0x70, 0xb6, 0x0c, 0x52, 0x67, 0xa9, 0x4e, 0x5f, 0x33, 0xb6, 0xb0, 0x29, 0x85, 0xed, 0x51, } } },
+    { 4, { 16, { 0xf8, 0x81, 0x64, 0xc1, 0x2d, 0x9c, 0x8f, 0xaf, 0x7d, 0x0f, 0x6e, 0x7c, 0x7b, 0xcd, 0x55, 0x79, } } },
+    { 5, { 16, { 0x13, 0x68, 0x87, 0x59, 0x80, 0x77, 0x6f, 0x88, 0x54, 0x52, 0x7a, 0x07, 0x69, 0x0e, 0x96, 0x27, } } },
+    { 6, { 16, { 0x14, 0xee, 0xca, 0x33, 0x8b, 0x20, 0x86, 0x13, 0x48, 0x5e, 0xa0, 0x30, 0x8f, 0xd7, 0xa1, 0x5e, } } },
+    { 7, { 16, { 0xa1, 0xf1, 0xeb, 0xbe, 0xd8, 0xdb, 0xc1, 0x53, 0xc0, 0xb8, 0x4a, 0xa6, 0x1f, 0xf0, 0x82, 0x39, } } },
+    { 8, { 16, { 0x3b, 0x62, 0xa9, 0xba, 0x62, 0x58, 0xf5, 0x61, 0x0f, 0x83, 0xe2, 0x64, 0xf3, 0x14, 0x97, 0xb4, } } },
+    { 9, { 16, { 0x26, 0x44, 0x99, 0x06, 0x0a, 0xd9, 0xba, 0xab, 0xc4, 0x7f, 0x8b, 0x02, 0xbb, 0x6d, 0x71, 0xed, } } },
+    { 10, { 16, { 0x00, 0x11, 0x0d, 0xc3, 0x78, 0x14, 0x69, 0x56, 0xc9, 0x54, 0x47, 0xd3, 0xf3, 0xd0, 0xfb, 0xba, } } },
+    { 11, { 16, { 0x01, 0x51, 0xc5, 0x68, 0x38, 0x6b, 0x66, 0x77, 0xa2, 0xb4, 0xdc, 0x6f, 0x81, 0xe5, 0xdc, 0x18, } } },
+    { 12, { 16, { 0xd6, 0x26, 0xb2, 0x66, 0x90, 0x5e, 0xf3, 0x58, 0x82, 0x63, 0x4d, 0xf6, 0x85, 0x32, 0xc1, 0x25, } } },
+    { 13, { 16, { 0x98, 0x69, 0xe2, 0x47, 0xe9, 0xc0, 0x8b, 0x10, 0xd0, 0x29, 0x93, 0x4f, 0xc4, 0xb9, 0x52, 0xf7, } } },
+    { 14, { 16, { 0x31, 0xfc, 0xef, 0xac, 0x66, 0xd7, 0xde, 0x9c, 0x7e, 0xc7, 0x48, 0x5f, 0xe4, 0x49, 0x49, 0x02, } } },
+    { 15, { 16, { 0x54, 0x93, 0xe9, 0x99, 0x33, 0xb0, 0xa8, 0x11, 0x7e, 0x08, 0xec, 0x0f, 0x97, 0xcf, 0xc3, 0xd9, } } },
+    { 16, { 16, { 0x6e, 0xe2, 0xa4, 0xca, 0x67, 0xb0, 0x54, 0xbb, 0xfd, 0x33, 0x15, 0xbf, 0x85, 0x23, 0x05, 0x77, } } },
+    { 17, { 16, { 0x47, 0x3d, 0x06, 0xe8, 0x73, 0x8d, 0xb8, 0x98, 0x54, 0xc0, 0x66, 0xc4, 0x7a, 0xe4, 0x77, 0x40, } } },
+    { 18, { 16, { 0xa4, 0x26, 0xe5, 0xe4, 0x23, 0xbf, 0x48, 0x85, 0x29, 0x4d, 0xa4, 0x81, 0xfe, 0xae, 0xf7, 0x23, } } },
+    { 19, { 16, { 0x78, 0x01, 0x77, 0x31, 0xcf, 0x65, 0xfa, 0xb0, 0x74, 0xd5, 0x20, 0x89, 0x52, 0x51, 0x2e, 0xb1, } } },
+    { 20, { 16, { 0x9e, 0x25, 0xfc, 0x83, 0x3f, 0x22, 0x90, 0x73, 0x3e, 0x93, 0x44, 0xa5, 0xe8, 0x38, 0x39, 0xeb, } } },
+    { 21, { 16, { 0x56, 0x8e, 0x49, 0x5a, 0xbe, 0x52, 0x5a, 0x21, 0x8a, 0x22, 0x14, 0xcd, 0x3e, 0x07, 0x1d, 0x12, } } },
+    { 22, { 16, { 0x4a, 0x29, 0xb5, 0x45, 0x52, 0xd1, 0x6b, 0x9a, 0x46, 0x9c, 0x10, 0x52, 0x8e, 0xff, 0x0a, 0xae, } } },
+    { 23, { 16, { 0xc9, 0xd1, 0x84, 0xdd, 0xd5, 0xa9, 0xf5, 0xe0, 0xcf, 0x8c, 0xe2, 0x9a, 0x9a, 0xbf, 0x69, 0x1c, } } },
+    { 24, { 16, { 0x2d, 0xb4, 0x79, 0xae, 0x78, 0xbd, 0x50, 0xd8, 0x88, 0x2a, 0x8a, 0x17, 0x8a, 0x61, 0x32, 0xad, } } },
+    { 25, { 16, { 0x8e, 0xce, 0x5f, 0x04, 0x2d, 0x5e, 0x44, 0x7b, 0x50, 0x51, 0xb9, 0xea, 0xcb, 0x8d, 0x8f, 0x6f, } } },
+    { 26, { 16, { 0x9c, 0x0b, 0x53, 0xb4, 0xb3, 0xc3, 0x07, 0xe8, 0x7e, 0xae, 0xe0, 0x86, 0x78, 0x14, 0x1f, 0x66, } } },
+    { 27, { 16, { 0xab, 0xf2, 0x48, 0xaf, 0x69, 0xa6, 0xea, 0xe4, 0xbf, 0xd3, 0xeb, 0x2f, 0x12, 0x9e, 0xeb, 0x94, } } },
+    { 28, { 16, { 0x06, 0x64, 0xda, 0x16, 0x68, 0x57, 0x4b, 0x88, 0xb9, 0x35, 0xf3, 0x02, 0x73, 0x58, 0xae, 0xf4, } } },
+    { 29, { 16, { 0xaa, 0x4b, 0x9d, 0xc4, 0xbf, 0x33, 0x7d, 0xe9, 0x0c, 0xd4, 0xfd, 0x3c, 0x46, 0x7c, 0x6a, 0xb7, } } },
+    { 30, { 16, { 0xea, 0x5c, 0x7f, 0x47, 0x1f, 0xaf, 0x6b, 0xde, 0x2b, 0x1a, 0xd7, 0xd4, 0x68, 0x6d, 0x22, 0x87, } } },
+    { 31, { 16, { 0x29, 0x39, 0xb0, 0x18, 0x32, 0x23, 0xfa, 0xfc, 0x17, 0x23, 0xde, 0x4f, 0x52, 0xc4, 0x3d, 0x35, } } },
+    { 32, { 16, { 0x7c, 0x39, 0x56, 0xca, 0x5e, 0xea, 0xfc, 0x3e, 0x36, 0x3e, 0x9d, 0x55, 0x65, 0x46, 0xeb, 0x68, } } },
+    { 33, { 16, { 0x77, 0xc6, 0x07, 0x71, 0x46, 0xf0, 0x1c, 0x32, 0xb6, 0xb6, 0x9d, 0x5f, 0x4e, 0xa9, 0xff, 0xcf, } } },
+    { 34, { 16, { 0x37, 0xa6, 0x98, 0x6c, 0xb8, 0x84, 0x7e, 0xdf, 0x09, 0x25, 0xf0, 0xf1, 0x30, 0x9b, 0x54, 0xde, } } },
+    { 35, { 16, { 0xa7, 0x05, 0xf0, 0xe6, 0x9d, 0xa9, 0xa8, 0xf9, 0x07, 0x24, 0x1a, 0x2e, 0x92, 0x3c, 0x8c, 0xc8, } } },
+    { 36, { 16, { 0x3d, 0xc4, 0x7d, 0x1f, 0x29, 0xc4, 0x48, 0x46, 0x1e, 0x9e, 0x76, 0xed, 0x90, 0x4f, 0x67, 0x11, } } },
+    { 37, { 16, { 0x0d, 0x62, 0xbf, 0x01, 0xe6, 0xfc, 0x0e, 0x1a, 0x0d, 0x3c, 0x47, 0x51, 0xc5, 0xd3, 0x69, 0x2b, } } },
+    { 38, { 16, { 0x8c, 0x03, 0x46, 0x8b, 0xca, 0x7c, 0x66, 0x9e, 0xe4, 0xfd, 0x5e, 0x08, 0x4b, 0xbe, 0xe7, 0xb5, } } },
+    { 39, { 16, { 0x52, 0x8a, 0x5b, 0xb9, 0x3b, 0xaf, 0x2c, 0x9c, 0x44, 0x73, 0xcc, 0xe5, 0xd0, 0xd2, 0x2b, 0xd9, } } },
+    { 40, { 16, { 0xdf, 0x6a, 0x30, 0x1e, 0x95, 0xc9, 0x5d, 0xad, 0x97, 0xae, 0x0c, 0xc8, 0xc6, 0x91, 0x3b, 0xd8, } } },
+    { 41, { 16, { 0x80, 0x11, 0x89, 0x90, 0x2c, 0x85, 0x7f, 0x39, 0xe7, 0x35, 0x91, 0x28, 0x5e, 0x70, 0xb6, 0xdb, } } },
+    { 42, { 16, { 0xe6, 0x17, 0x34, 0x6a, 0xc9, 0xc2, 0x31, 0xbb, 0x36, 0x50, 0xae, 0x34, 0xcc, 0xca, 0x0c, 0x5b, } } },
+    { 43, { 16, { 0x27, 0xd9, 0x34, 0x37, 0xef, 0xb7, 0x21, 0xaa, 0x40, 0x18, 0x21, 0xdc, 0xec, 0x5a, 0xdf, 0x89, } } },
+    { 44, { 16, { 0x89, 0x23, 0x7d, 0x9d, 0xed, 0x9c, 0x5e, 0x78, 0xd8, 0xb1, 0xc9, 0xb1, 0x66, 0xcc, 0x73, 0x42, } } },
+    { 45, { 16, { 0x4a, 0x6d, 0x80, 0x91, 0xbf, 0x5e, 0x7d, 0x65, 0x11, 0x89, 0xfa, 0x94, 0xa2, 0x50, 0xb1, 0x4c, } } },
+    { 46, { 16, { 0x0e, 0x33, 0xf9, 0x60, 0x55, 0xe7, 0xae, 0x89, 0x3f, 0xfc, 0x0e, 0x3d, 0xcf, 0x49, 0x29, 0x02, } } },
+    { 47, { 16, { 0xe6, 0x1c, 0x43, 0x2b, 0x72, 0x0b, 0x19, 0xd1, 0x8e, 0xc8, 0xd8, 0x4b, 0xdc, 0x63, 0x15, 0x1b, } } },
+    { 48, { 16, { 0xf7, 0xe5, 0xae, 0xf5, 0x49, 0xf7, 0x82, 0xcf, 0x37, 0x90, 0x55, 0xa6, 0x08, 0x26, 0x9b, 0x16, } } },
+    { 49, { 16, { 0x43, 0x8d, 0x03, 0x0f, 0xd0, 0xb7, 0xa5, 0x4f, 0xa8, 0x37, 0xf2, 0xad, 0x20, 0x1a, 0x64, 0x03, } } },
+    { 50, { 16, { 0xa5, 0x90, 0xd3, 0xee, 0x4f, 0xbf, 0x04, 0xe3, 0x24, 0x7e, 0x0d, 0x27, 0xf2, 0x86, 0x42, 0x3f, } } },
+    { 51, { 16, { 0x5f, 0xe2, 0xc1, 0xa1, 0x72, 0xfe, 0x93, 0xc4, 0xb1, 0x5c, 0xd3, 0x7c, 0xae, 0xf9, 0xf5, 0x38, } } },
+    { 52, { 16, { 0x2c, 0x97, 0x32, 0x5c, 0xbd, 0x06, 0xb3, 0x6e, 0xb2, 0x13, 0x3d, 0xd0, 0x8b, 0x3a, 0x01, 0x7c, } } },
+    { 53, { 16, { 0x92, 0xc8, 0x14, 0x22, 0x7a, 0x6b, 0xca, 0x94, 0x9f, 0xf0, 0x65, 0x9f, 0x00, 0x2a, 0xd3, 0x9e, } } },
+    { 54, { 16, { 0xdc, 0xe8, 0x50, 0x11, 0x0b, 0xd8, 0x32, 0x8c, 0xfb, 0xd5, 0x08, 0x41, 0xd6, 0x91, 0x1d, 0x87, } } },
+    { 55, { 16, { 0x67, 0xf1, 0x49, 0x84, 0xc7, 0xda, 0x79, 0x12, 0x48, 0xe3, 0x2b, 0xb5, 0x92, 0x25, 0x83, 0xda, } } },
+    { 56, { 16, { 0x19, 0x38, 0xf2, 0xcf, 0x72, 0xd5, 0x4e, 0xe9, 0x7e, 0x94, 0x16, 0x6f, 0xa9, 0x1d, 0x2a, 0x36, } } },
+    { 57, { 16, { 0x74, 0x48, 0x1e, 0x96, 0x46, 0xed, 0x49, 0xfe, 0x0f, 0x62, 0x24, 0x30, 0x16, 0x04, 0x69, 0x8e, } } },
+    { 58, { 16, { 0x57, 0xfc, 0xa5, 0xde, 0x98, 0xa9, 0xd6, 0xd8, 0x00, 0x64, 0x38, 0xd0, 0x58, 0x3d, 0x8a, 0x1d, } } },
+    { 59, { 16, { 0x9f, 0xec, 0xde, 0x1c, 0xef, 0xdc, 0x1c, 0xbe, 0xd4, 0x76, 0x36, 0x74, 0xd9, 0x57, 0x53, 0x59, } } },
+    { 60, { 16, { 0xe3, 0x04, 0x0c, 0x00, 0xeb, 0x28, 0xf1, 0x53, 0x66, 0xca, 0x73, 0xcb, 0xd8, 0x72, 0xe7, 0x40, } } },
+    { 61, { 16, { 0x76, 0x97, 0x00, 0x9a, 0x6a, 0x83, 0x1d, 0xfe, 0xcc, 0xa9, 0x1c, 0x59, 0x93, 0x67, 0x0f, 0x7a, } } },
+    { 62, { 16, { 0x58, 0x53, 0x54, 0x23, 0x21, 0xf5, 0x67, 0xa0, 0x05, 0xd5, 0x47, 0xa4, 0xf0, 0x47, 0x59, 0xbd, } } },
+    { 63, { 16, { 0x51, 0x50, 0xd1, 0x77, 0x2f, 0x50, 0x83, 0x4a, 0x50, 0x3e, 0x06, 0x9a, 0x97, 0x3f, 0xbd, 0x7c, } } }
+};
+
+static void hex_out(BIO *b, char *prefix, int width, unsigned char* data, size_t n)
+{
+    /*
+     * this could be modified to handle multiple lines, but as it is
+     * used here, this only displays up to 16 bytes
+     */
+    BIO_printf(b, "%s", prefix);
+    BIO_hex_string(b, 0, width, data, n);
+    BIO_printf(b, "\n");
+}
+
+
+static int test_siphash(int idx)
+{
+    SIPHASH siphash;
+    TESTDATA test = tests[idx];
+    unsigned char key[SIPHASH_KEY_SIZE];
+    unsigned char in[64];
+    size_t inlen = test.idx;
+    unsigned char *expected = test.expected.data;
+    size_t expectedlen = test.expected.size;
+    unsigned char out[SIPHASH_MAX_DIGEST_SIZE];
+    size_t i;
+
+    if (expectedlen != SIPHASH_MIN_DIGEST_SIZE &&
+        expectedlen != SIPHASH_MAX_DIGEST_SIZE)
+        return 0;
+
+    if (inlen > sizeof(in))
+        return 0;
+
+    /* key and in data are 00 01 02 ... */
+    for (i = 0; i < sizeof(key); i++)
+        key[i] = i;
+
+    for (i = 0; i < inlen; i++)
+        in[i] = i;
+
+    if (!SipHash_Init(&siphash, key, expectedlen, 0, 0)) {
+        BIO_printf(b_stderr, "SipHash_Init failed\n");
+        return 0;
+    }
+    SipHash_Update(&siphash, in, inlen);
+    if (!SipHash_Final(&siphash, out, expectedlen)) {
+        BIO_printf(b_stderr, "SipHash_Final failed\n");
+        return 0;
+    }
+
+    if (memcmp(out, expected, expectedlen) != 0) {
+        BIO_printf(b_stderr, "SipHash test #%d failed.\n", idx);
+        hex_out(b_stderr, "got:      ", 16, out, expectedlen);
+        hex_out(b_stderr, "expected: ", 16, expected, expectedlen);
+        return 0;
+    }
+
+    if (inlen > 16) {
+        if (!SipHash_Init(&siphash, key, expectedlen, 0, 0)) {
+            BIO_printf(b_stderr, "SipHash_Init failed\n");
+            return 0;
+        }
+        SipHash_Update(&siphash, in, 1);
+        SipHash_Update(&siphash, in+1, inlen-1);
+        if (!SipHash_Final(&siphash, out, expectedlen)) {
+            BIO_printf(b_stderr, "SipHash_Final failed\n");
+            return 0;
+        }
+
+        if (memcmp(out, expected, expectedlen) != 0) {
+            BIO_printf(b_stderr, "SipHash test #%d/1+(N-1) failed.\n", idx);
+            hex_out(b_stderr, "got:      ", 16, out, expectedlen);
+            hex_out(b_stderr, "expected: ", 16, expected, expectedlen);
+            return 0;
+        }
+    }
+
+    if (inlen > 32) {
+        size_t half = inlen / 2;
+
+        if (!SipHash_Init(&siphash, key, expectedlen, 0, 0)) {
+            BIO_printf(b_stderr, "SipHash_Init failed\n");
+            return 0;
+        }
+        SipHash_Update(&siphash, in, half);
+        SipHash_Update(&siphash, in+half, inlen-half);
+        if (!SipHash_Final(&siphash, out, expectedlen)) {
+            BIO_printf(b_stderr, "SipHash_Final failed\n");
+            return 0;
+        }
+
+        if (memcmp(out, expected, expectedlen) != 0) {
+            BIO_printf(b_stderr, "SipHash test #%d/2 failed.\n", idx);
+            hex_out(b_stderr, "got:      ", 16, out, expectedlen);
+            hex_out(b_stderr, "expected: ", 16, expected, expectedlen);
+            return 0;
+        }
+
+        for (half = 16; half < inlen; half += 16) {
+            if (!SipHash_Init(&siphash, key, expectedlen, 0, 0)) {
+                BIO_printf(b_stderr, "SipHash_Init failed\n");
+                return 0;
+            }
+            SipHash_Update(&siphash, in, half);
+            SipHash_Update(&siphash, in+half, inlen-half);
+            if (!SipHash_Final(&siphash, out, expectedlen)) {
+                BIO_printf(b_stderr, "SipHash_Final failed\n");
+                return 0;
+            }
+
+            if (memcmp(out, expected, expectedlen) != 0) {
+                BIO_printf(b_stderr, "SipHash test #%d/%" OSSLzu "+%" OSSLzu " failed.\n",
+                       idx, half, inlen-half);
+                hex_out(b_stderr, "got:      ", 16, out, expectedlen);
+                hex_out(b_stderr, "expected: ", 16, expected, expectedlen);
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
+static int test_siphash_basic(void)
+{
+    SIPHASH siphash;
+    unsigned char key[SIPHASH_KEY_SIZE];
+    unsigned char output[SIPHASH_MAX_DIGEST_SIZE];
+
+    /* Use invalid hash size */
+    if (SipHash_Init(&siphash, key, 4, 0, 0)) {
+        BIO_printf(b_stderr, "SipHash_Init(output size = 4) should have failed\n");
+        return 0;
+    }
+
+    /* Use hash size = 8 */
+    if (!SipHash_Init(&siphash, key, 8, 0, 0)) {
+        BIO_printf(b_stderr, "SipHash_Init(output size = 8) should have succeeded\n");
+        return 0;
+    }
+    if (!SipHash_Final(&siphash, output, 8)) {
+        BIO_printf(b_stderr, "SipHash_Final(output size = 8) should have succeeded\n");
+        return 0;
+    }
+    if (SipHash_Final(&siphash, output, 16)) {
+        BIO_printf(b_stderr, "SipHash_Final(output size = 16) should have failed\n");
+        return 0;
+    }
+
+    /* Use hash size = 16 */
+    if (!SipHash_Init(&siphash, key, 16, 0, 0)) {
+        BIO_printf(b_stderr, "SipHash_Init(output size = 16) should have succeeded\n");
+        return 0;
+    }
+    if (SipHash_Final(&siphash, output, 8)) {
+        BIO_printf(b_stderr, "SipHash_Final(output size = 8) should have failed\n");
+        return 0;
+    }
+    if (!SipHash_Final(&siphash, output, 16)) {
+        BIO_printf(b_stderr, "SipHash_Final(output size = 16) should have succeeded\n");
+        return 0;
+    }
+
+    /* Use hash size = 0 (default = 16) */
+    if (!SipHash_Init(&siphash, key, 0, 0, 0)) {
+        BIO_printf(b_stderr, "SipHash_Init(output size = 0) should have succeeded\n");
+        return 0;
+    }
+    if (SipHash_Final(&siphash, output, 8)) {
+        BIO_printf(b_stderr, "SipHash_Final(output size = 8) should have failed\n");
+        return 0;
+    }
+    if (!SipHash_Final(&siphash, output, 16)) {
+        BIO_printf(b_stderr, "SipHash_Final(output size = 16) should have succeeded\n");
+        return 0;
+    }
+    return 1;
+}
+
+
+
+int test_main(int argc, char **argv)
+{
+    int result = 0;
+    int iter_argv;
+    int benchmark = 0;
+
+    b_stderr = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+    b_stdout = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
+#ifdef OPENSSL_SYS_VMS
+    b_stderr = BIO_push(BIO_new(BIO_f_linebuffer()), b_stderr);
+    b_stdout = BIO_push(BIO_new(BIO_f_linebuffer()), b_stdout);
+#endif
+
+    for (iter_argv = 1; iter_argv < argc; iter_argv++) {
+        if (strcmp(argv[iter_argv], "-b") == 0)
+            benchmark = 1;
+        else if (strcmp(argv[iter_argv], "-h") == 0)
+            goto help;
+    }
+
+    ADD_TEST(test_siphash_basic);
+    ADD_ALL_TESTS(test_siphash, OSSL_NELEM(tests));
+    if (benchmark)
+        ADD_TEST(benchmark_siphash);
+
+    result = run_tests(argv[0]);
+    goto out;
+
+ help:
+    BIO_printf(b_stdout, "-h\tThis help\n");
+    BIO_printf(b_stdout, "-b\tBenchmark in addition to the tests\n");
+
+ out:
+    BIO_free(b_stdout);
+    BIO_free(b_stderr);
+
+    return result;
+}
index 8e9b7529401f0ff3c60c69f72eb0a34abcf187ca..d876ed46669e1ade6a7d8e88e6bd78dd6e44e3a0 100644 (file)
@@ -4230,3 +4230,4 @@ UI_UTIL_wrap_read_pem_callback          4180      1_1_1   EXIST::FUNCTION:UI
 X509_VERIFY_PARAM_get_time              4181   1_1_0d  EXIST::FUNCTION:
 EVP_PKEY_get0_poly1305                  4182   1_1_1   EXIST::FUNCTION:POLY1305
 DH_check_params                         4183   1_1_0d  EXIST::FUNCTION:DH
+EVP_PKEY_get0_siphash                   4184   1_1_1   EXIST::FUNCTION:SIPHASH
index c5884d3b925f27dbf13117f1172a3ff6c023f6ce..99f5c9d011c90c15a026e455b5f3c4f8a39c86fd 100755 (executable)
@@ -1,5 +1,5 @@
 #! /usr/bin/env perl
-# Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
 #
 # Licensed under the OpenSSL license (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
@@ -82,6 +82,7 @@ my @known_algorithms = ( "RC2", "RC4", "RC5", "IDEA", "DES", "BF",
                         "MDC2", "WHIRLPOOL", "RSA", "DSA", "DH", "EC", "EC2M",
                         "HMAC", "AES", "CAMELLIA", "SEED", "GOST",
                          "SCRYPT", "CHACHA", "POLY1305", "BLAKE2",
+                        "SIPHASH",
                         # EC_NISTP_64_GCC_128
                         "EC_NISTP_64_GCC_128",
                         # Envelope "algorithms"