From a6485a228d574c35bbedd28731d8add8a20667ac Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Fri, 14 Jan 2022 13:56:23 +1000 Subject: [PATCH] Add SipHash algorithm --- configure.ac | 14 + .../header_files/doxygen_groups.h | 1 + doc/dox_comments/header_files/doxygen_pages.h | 1 + doc/dox_comments/header_files/siphash.h | 151 +++ src/include.am | 4 + wolfcrypt/benchmark/benchmark.c | 43 + wolfcrypt/benchmark/benchmark.h | 1 + wolfcrypt/src/siphash.c | 930 ++++++++++++++++++ wolfcrypt/test/test.c | 331 +++++++ wolfssl/wolfcrypt/include.am | 1 + wolfssl/wolfcrypt/siphash.h | 101 ++ 11 files changed, 1578 insertions(+) create mode 100644 doc/dox_comments/header_files/siphash.h create mode 100644 wolfcrypt/src/siphash.c create mode 100644 wolfssl/wolfcrypt/siphash.h diff --git a/configure.ac b/configure.ac index 55677749f..1294ea888 100644 --- a/configure.ac +++ b/configure.ac @@ -683,6 +683,7 @@ then test "$enable_psk" = "" && enable_psk=yes test "$enable_idea" = "" && enable_idea=yes test "$enable_cmac" = "" && enable_cmac=yes + test "$enable_siphash" = "" && enable_siphash=yes test "$enable_xts" = "" && enable_xts=yes test "$enable_hc128" = "" && enable_hc128=yes test "$enable_rabbit" = "" && enable_rabbit=yes @@ -3354,6 +3355,17 @@ else fi +# SipHash +AC_ARG_ENABLE([siphash], + [AS_HELP_STRING([--enable-siphash],[Enable SipHash (default: disabled)])], + [ ENABLED_SIPHASH=$enableval ], + [ ENABLED_SIPHASH=no ] + ) + +AS_IF([test "x$ENABLED_SIPHASH" = "xyes"], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SIPHASH"]) + + # CMAC AC_ARG_ENABLE([cmac], [AS_HELP_STRING([--enable-cmac],[Enable CMAC (default: disabled)])], @@ -7394,6 +7406,7 @@ AM_CONDITIONAL([BUILD_FIPS_RAND],[test "x$FIPS_VERSION" = "xrand"]) AM_CONDITIONAL([BUILD_FIPS_V3],[test "$HAVE_FIPS_VERSION" = 3]) AM_CONDITIONAL([BUILD_FIPS_V5],[test "$HAVE_FIPS_VERSION" = 5]) AM_CONDITIONAL([BUILD_FIPS_CURRENT],[test "$HAVE_FIPS_VERSION" -ge 2 ]) +AM_CONDITIONAL([BUILD_SIPHASH],[test "x$ENABLED_SIPHASH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CMAC],[test "x$ENABLED_CMAC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SELFTEST],[test "x$ENABLED_SELFTEST" = "xyes"]) AM_CONDITIONAL([BUILD_SHA224],[test "x$ENABLED_SHA224" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) @@ -7713,6 +7726,7 @@ echo " * SHA3: $ENABLED_SHA3" echo " * SHAKE256: $ENABLED_SHAKE256" echo " * BLAKE2: $ENABLED_BLAKE2" echo " * BLAKE2S: $ENABLED_BLAKE2S" +echo " * SipHash: $ENABLED_SIPHASH" echo " * CMAC: $ENABLED_CMAC" echo " * keygen: $ENABLED_KEYGEN" echo " * certgen: $ENABLED_CERTGEN" diff --git a/doc/dox_comments/header_files/doxygen_groups.h b/doc/dox_comments/header_files/doxygen_groups.h index d699b234c..221367ae2 100644 --- a/doc/dox_comments/header_files/doxygen_groups.h +++ b/doc/dox_comments/header_files/doxygen_groups.h @@ -207,6 +207,7 @@ \defgroup RSA Algorithms - RSA \defgroup Rabbit Algorithms - Rabbit \defgroup SHA Algorithms - SHA 128/224/256/384/512 + \defgroup SipHash Algorithm - SipHash \defgroup SRP Algorithms - SRP \defgroup ASN ASN.1 diff --git a/doc/dox_comments/header_files/doxygen_pages.h b/doc/dox_comments/header_files/doxygen_pages.h index dd558f9a8..2e8cdb484 100644 --- a/doc/dox_comments/header_files/doxygen_pages.h +++ b/doc/dox_comments/header_files/doxygen_pages.h @@ -57,6 +57,7 @@
  • \ref RIPEMD
  • \ref RSA
  • \ref SHA
  • +
  • \ref SipHash
  • \ref SRP
  • */ diff --git a/doc/dox_comments/header_files/siphash.h b/doc/dox_comments/header_files/siphash.h new file mode 100644 index 000000000..35f5a7ed2 --- /dev/null +++ b/doc/dox_comments/header_files/siphash.h @@ -0,0 +1,151 @@ + +/*! + \ingroup SipHash + + \brief This function initializes SipHash with a key for a MAC size. + + \return 0 Returned upon successfully initializing + \return BAD_FUNC_ARG Returned when siphash or key is NULL + \return BAD_FUNC_ARG Returned when outSz is neither 8 nor 16 + + \param siphash pointer to the SipHash structure to use for MACing + \param key pointer to the 16-byte array + \param outSz number of bytes to output as MAC + + _Example_ + \code + SipHash siphash[1]; + unsigned char key[16] = { ... }; + byte macSz = 8; // 8 or 16 + + if ((ret = wc_InitSipHash(siphash, key, macSz)) != 0) { + WOLFSSL_MSG("wc_InitSipHash failed"); + } + else if ((ret = wc_SipHashUpdate(siphash, data, len)) != 0) { + WOLFSSL_MSG("wc_SipHashUpdate failed"); + } + else if ((ret = wc_SipHashFinal(siphash, mac, macSz)) != 0) { + WOLFSSL_MSG("wc_SipHashFinal failed"); + } + \endcode + + \sa wc_SipHash + \sa wc_SipHashUpdate + \sa wc_SipHashFinal +*/ +WOLFSSL_API int wc_InitSipHash(SipHash* siphash, const unsigned char* key, + unsigned char outSz); + +/*! + \ingroup SipHash + + \brief Can be called to continually hash the provided byte + array of length len. + + \return 0 Returned upon successfully adding the data to the MAC + \return BAD_FUNC_ARG Returned when siphash is NULL + \return BAD_FUNC_ARG Returned when in is NULL and inSz is not zero + + \param siphash pointer to the SipHash structure to use for MACing + \param in the data to be MACed + \param inSz size of data to be MACed + + _Example_ + \code + SipHash siphash[1]; + byte data[] = { Data to be MACed }; + word32 len = sizeof(data); + + if ((ret = wc_InitSipHash(siphash, key, macSz)) != 0) { + WOLFSSL_MSG("wc_InitSipHash failed"); + } + else if ((ret = wc_SipHashUpdate(siphash, data, len)) != 0) { + WOLFSSL_MSG("wc_SipHashUpdate failed"); + } + else if ((ret = wc_SipHashFinal(siphash, mac, macSz)) != 0) { + WOLFSSL_MSG("wc_SipHashFinal failed"); + } + \endcode + + \sa wc_SipHash + \sa wc_InitSipHash + \sa wc_SipHashFinal +*/ +WOLFSSL_API int wc_SipHashUpdate(SipHash* siphash, const unsigned char* in, + word32 inSz); + +/*! + \ingroup SipHash + + \brief Finalizes MACing of data. Result is placed into out. + + \return 0 Returned upon successfully finalizing. + \return BAD_FUNC_ARG Returned when siphash of out is NULL + \return BAD_FUNC_ARG Returned when outSz is not the same as the initialized + value + + \param siphash pointer to the SipHash structure to use for MACing + \param out Byte array to hold MAC value + \param outSz number of bytes to output as MAC + + _Example_ + \code + SipHash siphash[1]; + byte mac[8] = { ... }; // 8 or 16 bytes + byte macSz = sizeof(mac); + + if ((ret = wc_InitSipHash(siphash, key, macSz)) != 0) { + WOLFSSL_MSG("wc_InitSipHash failed"); + } + else if ((ret = wc_SipHashUpdate(siphash, data, len)) != 0) { + WOLFSSL_MSG("wc_SipHashUpdate failed"); + } + else if ((ret = wc_SipHashFinal(siphash, mac, macSz)) != 0) { + WOLFSSL_MSG("wc_SipHashFinal failed"); + } + \endcode + + \sa wc_SipHash + \sa wc_InitSipHash + \sa wc_SipHashUpdate +*/ +WOLFSSL_API int wc_SipHashFinal(SipHash* siphash, unsigned char* out, + unsigned char outSz); + +/*! + \ingroup SipHash + + \brief This function one-shots the data using SipHash to calculate a MAC + based on the key. + + \return 0 Returned upon successfully MACing + \return BAD_FUNC_ARG Returned when key or out is NULL + \return BAD_FUNC_ARG Returned when in is NULL and inSz is not zero + \return BAD_FUNC_ARG Returned when outSz is neither 8 nor 16 + + \param key pointer to the 16-byte array + \param in the data to be MACed + \param inSz size of data to be MACed + \param out Byte array to hold MAC value + \param outSz number of bytes to output as MAC + + _Example_ + \code + unsigned char key[16] = { ... }; + byte data[] = { Data to be MACed }; + word32 len = sizeof(data); + byte mac[8] = { ... }; // 8 or 16 bytes + byte macSz = sizeof(mac); + + if ((ret = wc_SipHash(key, data, len, mac, macSz)) != 0) { + WOLFSSL_MSG("wc_SipHash failed"); + } + \endcode + + \sa wc_InitSipHash + \sa wc_SipHashUpdate + \sa wc_SipHashFinal +*/ +WOLFSSL_API int wc_SipHash(const unsigned char* key, const unsigned char* in, + word32 inSz, unsigned char* out, unsigned char outSz); + diff --git a/src/include.am b/src/include.am index daf320d19..245a4536f 100644 --- a/src/include.am +++ b/src/include.am @@ -487,6 +487,10 @@ endif !BUILD_FIPS_CURRENT endif !BUILD_FIPS_RAND +if BUILD_SIPHASH +src_libwolfssl_la_SOURCES += wolfcrypt/src/siphash.c +endif + src_libwolfssl_la_SOURCES += \ wolfcrypt/src/logging.c \ wolfcrypt/src/wc_port.c \ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 54f697ef2..4be7eaa38 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -171,6 +171,9 @@ #ifndef NO_HMAC #include #endif +#ifdef WOLFSSL_SIPHASH + #include +#endif #ifndef NO_PWDBASED #include #endif @@ -316,6 +319,7 @@ BENCH_HMAC_SHA224 | BENCH_HMAC_SHA256 | \ BENCH_HMAC_SHA384 | BENCH_HMAC_SHA512) #define BENCH_PBKDF2 0x00000100 +#define BENCH_SIPHASH 0x00000200 /* Asymmetric algorithms. */ #define BENCH_RSA_KEYGEN 0x00000001 @@ -547,6 +551,9 @@ static const bench_alg bench_mac_opt[] = { #ifndef NO_PWDBASED { "-pbkdf2", BENCH_PBKDF2 }, #endif + #ifdef WOLFSSL_SIPHASH + { "-siphash", BENCH_SIPHASH }, + #endif #endif { NULL, 0 } }; @@ -1990,6 +1997,11 @@ static void* benchmarks_do(void* args) bench_pbkdf2(); } #endif + #ifdef WOLFSSL_SIPHASH + if (bench_all || (bench_mac_algs & BENCH_SIPHASH)) { + bench_siphash(); + } + #endif #endif /* NO_HMAC */ #ifdef HAVE_SCRYPT @@ -4752,6 +4764,37 @@ void bench_pbkdf2(void) #endif /* NO_HMAC */ +#ifdef WOLFSSL_SIPHASH +void bench_siphash(void) +{ + double start; + int ret = 0, count; + const char* passwd16 = "passwordpassword"; + byte out[16]; + int i; + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + ret = wc_SipHash((const byte*)passwd16, bench_plain, BENCH_SIZE, + out, 8); + } + count += i; + } while (bench_stats_sym_check(start)); + bench_stats_sym_finish("SipHash-8", 1, count, BENCH_SIZE, start, ret); + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + ret = wc_SipHash((const byte*)passwd16, bench_plain, BENCH_SIZE, + out, 16); + } + count += i; + } while (bench_stats_sym_check(start)); + bench_stats_sym_finish("SipHash-16", 1, count, BENCH_SIZE, start, ret); +} +#endif + #ifndef NO_RSA #if defined(WOLFSSL_KEY_GEN) diff --git a/wolfcrypt/benchmark/benchmark.h b/wolfcrypt/benchmark/benchmark.h index 34380ba02..04ac32faf 100644 --- a/wolfcrypt/benchmark/benchmark.h +++ b/wolfcrypt/benchmark/benchmark.h @@ -77,6 +77,7 @@ void bench_hmac_sha224(int); void bench_hmac_sha256(int); void bench_hmac_sha384(int); void bench_hmac_sha512(int); +void bench_siphash(void); void bench_rsaKeyGen(int); void bench_rsaKeyGen_size(int, int); void bench_rsa(int); diff --git a/wolfcrypt/src/siphash.c b/wolfcrypt/src/siphash.c new file mode 100644 index 000000000..bf95b5b5e --- /dev/null +++ b/wolfcrypt/src/siphash.c @@ -0,0 +1,930 @@ +/* siphash.c + * + * Copyright (C) 2006-2021 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include +#include + +#include +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + + +/* DESCRIPTION + * + * SipHash is a PseudoRandom Function (PRF) that can be used with small + * messages (less than 256 bytes). + * SipHash can be used for Message Authentication Codes (MACs) and as such must + * be passed a secret key. + * https://eprint.iacr.org/2012/351.pdf + * + * SipHash is commonly used in hash tables. + * Do not use this as a hash not as a general purpose MAC. + * + * WOLFSSL_SIPHASH_CROUNDS and WOLFSSL_SIPHASH_DROUNDS can be defined at build + * time to change the algorithm. + * Default is SipHash-2-4: + * WOLFSSL_SIPHASH_CROUNDS = 2 + * WOLFSSL_SIPHASH_DROUNDS = 4 + * + * Inline assembly implementations of wc_SipHash() written for: + * - GCC for Intel x86_64 + * - GCC for Aarch64. + */ + +#ifdef WOLFSSL_SIPHASH + +#ifdef LITTLE_ENDIAN_ORDER +/** + * Decode little-endian byte array to 64-bit number. + * + * @param [in] a Little-endian byte array. + * @return 64-bit number. + */ +#define GET_U64(a) (*(word64*)(a)) +/** + * Decode little-endian byte array to 32-bit number. + * + * @param [in] a Little-endian byte array. + * @return 32-bit number. + */ +#define GET_U32(a) (*(word32*)(a)) +/** + * Decode little-endian byte array to 16-bit number. + * + * @param [in] a Little-endian byte array. + * @return 16-bit number. + */ +#define GET_U16(a) (*(word16*)(a)) +/** + * Encode 64-bit nuumber to a little-endian byte array. + * + * @param [out] a Byte array to write into. + * @param [in] n Number to encode. + */ +#define SET_U64(a, n) ((*(word64*)(a)) = n) +#else +/** + * Decode little-endian byte array to 64-bit number. + * + * @param [in] a Little-endian byte array. + * @return 64-bit number. + */ +#define GET_U64(a) (((word64)((a)[7]) << 56) | \ + ((word64)((a)[6]) << 48) | \ + ((word64)((a)[5]) << 40) | \ + ((word64)((a)[4]) << 32) | \ + ((word64)((a)[3]) << 24) | \ + ((word64)((a)[2]) << 16) | \ + ((word64)((a)[1]) << 8) | \ + ((word64)((a)[0]) )) +/** + * Decode little-endian byte array to 32-bit number. + * + * @param [in] a Little-endian byte array. + * @return 32-bit number. + */ +#define GET_U32(a) (((word64)((a)[3]) << 24) | \ + ((word32)((a)[2]) << 16) | \ + ((word32)((a)[1]) << 8) | \ + ((word32)((a)[0]) )) +/** + * Decode little-endian byte array to 16-bit number. + * + * @param [in] a Little-endian byte array. + * @return 16-bit number. + */ +#define GET_U16(a) (((word16)((a)[1]) << 8) | \ + ((word16)((a)[0]) )) +/** + * Encode 64-bit nuumber to a little-endian byte array. + * + * @param [out] a Byte array to write into. + * @param [in] n Number to encode. + */ +#define SET_U64(a, n) (a)[0] = (byte)((n) ); \ + (a)[1] = (byte)((n) >> 8); \ + (a)[2] = (byte)((n) >> 16); \ + (a)[3] = (byte)((n) >> 24); \ + (a)[4] = (byte)((n) >> 32); \ + (a)[5] = (byte)((n) >> 40); \ + (a)[6] = (byte)((n) >> 48); \ + (a)[7] = (byte)((n) >> 56) +#endif + +/** + * Initialize SipHash operation with a key. + * + * @param [out] sipHash SipHash object. + * @param [in] key 16 byte array - little endian. + * @return BAD_FUNC_ARG when sipHash or key is NULL. + * @return BAD_FUNC_ARG when outSz is neither 8 nor 16. + * @return 0 on success. + */ +int wc_InitSipHash(SipHash* sipHash, const unsigned char* key, + unsigned char outSz) +{ + int ret = 0; + + /* Validate parameters. */ + if ((sipHash == NULL) || (key == NULL) || + ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + word64 k0 = GET_U64(key + 0); + word64 k1 = GET_U64(key + 8); + + /* Initialize state with key. */ + sipHash->v[0] = 0x736f6d6570736575UL; + if (outSz == SIPHASH_MAC_SIZE_8) { + sipHash->v[1] = 0x646f72616e646f6dUL; + } + else { + sipHash->v[1] = 0x646f72616e646f83UL; + } + sipHash->v[2] = 0x6c7967656e657261UL; + sipHash->v[3] = 0x7465646279746573UL; + + sipHash->v[0] ^= k0; + sipHash->v[1] ^= k1; + sipHash->v[2] ^= k0; + sipHash->v[3] ^= k1; + + /* No cached message bytes. */ + sipHash->cacheCnt = 0; + /* No message bytes compressed yet. */ + sipHash->inCnt = 0; + /* Keep the output size to check against final call. */ + sipHash->outSz = outSz; + } + + return ret; +} + +/** + * One round of SipHash. + * + * @param [in, out] sipHash SipHash object. + */ +static WC_INLINE void SipRound(SipHash *sipHash) +{ + word64* v = sipHash->v; + + v[0] += v[1]; + v[2] += v[3]; + v[1] = rotlFixed64(v[1], 13); + v[3] = rotlFixed64(v[3], 16); + v[1] ^= v[0]; + v[3] ^= v[2]; + v[0] = rotlFixed64(v[0], 32); + v[2] += v[1]; + v[0] += v[3]; + v[1] = rotlFixed64(v[1], 17); + v[3] = rotlFixed64(v[3], 21); + v[1] ^= v[2]; + v[3] ^= v[0]; + v[2] = rotlFixed64(v[2], 32); +} + +/** + * One step of the compression operation. + * + * @param [in, out] sipHash SipHash object. + * @param [in] m Message to compress. + */ +static WC_INLINE void SipHashCompress(SipHash* sipHash, const byte* m) +{ + int i; + + sipHash->v[3] ^= GET_U64(m); + for (i = 0; i < WOLFSSL_SIPHASH_CROUNDS; i++) { + SipRound(sipHash); + } + sipHash->v[0] ^= GET_U64(m); +} + +/** + * Update the SipHash operation with more data. + * + * @param [in, out] sipHash SipHash object. + * @param [in] in Input message. + * @param [in] inSz Size of input message. + * @return BAD_FUNC_ARG when sipHash is NULL. + * @return BAD_FUNC_ARG when in is NULL and inSz is not zero. + * @return 0 on success. + */ +int wc_SipHashUpdate(SipHash* sipHash, const unsigned char* in, word32 inSz) +{ + int ret = 0; + + /* Validate parameters. */ + if ((sipHash == NULL) || ((in == NULL) && (inSz != 0))) { + ret = BAD_FUNC_ARG; + } + + /* Process any message bytes. */ + if ((ret == 0) && (inSz > 0)) { + /* Add to cache if already started. */ + if (sipHash->cacheCnt > 0) { + byte len = SIPHASH_BLOCK_SIZE - sipHash->cacheCnt; + if (len > inSz) { + len = inSz; + } + XMEMCPY(sipHash->cache + sipHash->cacheCnt, in, len); + in += len; + inSz -= len; + sipHash->cacheCnt += len; + + if (sipHash->cacheCnt == SIPHASH_BLOCK_SIZE) { + /* Compress the block from the cache. */ + SipHashCompress(sipHash, sipHash->cache); + sipHash->cacheCnt = 0; + } + } + + /* Process more blocks from message. */ + while (inSz >= SIPHASH_BLOCK_SIZE) { + /* Compress the next block from the message data. */ + SipHashCompress(sipHash, in); + in += SIPHASH_BLOCK_SIZE; + inSz -= SIPHASH_BLOCK_SIZE; + sipHash->inCnt += SIPHASH_BLOCK_SIZE; + } + + if (inSz > 0) { + /* Cache remaining message bytes less than a block. */ + XMEMCPY(sipHash->cache, in, inSz); + sipHash->cacheCnt = inSz; + } + } + + return ret; +} + +/** + * Calculate 8-bytes of output. + * + * @param [in, out] sipHash SipHash object. + * @param [out] out Buffer to place 8-bytes of MAC into. + */ +static WC_INLINE void SipHashOut(SipHash* sipHash, byte* out) +{ + word64 n; + int i; + + for (i = 0; i < WOLFSSL_SIPHASH_DROUNDS; i++) { + SipRound(sipHash); + } + n = sipHash->v[0] ^ sipHash->v[1] ^ sipHash->v[2] ^ sipHash->v[3]; + SET_U64(out, n); +} + +/** + * Finalize SipHash operation. + * + * @param [in, out] sipHash SipHash object. + * @param [out] out Buffer to place MAC into. + * @param [in] outSz Size of ouput MAC. 8 or 16 only. + * @return BAD_FUNC_ARG when sipHash or out is NULL. + * @return BAD_FUNC_ARG when outSz is not the same as initialized value. + * @return 0 on success. + */ +int wc_SipHashFinal(SipHash* sipHash, unsigned char* out, unsigned char outSz) +{ + int ret = 0; + + /* Validate parameters. */ + if ((sipHash == NULL) || (out == NULL) || (outSz != sipHash->outSz)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + /* Put int remaining cached message bytes. */ + XMEMSET(sipHash->cache + sipHash->cacheCnt, 0, 7 - sipHash->cacheCnt); + sipHash->cache[7] = (byte)(sipHash->inCnt + sipHash->cacheCnt); + + SipHashCompress(sipHash, sipHash->cache); + sipHash->cacheCnt = 0; + + /* Output either 8 or 16 bytes. */ + if (outSz == SIPHASH_MAC_SIZE_8) { + sipHash->v[2] ^= (word64)0xff; + SipHashOut(sipHash, out); + } + else { + sipHash->v[2] ^= (word64)0xee; + SipHashOut(sipHash, out); + sipHash->v[1] ^= (word64)0xdd; + SipHashOut(sipHash, out + 8); + } + } + + return ret; +} + +#if defined(__GNUC__) && defined(__x86_64__) && \ + (WOLFSSL_SIPHASH_CROUNDS == 1 || WOLFSSL_SIPHASH_CROUNDS == 2) && \ + (WOLFSSL_SIPHASH_DROUNDS == 2 || WOLFSSL_SIPHASH_DROUNDS == 4) + +#define SIPHASH_ROUND(v0, v1, v2, v3) \ + "addq " #v1 ", " #v0 "\n\t" \ + "addq " #v3 ", " #v2 "\n\t" \ + "rolq $13, " #v1 "\n\t" \ + "rolq $16, " #v3 "\n\t" \ + "xorq " #v0 ", " #v1 "\n\t" \ + "xorq " #v2 ", " #v3 "\n\t" \ + "rolq $32, " #v0 "\n\t" \ + "addq " #v1 ", " #v2 "\n\t" \ + "addq " #v3 ", " #v0 "\n\t" \ + "rolq $17, " #v1 "\n\t" \ + "rolq $21, " #v3 "\n\t" \ + "xorq " #v2 ", " #v1 "\n\t" \ + "xorq " #v0 ", " #v3 "\n\t" \ + "rolq $32, " #v2 "\n\t" + +#define SIPHASH_LAST_ROUND(v0, v1, v2, v3) \ + "addq " #v1 ", " #v0 "\n\t" \ + "addq " #v3 ", " #v2 "\n\t" \ + "rolq $13, " #v1 "\n\t" \ + "rolq $16, " #v3 "\n\t" \ + "xorq " #v0 ", " #v1 "\n\t" \ + "xorq " #v2 ", " #v3 "\n\t" \ + "addq " #v1 ", " #v2 "\n\t" \ + "rolq $17, " #v1 "\n\t" \ + "rolq $21, " #v3 "\n\t" \ + "xorq " #v2 ", " #v1 "\n\t" \ + "rolq $32, " #v2 "\n\t" + +/** + * Perform SipHash operation on input with key. + * + * @param [in] key 16 byte array - little endian. + * @param [in] in Input message. + * @param [in] inSz Size of input message. + * @param [out] out Buffer to place MAC into. + * @param [in] outSz Size of ouput MAC. 8 or 16 only. + * @return BAD_FUNC_ARG when key or out is NULL. + * @return BAD_FUNC_ARG when in is NULL and inSz is not zero. + * @return BAD_FUNC_ARG when outSz is neither 8 nor 16. + * @return 0 on success. + */ +int wc_SipHash(const unsigned char* key, const unsigned char* in, word32 inSz, + unsigned char* out, unsigned char outSz) +{ + if ((key == NULL) || ((in == NULL) && (inSz != 0)) || (out == NULL) || + ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) { + return BAD_FUNC_ARG; + } + + /* v0=%r8, v1=%r9, v2=%r10, v3=%r11 */ + __asm__ __volatile__ ( + "movq (%[key]), %%r12\n\t" + "movq 8(%[key]), %%r13\n\t" + + "movabsq $0x736f6d6570736575, %%r8\n\t" + "movabsq $0x646f72616e646f6d, %%r9\n\t" + "movabsq $0x6c7967656e657261, %%r10\n\t" + "movabsq $0x7465646279746573, %%r11\n\t" + + "xorq %%r12, %%r8\n\t" + "xorq %%r13, %%r9\n\t" + "xorq %%r12, %%r10\n\t" + "xorq %%r13, %%r11\n\t" + + "cmp $8, %[outSz]\n\t" + "mov %[inSz], %%r13d\n\t" + "je L_siphash_8_top\n\t" + "xorq $0xee, %%r9\n\t" + "L_siphash_8_top:\n\t" + + "sub $8, %[inSz]\n\t" + "jb L_siphash_done_input_8\n\t" + "L_siphash_input:\n\t" + "movq (%[in]), %%r12\n\t" + "addq $8, %[in]\n\t" + "xorq %%r12, %%r11\n\t" +#if WOLFSSL_SIPHASH_CROUNDS == 1 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) +#elif WOLFSSL_SIPHASH_CROUNDS == 2 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) +#endif + "xorq %%r12, %%r8\n\t" + "sub $8, %[inSz]\n\t" + "jge L_siphash_input\n\t" + "L_siphash_done_input_8:\n\t" + "add $8, %[inSz]\n\t" + + "shlq $56, %%r13\n\t" + "cmp $0, %[inSz]\n\t" + "je L_siphash_last_done\n\t" + "cmp $4, %[inSz]\n\t" + "jl L_siphash_last_lt4\n\t" + + "cmp $7, %[inSz]\n\t" + "jl L_siphash_n7\n\t" + "movzxb 6(%[in]), %%r12\n\t" + "shlq $48, %%r12\n\t" + "orq %%r12, %%r13\n\t" + "L_siphash_n7:\n\t" + + "cmp $6, %[inSz]\n\t" + "jl L_siphash_n6\n\t" + "movzxb 5(%[in]), %%r12\n\t" + "shlq $40, %%r12\n\t" + "orq %%r12, %%r13\n\t" + "L_siphash_n6:\n\t" + + "cmp $5, %[inSz]\n\t" + "jl L_siphash_n5\n\t" + "movzxb 4(%[in]), %%r12\n\t" + "shlq $32, %%r12\n\t" + "orq %%r12, %%r13\n\t" + "L_siphash_n5:\n\t" + + "mov (%[in]), %%r12d\n\t" + "orq %%r12, %%r13\n\t" + "jmp L_siphash_last_done\n\t" + + "L_siphash_last_lt4:\n\t" + + "cmp $1, %[inSz]\n\t" + "je L_siphash_last_1\n\t" + + "cmp $3, %[inSz]\n\t" + "jl L_siphash_n3\n\t" + "movzxb 2(%[in]), %%r12\n\t" + "shlq $16, %%r12\n\t" + "orq %%r12, %%r13\n\t" + "L_siphash_n3:\n\t" + + "movw (%[in]), %%r12w\n\t" + "or %%r12w, %%r13w\n\t" + "jmp L_siphash_last_done\n\t" + + "L_siphash_last_1:\n\t" + "movb (%[in]), %%r12b\n\t" + "or %%r12b, %%r13b\n\t" + + "L_siphash_last_done:\n\t" + + "xorq %%r13, %%r11\n\t" +#if WOLFSSL_SIPHASH_CROUNDS == 1 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) +#elif WOLFSSL_SIPHASH_CROUNDS == 2 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) +#endif + "xorq %%r13, %%r8\n\t" + + "cmp $8, %[outSz]\n\t" + "je L_siphash_8_end\n\t" + + "xor $0xee, %%r10b\n\t" +#if WOLFSSL_SIPHASH_DROUNDS == 2 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) +#elif WOLFSSL_SIPHASH_DROUNDS == 4 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) +#endif + "movq %%r8, %%r12\n\t" + "xorq %%r9, %%r12\n\t" + "xorq %%r10, %%r12\n\t" + "xorq %%r11, %%r12\n\t" + "movq %%r12, (%[out])\n\t" + + "xor $0xdd, %%r9b\n\t" +#if WOLFSSL_SIPHASH_DROUNDS == 2 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_LAST_ROUND(%%r8, %%r9, %%r10, %%r11) +#elif WOLFSSL_SIPHASH_DROUNDS == 4 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_LAST_ROUND(%%r8, %%r9, %%r10, %%r11) +#endif + "xorq %%r11, %%r9\n\t" + "xorq %%r10, %%r9\n\t" + "movq %%r9, 8(%[out])\n\t" + "jmp L_siphash_done\n\t" + + "L_siphash_8_end:\n\t" + "xor $0xff, %%r10b\n\t" +#if WOLFSSL_SIPHASH_DROUNDS == 2 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_LAST_ROUND(%%r8, %%r9, %%r10, %%r11) +#elif WOLFSSL_SIPHASH_DROUNDS == 4 + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_ROUND(%%r8, %%r9, %%r10, %%r11) + SIPHASH_LAST_ROUND(%%r8, %%r9, %%r10, %%r11) +#endif + "xorq %%r11, %%r9\n\t" + "xorq %%r10, %%r9\n\t" + "movq %%r9, (%[out])\n\t" + + "L_siphash_done:\n\t" + + : [in] "+r" (in), [inSz] "+r" (inSz) + : [key] "r" (key), [out] "r" (out) , [outSz] "r" (outSz) + : "memory", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13" + ); + + return 0; +} + +#elif defined(__GNUC__) && defined(__aarch64__) && \ + (WOLFSSL_SIPHASH_CROUNDS == 1 || WOLFSSL_SIPHASH_CROUNDS == 2) && \ + (WOLFSSL_SIPHASH_DROUNDS == 2 || WOLFSSL_SIPHASH_DROUNDS == 4) + +#define SIPHASH_ROUND(v0, v1, v2, v3) \ + "add " #v0 ", " #v0 ", " #v1 "\n\t" \ + "add " #v2 ", " #v2 ", " #v3 "\n\t" \ + "ror " #v1 ", " #v1 ", #51\n\t" \ + "ror " #v3 ", " #v3 ", #48\n\t" \ + "eor " #v1 ", " #v1 ", " #v0 "\n\t" \ + "eor " #v3 ", " #v3 ", " #v2 "\n\t" \ + "ror " #v0 ", " #v0 ", #32\n\t" \ + "add " #v2 ", " #v2 ", " #v1 "\n\t" \ + "add " #v0 ", " #v0 ", " #v3 "\n\t" \ + "ror " #v1 ", " #v1 ", #47\n\t" \ + "ror " #v3 ", " #v3 ", #43\n\t" \ + "eor " #v1 ", " #v1 ", " #v2 "\n\t" \ + "eor " #v3 ", " #v3 ", " #v0 "\n\t" \ + "ror " #v2 ", " #v2 ", #32\n\t" + +#define SIPHASH_LAST_ROUND(v0, v1, v2, v3) \ + "add " #v0 ", " #v0 ", " #v1 "\n\t" \ + "add " #v2 ", " #v2 ", " #v3 "\n\t" \ + "ror " #v1 ", " #v1 ", #51\n\t" \ + "ror " #v3 ", " #v3 ", #48\n\t" \ + "eor " #v1 ", " #v1 ", " #v0 "\n\t" \ + "eor " #v3 ", " #v3 ", " #v2 "\n\t" \ + "add " #v2 ", " #v2 ", " #v1 "\n\t" \ + "ror " #v1 ", " #v1 ", #47\n\t" \ + "ror " #v3 ", " #v3 ", #43\n\t" \ + "eor " #v1 ", " #v1 ", " #v2 "\n\t" \ + "ror " #v2 ", " #v2 ", #32\n\t" + +/** + * Perform SipHash operation on input with key. + * + * @param [in] key 16 byte array - little endian. + * @param [in] in Input message. + * @param [in] inSz Size of input message. + * @param [out] out Buffer to place MAC into. + * @param [in] outSz Size of ouput MAC. 8 or 16 only. + * @return BAD_FUNC_ARG when key or out is NULL. + * @return BAD_FUNC_ARG when in is NULL and inSz is not zero. + * @return BAD_FUNC_ARG when outSz is not 8 nor 16. + * @return 0 on success. + */ +int wc_SipHash(const unsigned char* key, const unsigned char* in, word32 inSz, + unsigned char* out, unsigned char outSz) +{ + if ((key == NULL) || ((in == NULL) && (inSz != 0)) || (out == NULL) || + ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) { + return BAD_FUNC_ARG; + } + + /* v0=x8, v1=x9, v2=x10, v3=x11 */ + __asm__ __volatile__ ( + "ldp x12, x13, [%[key]]\n\t" + + "mov x8, #0x6575\n\t" + "movk x8, #0x7073, lsl #16\n\t" + "movk x8, #0x6d65, lsl #32\n\t" + "movk x8, #0x736f, lsl #48\n\t" + "mov x9, #0x6f6d\n\t" + "movk x9, #0x6e64, lsl #16\n\t" + "movk x9, #0x7261, lsl #32\n\t" + "movk x9, #0x646f, lsl #48\n\t" + "mov x10, #0x7261\n\t" + "movk x10, #0x6e65, lsl #16\n\t" + "movk x10, #0x6765, lsl #32\n\t" + "movk x10, #0x6c79, lsl #48\n\t" + "mov x11, #0x6573\n\t" + "movk x11, #0x7974, lsl #16\n\t" + "movk x11, #0x6462, lsl #32\n\t" + "movk x11, #0x7465, lsl #48\n\t" + + "eor x8, x8, x12\n\t" + "eor x9, x9, x13\n\t" + "eor x10, x10, x12\n\t" + "eor x11, x11, x13\n\t" + + "mov w13, %w[inSz]\n\t" + "cmp %w[outSz], #8\n\t" + "b.eq L_siphash_8_top\n\t" + "mov w12, #0xee\n\t" + "eor x9, x9, x12\n\t" + "L_siphash_8_top:\n\t" + + "subs %w[inSz], %w[inSz], #8\n\t" + "b.mi L_siphash_done_input_8\n\t" + "L_siphash_input:\n\t" + "ldr x12, [%[in]], #8\n\t" + "eor x11, x11, x12\n\t" +#if WOLFSSL_SIPHASH_CROUNDS == 1 + SIPHASH_ROUND(x8, x9, x10, x11) +#elif WOLFSSL_SIPHASH_CROUNDS == 2 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) +#endif + "eor x8, x8, x12\n\t" + "subs %w[inSz], %w[inSz], #8\n\t" + "b.ge L_siphash_input\n\t" + "L_siphash_done_input_8:\n\t" + "add %w[inSz], %w[inSz], #8\n\t" + + "lsl x13, x13, #56\n\t" + "cmp %w[inSz], #0\n\t" + "b.eq L_siphash_last_done\n\t" + "cmp %w[inSz], #4\n\t" + "b.lt L_siphash_last_lt4\n\t" + + "cmp %w[inSz], #7\n\t" + "b.lt L_siphash_n7\n\t" + "ldrb w12, [%[in], 6]\n\t" + "orr x13, x13, x12, lsl 48\n\t" + "L_siphash_n7:\n\t" + + "cmp %w[inSz], #6\n\t" + "b.lt L_siphash_n6\n\t" + "ldrb w12, [%[in], 5]\n\t" + "orr x13, x13, x12, lsl 40\n\t" + "L_siphash_n6:\n\t" + + "cmp %w[inSz], #5\n\t" + "b.lt L_siphash_n5\n\t" + "ldrb w12, [%[in], 4]\n\t" + "orr x13, x13, x12, lsl 32\n\t" + "L_siphash_n5:\n\t" + + "ldr w12, [%[in]]\n\t" + "orr x13, x13, x12\n\t" + "b L_siphash_last_done\n\t" + + "L_siphash_last_lt4:\n\t" + + "cmp %w[inSz], #1\n\t" + "b.eq L_siphash_last_1\n\t" + + "cmp %w[inSz], #3\n\t" + "b.lt L_siphash_n3\n\t" + "ldrb w12, [%[in], 2]\n\t" + "orr x13, x13, x12, lsl 16\n\t" + "L_siphash_n3:\n\t" + + "ldrh w12, [%[in]]\n\t" + "orr x13, x13, x12\n\t" + "b L_siphash_last_done\n\t" + + "L_siphash_last_1:\n\t" + "ldrb w12, [%[in]]\n\t" + "orr x13, x13, x12\n\t" + + "L_siphash_last_done:\n\t" + + "eor x11, x11, x13\n\t" +#if WOLFSSL_SIPHASH_CROUNDS == 1 + SIPHASH_ROUND(x8, x9, x10, x11) +#elif WOLFSSL_SIPHASH_CROUNDS == 2 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) +#endif + "eor x8, x8, x13\n\t" + + "cmp %w[outSz], #8\n\t" + "b.eq L_siphash_8_end\n\t" + + "mov w13, #0xee\n\t" + "eor x10, x10, x13\n\t" +#if WOLFSSL_SIPHASH_DROUNDS == 2 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) +#elif WOLFSSL_SIPHASH_DROUNDS == 4 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) +#endif + "eor x12, x8, x9\n\t" + "eor x13, x10, x11\n\t" + "eor x12, x12, x13\n\t" + + "mov w13, #0xdd\n\t" + "eor x9, x9, x13\n\t" +#if WOLFSSL_SIPHASH_DROUNDS == 2 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_LAST_ROUND(x8, x9, x10, x11) +#elif WOLFSSL_SIPHASH_DROUNDS == 4 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_LAST_ROUND(x8, x9, x10, x11) +#endif + "eor x13, x11, x9\n\t" + "eor x13, x13, x10\n\t" + "stp x12, x13, [%[out]]\n\t" + "b L_siphash_done\n\t" + + "L_siphash_8_end:\n\t" + "mov w13, #0xff\n\t" + "eor x10, x10, x13\n\t" +#if WOLFSSL_SIPHASH_DROUNDS == 2 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_LAST_ROUND(x8, x9, x10, x11) +#elif WOLFSSL_SIPHASH_DROUNDS == 4 + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_ROUND(x8, x9, x10, x11) + SIPHASH_LAST_ROUND(x8, x9, x10, x11) +#endif + "eor x13, x11, x9\n\t" + "eor x13, x13, x10\n\t" + "str x13, [%[out]]\n\t" + + "L_siphash_done:\n\t" + + : [in] "+r" (in), [inSz] "+r" (inSz) + : [key] "r" (key), [out] "r" (out) , [outSz] "r" (outSz) + : "memory", "x8", "x9", "x10", "x11", "x12", "x13" + ); + + return 0; +} + +#else + +#define SipRoundV(v0, v1, v2, v3) \ + v0 += v1; \ + v2 += v3; \ + v1 = rotlFixed64(v1, 13); \ + v3 = rotlFixed64(v3, 16); \ + v1 ^= v0; \ + v3 ^= v2; \ + v0 = rotlFixed64(v0, 32); \ + v2 += v1; \ + v0 += v3; \ + v1 = rotlFixed64(v1, 17); \ + v3 = rotlFixed64(v3, 21); \ + v1 ^= v2; \ + v3 ^= v0; \ + v2 = rotlFixed64(v2, 32); + +#define SipHashCompressV(v0, v1, v2, v3, m) \ + do { \ + int i; \ + v3 ^= m; \ + for (i = 0; i < WOLFSSL_SIPHASH_CROUNDS; i++) { \ + SipRoundV(v0, v1, v2, v3); \ + } \ + v0 ^= m; \ + } \ + while (0) + +#define SipHashOutV(v0, v1, v2, v3, out) \ + do { \ + word64 n; \ + int i; \ + \ + for (i = 0; i < WOLFSSL_SIPHASH_DROUNDS; i++) { \ + SipRoundV(v0, v1, v2, v3); \ + } \ + n = v0 ^ v1 ^ v2 ^ v3; \ + SET_U64(out, n); \ + } \ + while (0) + +/** + * Perform SipHash operation on input with key. + * + * @param [in] key 16 byte array - little endian. + * @param [in] in Input message. + * @param [in] inSz Size of input message. + * @param [out] out Buffer to place MAC into. + * @param [in] outSz Size of ouput MAC. 8 or 16 only. + * @return BAD_FUNC_ARG when key or out is NULL. + * @return BAD_FUNC_ARG when in is NULL and inSz is not zero. + * @return BAD_FUNC_ARG when outSz is not 8 nor 16. + * @return 0 on success. + */ +int wc_SipHash(const unsigned char* key, const unsigned char* in, word32 inSz, + unsigned char* out, unsigned char outSz) +{ + int ret = 0; + + if ((key == NULL) || ((in == NULL) && (inSz != 0)) || (out == NULL) || + ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + word64 v0, v1, v2, v3; + word64 k0 = GET_U64(key + 0); + word64 k1 = GET_U64(key + 8); + word64 b = (word64)((word64)inSz << 56); + + /* Initialize state with key. */ + v0 = 0x736f6d6570736575UL; + v1 = 0x646f72616e646f6dUL; + v2 = 0x6c7967656e657261UL; + v3 = 0x7465646279746573UL; + + if (outSz == SIPHASH_MAC_SIZE_16) { + v1 ^= 0xee; + } + + v0 ^= k0; + v1 ^= k1; + v2 ^= k0; + v3 ^= k1; + + /* Process blocks from message. */ + while (inSz >= SIPHASH_BLOCK_SIZE) { + word64 m = GET_U64(in); + /* Compress the next block from the message data. */ + SipHashCompressV(v0, v1, v2, v3, m); + in += SIPHASH_BLOCK_SIZE; + inSz -= SIPHASH_BLOCK_SIZE; + } + + switch (inSz) { + case 7: + b |= (word64)in[6] << 48; + /* fall-through */ + case 6: + b |= (word64)in[5] << 40; + /* fall-through */ + case 5: + b |= (word64)in[4] << 32; + /* fall-through */ + case 4: + b |= (word64)GET_U32(in); + break; + case 3: + b |= (word64)in[2] << 16; + /* fall-through */ + case 2: + b |= (word64)GET_U16(in); + break; + case 1: + b |= (word64)in[0]; + break; + case 0: + break; + } + SipHashCompressV(v0, v1, v2, v3, b); + + /* Output either 8 or 16 bytes. */ + if (outSz == SIPHASH_MAC_SIZE_8) { + v2 ^= (word64)0xff; + SipHashOutV(v0, v1, v2, v3, out); + } + else { + v2 ^= (word64)0xee; + SipHashOutV(v0, v1, v2, v3, out); + v1 ^= (word64)0xdd; + SipHashOutV(v0, v1, v2, v3, out + 8); + } + } + + return ret; +} +#endif /* !ASM */ + +#endif /* WOLFSSL_SIPHASH */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index bf7db60b1..d98c0714a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -235,6 +235,7 @@ _Pragma("GCC diagnostic ignored \"-Wunused-function\"") #include #include #include +#include #include #include #include @@ -426,6 +427,9 @@ WOLFSSL_TEST_SUBROUTINE int aes192_test(void); WOLFSSL_TEST_SUBROUTINE int aes256_test(void); WOLFSSL_TEST_SUBROUTINE int aesofb_test(void); WOLFSSL_TEST_SUBROUTINE int cmac_test(void); +#if defined(WOLFSSL_SIPHASH) +WOLFSSL_TEST_SUBROUTINE int siphash_test(void); +#endif WOLFSSL_TEST_SUBROUTINE int poly1305_test(void); WOLFSSL_TEST_SUBROUTINE int aesgcm_test(void); WOLFSSL_TEST_SUBROUTINE int aesgcm_default_test(void); @@ -1330,6 +1334,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("CMAC test passed!\n"); #endif +#if defined(WOLFSSL_SIPHASH) + if ( (ret = siphash_test()) != 0) + return err_sys("SipHash test failed!\n", ret); + else + TEST_PASS("SipHash test passed!\n"); +#endif + #ifdef HAVE_LIBZ if ( (ret = compress_test()) != 0) return err_sys("COMPRESS test failed!\n", ret); @@ -30334,6 +30345,326 @@ WOLFSSL_TEST_SUBROUTINE int cmac_test(void) #endif /* NO_AES && WOLFSSL_CMAC */ +#if defined(WOLFSSL_SIPHASH) + +#if WOLFSSL_SIPHASH_CROUNDS == 2 && WOLFSSL_SIPHASH_DROUNDS == 4 +/* Test vectors from: + * https://github.com/veorq/SipHash/blob/master/vectors.h + */ +static const unsigned char siphash_key[SIPHASH_KEY_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; +static const unsigned char siphash_msg[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}; +static const unsigned char siphash_r8[64][SIPHASH_MAC_SIZE_8] = { + { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, + { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, }, + { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, }, + { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, }, + { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, }, + { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, }, + { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, }, + { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, }, + { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, }, + { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, }, + { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, }, + { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, }, + { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, }, + { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, }, + { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, }, + { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, }, + { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, }, + { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, }, + { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, }, + { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, }, + { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, }, + { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, }, + { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, }, + { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, }, + { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, }, + { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, }, + { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, }, + { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, }, + { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, }, + { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, }, + { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, }, + { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, }, + { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, }, + { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, }, + { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, }, + { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, }, + { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, }, + { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, }, + { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, }, + { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, }, + { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, }, + { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, }, + { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, }, + { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, }, + { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, }, + { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, }, + { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, }, + { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, }, + { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, }, + { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, }, + { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, }, + { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, }, + { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, }, + { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, }, + { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, }, + { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, }, + { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, }, + { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, }, + { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, }, + { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, }, + { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, }, + { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, }, + { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, }, + { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }, +}; +static const unsigned char siphash_r16[64][SIPHASH_MAC_SIZE_16] = { + { 0xa3, 0x81, 0x7f, 0x04, 0xba, 0x25, 0xa8, 0xe6, + 0x6d, 0xf6, 0x72, 0x14, 0xc7, 0x55, 0x02, 0x93, }, + { 0xda, 0x87, 0xc1, 0xd8, 0x6b, 0x99, 0xaf, 0x44, + 0x34, 0x76, 0x59, 0x11, 0x9b, 0x22, 0xfc, 0x45, }, + { 0x81, 0x77, 0x22, 0x8d, 0xa4, 0xa4, 0x5d, 0xc7, + 0xfc, 0xa3, 0x8b, 0xde, 0xf6, 0x0a, 0xff, 0xe4, }, + { 0x9c, 0x70, 0xb6, 0x0c, 0x52, 0x67, 0xa9, 0x4e, + 0x5f, 0x33, 0xb6, 0xb0, 0x29, 0x85, 0xed, 0x51, }, + { 0xf8, 0x81, 0x64, 0xc1, 0x2d, 0x9c, 0x8f, 0xaf, + 0x7d, 0x0f, 0x6e, 0x7c, 0x7b, 0xcd, 0x55, 0x79, }, + { 0x13, 0x68, 0x87, 0x59, 0x80, 0x77, 0x6f, 0x88, + 0x54, 0x52, 0x7a, 0x07, 0x69, 0x0e, 0x96, 0x27, }, + { 0x14, 0xee, 0xca, 0x33, 0x8b, 0x20, 0x86, 0x13, + 0x48, 0x5e, 0xa0, 0x30, 0x8f, 0xd7, 0xa1, 0x5e, }, + { 0xa1, 0xf1, 0xeb, 0xbe, 0xd8, 0xdb, 0xc1, 0x53, + 0xc0, 0xb8, 0x4a, 0xa6, 0x1f, 0xf0, 0x82, 0x39, }, + { 0x3b, 0x62, 0xa9, 0xba, 0x62, 0x58, 0xf5, 0x61, + 0x0f, 0x83, 0xe2, 0x64, 0xf3, 0x14, 0x97, 0xb4, }, + { 0x26, 0x44, 0x99, 0x06, 0x0a, 0xd9, 0xba, 0xab, + 0xc4, 0x7f, 0x8b, 0x02, 0xbb, 0x6d, 0x71, 0xed, }, + { 0x00, 0x11, 0x0d, 0xc3, 0x78, 0x14, 0x69, 0x56, + 0xc9, 0x54, 0x47, 0xd3, 0xf3, 0xd0, 0xfb, 0xba, }, + { 0x01, 0x51, 0xc5, 0x68, 0x38, 0x6b, 0x66, 0x77, + 0xa2, 0xb4, 0xdc, 0x6f, 0x81, 0xe5, 0xdc, 0x18, }, + { 0xd6, 0x26, 0xb2, 0x66, 0x90, 0x5e, 0xf3, 0x58, + 0x82, 0x63, 0x4d, 0xf6, 0x85, 0x32, 0xc1, 0x25, }, + { 0x98, 0x69, 0xe2, 0x47, 0xe9, 0xc0, 0x8b, 0x10, + 0xd0, 0x29, 0x93, 0x4f, 0xc4, 0xb9, 0x52, 0xf7, }, + { 0x31, 0xfc, 0xef, 0xac, 0x66, 0xd7, 0xde, 0x9c, + 0x7e, 0xc7, 0x48, 0x5f, 0xe4, 0x49, 0x49, 0x02, }, + { 0x54, 0x93, 0xe9, 0x99, 0x33, 0xb0, 0xa8, 0x11, + 0x7e, 0x08, 0xec, 0x0f, 0x97, 0xcf, 0xc3, 0xd9, }, + { 0x6e, 0xe2, 0xa4, 0xca, 0x67, 0xb0, 0x54, 0xbb, + 0xfd, 0x33, 0x15, 0xbf, 0x85, 0x23, 0x05, 0x77, }, + { 0x47, 0x3d, 0x06, 0xe8, 0x73, 0x8d, 0xb8, 0x98, + 0x54, 0xc0, 0x66, 0xc4, 0x7a, 0xe4, 0x77, 0x40, }, + { 0xa4, 0x26, 0xe5, 0xe4, 0x23, 0xbf, 0x48, 0x85, + 0x29, 0x4d, 0xa4, 0x81, 0xfe, 0xae, 0xf7, 0x23, }, + { 0x78, 0x01, 0x77, 0x31, 0xcf, 0x65, 0xfa, 0xb0, + 0x74, 0xd5, 0x20, 0x89, 0x52, 0x51, 0x2e, 0xb1, }, + { 0x9e, 0x25, 0xfc, 0x83, 0x3f, 0x22, 0x90, 0x73, + 0x3e, 0x93, 0x44, 0xa5, 0xe8, 0x38, 0x39, 0xeb, }, + { 0x56, 0x8e, 0x49, 0x5a, 0xbe, 0x52, 0x5a, 0x21, + 0x8a, 0x22, 0x14, 0xcd, 0x3e, 0x07, 0x1d, 0x12, }, + { 0x4a, 0x29, 0xb5, 0x45, 0x52, 0xd1, 0x6b, 0x9a, + 0x46, 0x9c, 0x10, 0x52, 0x8e, 0xff, 0x0a, 0xae, }, + { 0xc9, 0xd1, 0x84, 0xdd, 0xd5, 0xa9, 0xf5, 0xe0, + 0xcf, 0x8c, 0xe2, 0x9a, 0x9a, 0xbf, 0x69, 0x1c, }, + { 0x2d, 0xb4, 0x79, 0xae, 0x78, 0xbd, 0x50, 0xd8, + 0x88, 0x2a, 0x8a, 0x17, 0x8a, 0x61, 0x32, 0xad, }, + { 0x8e, 0xce, 0x5f, 0x04, 0x2d, 0x5e, 0x44, 0x7b, + 0x50, 0x51, 0xb9, 0xea, 0xcb, 0x8d, 0x8f, 0x6f, }, + { 0x9c, 0x0b, 0x53, 0xb4, 0xb3, 0xc3, 0x07, 0xe8, + 0x7e, 0xae, 0xe0, 0x86, 0x78, 0x14, 0x1f, 0x66, }, + { 0xab, 0xf2, 0x48, 0xaf, 0x69, 0xa6, 0xea, 0xe4, + 0xbf, 0xd3, 0xeb, 0x2f, 0x12, 0x9e, 0xeb, 0x94, }, + { 0x06, 0x64, 0xda, 0x16, 0x68, 0x57, 0x4b, 0x88, + 0xb9, 0x35, 0xf3, 0x02, 0x73, 0x58, 0xae, 0xf4, }, + { 0xaa, 0x4b, 0x9d, 0xc4, 0xbf, 0x33, 0x7d, 0xe9, + 0x0c, 0xd4, 0xfd, 0x3c, 0x46, 0x7c, 0x6a, 0xb7, }, + { 0xea, 0x5c, 0x7f, 0x47, 0x1f, 0xaf, 0x6b, 0xde, + 0x2b, 0x1a, 0xd7, 0xd4, 0x68, 0x6d, 0x22, 0x87, }, + { 0x29, 0x39, 0xb0, 0x18, 0x32, 0x23, 0xfa, 0xfc, + 0x17, 0x23, 0xde, 0x4f, 0x52, 0xc4, 0x3d, 0x35, }, + { 0x7c, 0x39, 0x56, 0xca, 0x5e, 0xea, 0xfc, 0x3e, + 0x36, 0x3e, 0x9d, 0x55, 0x65, 0x46, 0xeb, 0x68, }, + { 0x77, 0xc6, 0x07, 0x71, 0x46, 0xf0, 0x1c, 0x32, + 0xb6, 0xb6, 0x9d, 0x5f, 0x4e, 0xa9, 0xff, 0xcf, }, + { 0x37, 0xa6, 0x98, 0x6c, 0xb8, 0x84, 0x7e, 0xdf, + 0x09, 0x25, 0xf0, 0xf1, 0x30, 0x9b, 0x54, 0xde, }, + { 0xa7, 0x05, 0xf0, 0xe6, 0x9d, 0xa9, 0xa8, 0xf9, + 0x07, 0x24, 0x1a, 0x2e, 0x92, 0x3c, 0x8c, 0xc8, }, + { 0x3d, 0xc4, 0x7d, 0x1f, 0x29, 0xc4, 0x48, 0x46, + 0x1e, 0x9e, 0x76, 0xed, 0x90, 0x4f, 0x67, 0x11, }, + { 0x0d, 0x62, 0xbf, 0x01, 0xe6, 0xfc, 0x0e, 0x1a, + 0x0d, 0x3c, 0x47, 0x51, 0xc5, 0xd3, 0x69, 0x2b, }, + { 0x8c, 0x03, 0x46, 0x8b, 0xca, 0x7c, 0x66, 0x9e, + 0xe4, 0xfd, 0x5e, 0x08, 0x4b, 0xbe, 0xe7, 0xb5, }, + { 0x52, 0x8a, 0x5b, 0xb9, 0x3b, 0xaf, 0x2c, 0x9c, + 0x44, 0x73, 0xcc, 0xe5, 0xd0, 0xd2, 0x2b, 0xd9, }, + { 0xdf, 0x6a, 0x30, 0x1e, 0x95, 0xc9, 0x5d, 0xad, + 0x97, 0xae, 0x0c, 0xc8, 0xc6, 0x91, 0x3b, 0xd8, }, + { 0x80, 0x11, 0x89, 0x90, 0x2c, 0x85, 0x7f, 0x39, + 0xe7, 0x35, 0x91, 0x28, 0x5e, 0x70, 0xb6, 0xdb, }, + { 0xe6, 0x17, 0x34, 0x6a, 0xc9, 0xc2, 0x31, 0xbb, + 0x36, 0x50, 0xae, 0x34, 0xcc, 0xca, 0x0c, 0x5b, }, + { 0x27, 0xd9, 0x34, 0x37, 0xef, 0xb7, 0x21, 0xaa, + 0x40, 0x18, 0x21, 0xdc, 0xec, 0x5a, 0xdf, 0x89, }, + { 0x89, 0x23, 0x7d, 0x9d, 0xed, 0x9c, 0x5e, 0x78, + 0xd8, 0xb1, 0xc9, 0xb1, 0x66, 0xcc, 0x73, 0x42, }, + { 0x4a, 0x6d, 0x80, 0x91, 0xbf, 0x5e, 0x7d, 0x65, + 0x11, 0x89, 0xfa, 0x94, 0xa2, 0x50, 0xb1, 0x4c, }, + { 0x0e, 0x33, 0xf9, 0x60, 0x55, 0xe7, 0xae, 0x89, + 0x3f, 0xfc, 0x0e, 0x3d, 0xcf, 0x49, 0x29, 0x02, }, + { 0xe6, 0x1c, 0x43, 0x2b, 0x72, 0x0b, 0x19, 0xd1, + 0x8e, 0xc8, 0xd8, 0x4b, 0xdc, 0x63, 0x15, 0x1b, }, + { 0xf7, 0xe5, 0xae, 0xf5, 0x49, 0xf7, 0x82, 0xcf, + 0x37, 0x90, 0x55, 0xa6, 0x08, 0x26, 0x9b, 0x16, }, + { 0x43, 0x8d, 0x03, 0x0f, 0xd0, 0xb7, 0xa5, 0x4f, + 0xa8, 0x37, 0xf2, 0xad, 0x20, 0x1a, 0x64, 0x03, }, + { 0xa5, 0x90, 0xd3, 0xee, 0x4f, 0xbf, 0x04, 0xe3, + 0x24, 0x7e, 0x0d, 0x27, 0xf2, 0x86, 0x42, 0x3f, }, + { 0x5f, 0xe2, 0xc1, 0xa1, 0x72, 0xfe, 0x93, 0xc4, + 0xb1, 0x5c, 0xd3, 0x7c, 0xae, 0xf9, 0xf5, 0x38, }, + { 0x2c, 0x97, 0x32, 0x5c, 0xbd, 0x06, 0xb3, 0x6e, + 0xb2, 0x13, 0x3d, 0xd0, 0x8b, 0x3a, 0x01, 0x7c, }, + { 0x92, 0xc8, 0x14, 0x22, 0x7a, 0x6b, 0xca, 0x94, + 0x9f, 0xf0, 0x65, 0x9f, 0x00, 0x2a, 0xd3, 0x9e, }, + { 0xdc, 0xe8, 0x50, 0x11, 0x0b, 0xd8, 0x32, 0x8c, + 0xfb, 0xd5, 0x08, 0x41, 0xd6, 0x91, 0x1d, 0x87, }, + { 0x67, 0xf1, 0x49, 0x84, 0xc7, 0xda, 0x79, 0x12, + 0x48, 0xe3, 0x2b, 0xb5, 0x92, 0x25, 0x83, 0xda, }, + { 0x19, 0x38, 0xf2, 0xcf, 0x72, 0xd5, 0x4e, 0xe9, + 0x7e, 0x94, 0x16, 0x6f, 0xa9, 0x1d, 0x2a, 0x36, }, + { 0x74, 0x48, 0x1e, 0x96, 0x46, 0xed, 0x49, 0xfe, + 0x0f, 0x62, 0x24, 0x30, 0x16, 0x04, 0x69, 0x8e, }, + { 0x57, 0xfc, 0xa5, 0xde, 0x98, 0xa9, 0xd6, 0xd8, + 0x00, 0x64, 0x38, 0xd0, 0x58, 0x3d, 0x8a, 0x1d, }, + { 0x9f, 0xec, 0xde, 0x1c, 0xef, 0xdc, 0x1c, 0xbe, + 0xd4, 0x76, 0x36, 0x74, 0xd9, 0x57, 0x53, 0x59, }, + { 0xe3, 0x04, 0x0c, 0x00, 0xeb, 0x28, 0xf1, 0x53, + 0x66, 0xca, 0x73, 0xcb, 0xd8, 0x72, 0xe7, 0x40, }, + { 0x76, 0x97, 0x00, 0x9a, 0x6a, 0x83, 0x1d, 0xfe, + 0xcc, 0xa9, 0x1c, 0x59, 0x93, 0x67, 0x0f, 0x7a, }, + { 0x58, 0x53, 0x54, 0x23, 0x21, 0xf5, 0x67, 0xa0, + 0x05, 0xd5, 0x47, 0xa4, 0xf0, 0x47, 0x59, 0xbd, }, + { 0x51, 0x50, 0xd1, 0x77, 0x2f, 0x50, 0x83, 0x4a, + 0x50, 0x3e, 0x06, 0x9a, 0x97, 0x3f, 0xbd, 0x7c, }, +}; +#endif + +WOLFSSL_TEST_SUBROUTINE int siphash_test(void) +{ + int ret = 0; + int i; +#if WOLFSSL_SIPHASH_CROUNDS == 2 && WOLFSSL_SIPHASH_DROUNDS == 4 + unsigned char res[SIPHASH_MAC_SIZE_16]; + SipHash siphash; + + for (i = 0; i < 64; i++) { + ret = wc_InitSipHash(&siphash, siphash_key, SIPHASH_MAC_SIZE_8); + if (ret != 0) + return -12100 - i; + ret = wc_SipHashUpdate(&siphash, siphash_msg, i); + if (ret != 0) + return -12200 - i; + ret = wc_SipHashFinal(&siphash, res, SIPHASH_MAC_SIZE_8); + if (ret != 0) + return -12300 - i; + if (XMEMCMP(res, siphash_r8[i], SIPHASH_MAC_SIZE_8) != 0) + return -12400 - i; + ret = wc_SipHash(siphash_key, siphash_msg, i, res, SIPHASH_MAC_SIZE_8); + if (ret != 0) + return -12500 - i; + if (XMEMCMP(res, siphash_r8[i], SIPHASH_MAC_SIZE_8) != 0) + return -12600 - i; + } + for (i = 0; i < 64; i++) { + ret = wc_InitSipHash(&siphash, siphash_key, SIPHASH_MAC_SIZE_16); + if (ret != 0) + return -12700 - i; + ret = wc_SipHashUpdate(&siphash, siphash_msg, i); + if (ret != 0) + return -12800 - i; + ret = wc_SipHashFinal(&siphash, res, SIPHASH_MAC_SIZE_16); + if (ret != 0) + return -12900 - i; + if (XMEMCMP(res, siphash_r16[i], SIPHASH_MAC_SIZE_16) != 0) + return -13000 - i; + ret = wc_SipHash(siphash_key, siphash_msg, i, res, SIPHASH_MAC_SIZE_16); + if (ret != 0) + return -13100 - i; + if (XMEMCMP(res, siphash_r16[i], SIPHASH_MAC_SIZE_16) != 0) + return -13200 - i; + } +#endif + + /* Testing bad parameters. */ + ret = wc_InitSipHash(NULL, NULL, SIPHASH_MAC_SIZE_8); + if (ret != BAD_FUNC_ARG) + return -13300; + ret = wc_InitSipHash(NULL, siphash_key, SIPHASH_MAC_SIZE_8); + if (ret != BAD_FUNC_ARG) + return -13301; + ret = wc_InitSipHash(&siphash, NULL, SIPHASH_MAC_SIZE_8); + if (ret != BAD_FUNC_ARG) + return -13302; + ret = wc_InitSipHash(&siphash, siphash_key, 7); + if (ret != BAD_FUNC_ARG) + return -13303; + ret = wc_InitSipHash(&siphash, siphash_key, SIPHASH_MAC_SIZE_8); + if (ret != 0) + return -13304; + ret = wc_SipHashUpdate(NULL, NULL, 0); + if (ret != BAD_FUNC_ARG) + return -13305; + ret = wc_SipHashUpdate(&siphash, NULL, 1); + if (ret != BAD_FUNC_ARG) + return -13306; + ret = wc_SipHashFinal(NULL, NULL, SIPHASH_MAC_SIZE_8); + if (ret != BAD_FUNC_ARG) + return -13307; + ret = wc_SipHashFinal(&siphash, NULL, SIPHASH_MAC_SIZE_8); + if (ret != BAD_FUNC_ARG) + return -13308; + ret = wc_SipHashFinal(NULL, res, SIPHASH_MAC_SIZE_8); + if (ret != BAD_FUNC_ARG) + return -13309; + ret = wc_SipHashFinal(&siphash, res, SIPHASH_MAC_SIZE_16); + if (ret != BAD_FUNC_ARG) + return -13310; + + ret = wc_SipHash(NULL, NULL, 0, NULL, SIPHASH_MAC_SIZE_16); + if (ret != BAD_FUNC_ARG) + return -13311; + ret = wc_SipHash(siphash_key, NULL, 0, NULL, SIPHASH_MAC_SIZE_16); + if (ret != BAD_FUNC_ARG) + return -13312; + ret = wc_SipHash(NULL, NULL, 0, res, SIPHASH_MAC_SIZE_16); + if (ret != BAD_FUNC_ARG) + return -13313; + ret = wc_SipHash(siphash_key, NULL, 0, res, 15); + if (ret != BAD_FUNC_ARG) + return -13314; + ret = wc_SipHash(siphash_key, NULL, 1, res, SIPHASH_MAC_SIZE_16); + if (ret != BAD_FUNC_ARG) + return -13315; + + return 0; +} + +#endif /* WOLFSSL_SIPHASH */ + #ifdef HAVE_LIBZ static const byte sample_text[] = diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 7728fc35c..c3015a41f 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -70,6 +70,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/pkcs12.h \ wolfssl/wolfcrypt/wolfmath.h \ wolfssl/wolfcrypt/sha3.h \ + wolfssl/wolfcrypt/siphash.h \ wolfssl/wolfcrypt/cpuid.h \ wolfssl/wolfcrypt/cryptocb.h diff --git a/wolfssl/wolfcrypt/siphash.h b/wolfssl/wolfcrypt/siphash.h new file mode 100644 index 000000000..4f40ca7ad --- /dev/null +++ b/wolfssl/wolfcrypt/siphash.h @@ -0,0 +1,101 @@ +/* siphash.h + * + * Copyright (C) 2006-2021 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifndef WOLF_CRYPT_SIPHASH_H +#define WOLF_CRYPT_SIPHASH_H + +#include + +#if defined(WOLFSSL_SIPHASH) + +/* DESCRIPTION + * + * SipHash is a PseudoRandom Function (PRF) that can be used with small + * messages (less than 256 bytes). + * SipHash can be used for Message Authentication Codes (MACs) and as such must + * be passed a secret key. + * https://eprint.iacr.org/2012/351.pdf + * + * SipHash is commonly used in hash tables. + * Do not use this as a hash not as a general purpose MAC. + * + * WOLFSSL_SIPHASH_CROUNDS and WOLFSSL_SIPHASH_DROUNDS can be defined at build + * time to change the algorithm. + * Default is SipHash-2-4: + * WOLFSSL_SIPHASH_CROUNDS = 2 + * WOLFSSL_SIPHASH_DROUNDS = 4 + */ + +#ifndef WOLFSSL_SIPHASH_CROUNDS +/* Number of rounds to perform in compression operation. */ +#define WOLFSSL_SIPHASH_CROUNDS 2 +#endif /* WOLFSSL_SIPHASH_CROUNDS */ + +#ifndef WOLFSSL_SIPHASH_DROUNDS +/* Number of rounds to perform in final operation. */ +#define WOLFSSL_SIPHASH_DROUNDS 4 +#endif /* WOLFSSL_SIPHASH_DROUNDS */ + +enum { + SIPHASH_KEY_SIZE = 16, /* Key size of SipHash. */ + SIPHASH_BLOCK_SIZE = 8, /* Block size of SipHash. */ + SIPHASH_MAC_SIZE_8 = 8, /* Output an 8 byte MAC. */ + SIPHASH_MAC_SIZE_16 = 16, /* Output a 16 byte MAC. */ +}; + +typedef struct SipHash SipHash; + +struct SipHash { + /* Internal state. */ + word64 v[4]; + /* Cached message data. */ + byte cache[SIPHASH_BLOCK_SIZE]; + /* Number of bytes cached. */ + byte cacheCnt; + /* Number of output bytes. */ + byte outSz; + /* Number of input bytes processed. */ + word32 inCnt; +}; + + +#ifdef __cplusplus + extern "C" { +#endif + +WOLFSSL_API int wc_InitSipHash(SipHash* sipHash, const unsigned char* key, + unsigned char outSz); +WOLFSSL_API int wc_SipHashUpdate(SipHash* sipHash, const unsigned char* in, + word32 inSz); +WOLFSSL_API int wc_SipHashFinal(SipHash* sipHash, unsigned char* out, + unsigned char outSz); +WOLFSSL_API int wc_SipHash(const unsigned char* key, const unsigned char* in, + word32 inSz, unsigned char* out, unsigned char outSz); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* NO_AES && WOLFSSL_SIPHASH */ +#endif /* WOLF_CRYPT_SIPHASH_H */ +