From 10f5d66e90b75e4992c8530000f51f100eb4b132 Mon Sep 17 00:00:00 2001 From: tedu <> Date: Mon, 8 Dec 2014 20:37:11 +0000 Subject: [PATCH] add siphash from the kernel to libc --- src/lib/libc/hash/Makefile.inc | 9 +- src/lib/libc/hash/SipHash24.3 | 109 ++++++++++++++++++++ src/lib/libc/hash/siphash.c | 183 +++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+), 3 deletions(-) create mode 100644 src/lib/libc/hash/SipHash24.3 create mode 100644 src/lib/libc/hash/siphash.c diff --git a/src/lib/libc/hash/Makefile.inc b/src/lib/libc/hash/Makefile.inc index bc6d0060..b3522b26 100644 --- a/src/lib/libc/hash/Makefile.inc +++ b/src/lib/libc/hash/Makefile.inc @@ -1,11 +1,11 @@ -# $OpenBSD: Makefile.inc,v 1.20 2014/03/23 23:27:22 naddy Exp $ +# $OpenBSD: Makefile.inc,v 1.21 2014/12/08 20:37:11 tedu Exp $ # hash functions .PATH: ${LIBCSRCDIR}/hash HELPER= md5hl.c rmd160hl.c sha1hl.c sha224hl.c sha256hl.c sha384hl.c sha512hl.c -SRCS+= md5.c rmd160.c sha1.c sha2.c ${HELPER} -MAN+= md5.3 rmd160.3 sha1.3 sha2.3 +SRCS+= md5.c rmd160.c sha1.c sha2.c ${HELPER} siphash.c +MAN+= md5.3 rmd160.3 sha1.3 sha2.3 SipHash.3 MLINKS+=md5.3 MD5Transform.3 md5.3 MD5Init.3 md5.3 MD5Final.3 MLINKS+=md5.3 MD5Update.3 md5.3 MD5End.3 md5.3 MD5File.3 @@ -28,6 +28,9 @@ MLINKS+=sha2.3 SHA384File.3 sha2.3 SHA384FileChunk.3 sha2.3 SHA384Data.3 MLINKS+=sha2.3 SHA512Init.3 sha2.3 SHA512Update.3 sha2.3 SHA512Pad.3 MLINKS+=sha2.3 SHA512Final.3 sha2.3 SHA512Transform.3 sha2.3 SHA512End.3 MLINKS+=sha2.3 SHA512File.3 sha2.3 SHA512FileChunk.3 sha2.3 SHA512Data.3 +MLINKS+=SipHash24.3 SipHash24_Init.3 SipHash24.3 SipHash24_Update.3 +MLINKS+=SipHash24.3 SipHash24_End.3 SipHash24.3 SipHash24_Final.3 + CLEANFILES+= ${HELPER} md5hl.c: helper.c diff --git a/src/lib/libc/hash/SipHash24.3 b/src/lib/libc/hash/SipHash24.3 new file mode 100644 index 00000000..3a2398a0 --- /dev/null +++ b/src/lib/libc/hash/SipHash24.3 @@ -0,0 +1,109 @@ +.\" $OpenBSD: SipHash24.3,v 1.1 2014/12/08 20:37:11 tedu Exp $ +.\" +.\" Copyright (c) 2014 David Gwynne +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: December 8 2014 $ +.Dt SIPHASH24 9 +.Os +.Sh NAME +.Nm SipHash24_Init , +.Nm SipHash24_Update , +.Nm SipHash24_End , +.Nm SipHash24_Final , +.Nm SipHash24 +.Nd calculate SipHash24 hashes +.Sh SYNOPSIS +.In siphash.h +.Ft void +.Fn "SipHash24_Init" "SIPHASH_CTX *ctx" "const SIPHASH_KEY *key" +.Ft void +.Fn "SipHash24_Update" "SIPHASH_CTX *ctx" "const void *data" "size_t len" +.Ft u_int64_t +.Fn "SipHash24_End" "SIPHASH_CTX *ctx" +.Ft void +.Fn "SipHash24_Final" "void *digest" "SIPHASH_CTX *ctx" +.Ft u_int64_t +.Fn "SipHash24" "const SIPHASH_KEY *key" "const void *data" "size_t len" +.Sh DESCRIPTION +The SipHash algorithm is a keyed hash algorithm optimised for short +inputs which produces a 64-bit digest of data. +The SipHash24 functions implement the algorithm with 2 compression +rounds and 4 finalisation rounds. +.Pp +.Fn SipHash24_Init +initialises a +.Vt SIPHASH_CTX +context +.Fa ctx +with the secret +.Fa key . +.Pp +.Fn SipHash24_Update +adds +.Fa data +of length +.Fa len +to the context +.Fa ctx . +.Pp +.Fn SipHash24_End +is called after all data has been added to +.Fa ctx +via +.Fn SipHash24_Update +and returns a message digest in the host's native endian. +.Pp +.Fn SipHash24_Final +is called after all data has been added to +.Fa ctx +via +.Fn SipHash24_Update +and stores the message digest at the address specified by the +.Fa digest +parameter. +The buffer at +.Fa digest +must be +.Dv SIPHASH_DIGEST_LENGTH +bytes long. +.Pp +.Fn SipHash24 +calculates the digest of +.Fa data +of length +.Fa len +with the secret +.Fa key . +.Pp +If SipHash is being used to mitigate against hash-table flooding +attacks, it is recommended that the +.Vt SIPHASH_KEY +key be generated with +.Xr arc4random_buf 9 . +.Sh CONTEXT +.Fn SipHash24_Init , +.Fn SipHash24_Update , +.Fn SipHash24_End , +.Fn SipHash24_Final +and +.Fn SipHash24 +can be called during autoconf, from process context, or from interrupt context. +.Sh RETURN VALUES +.Fn SipHash24_End +and +.Fn SipHash24 +return the 64-bit message digest in the host's native endian representation. +.Sh SEE ALSO +.Xr arc4random_buf 9 diff --git a/src/lib/libc/hash/siphash.c b/src/lib/libc/hash/siphash.c new file mode 100644 index 00000000..81b4b818 --- /dev/null +++ b/src/lib/libc/hash/siphash.c @@ -0,0 +1,183 @@ +/* $OpenBSD: siphash.c,v 1.1 2014/12/08 20:37:11 tedu Exp $ */ + +/*- + * Copyright (c) 2013 Andre Oppermann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d + * are the number of compression rounds and the number of finalization rounds. + * A compression round is identical to a finalization round and this round + * function is called SipRound. Given a 128-bit key k and a (possibly empty) + * byte string m, SipHash-c-d returns a 64-bit value SipHash-c-d(k; m). + * + * Implemented from the paper "SipHash: a fast short-input PRF", 2012.09.18, + * by Jean-Philippe Aumasson and Daniel J. Bernstein, + * Permanent Document ID b9a943a805fbfc6fde808af9fc0ecdfa + * https://131002.net/siphash/siphash.pdf + * https://131002.net/siphash/ + */ + +#include +#include + +#include +#include + +void SipHash_CRounds(SIPHASH_CTX *, int); +void SipHash_Rounds(SIPHASH_CTX *, int); + +void +SipHash_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key) +{ + uint64_t k0, k1; + + k0 = le64toh(key->k0); + k1 = le64toh(key->k1); + + ctx->v[0] = 0x736f6d6570736575ULL ^ k0; + ctx->v[1] = 0x646f72616e646f6dULL ^ k1; + ctx->v[2] = 0x6c7967656e657261ULL ^ k0; + ctx->v[3] = 0x7465646279746573ULL ^ k1; + + memset(ctx->buf, 0, sizeof(ctx->buf)); + ctx->bytes = 0; +} + +void +SipHash_Update(SIPHASH_CTX *ctx, int rc, int rf, const void *src, size_t len) +{ + const u_int8_t *ptr = src; + size_t free, used; + + if (len == 0) + return; + + used = ctx->bytes % sizeof(ctx->buf); + ctx->bytes += len; + + if (used > 0) { + free = sizeof(ctx->buf) - used; + + if (len >= free) { + memcpy(&ctx->buf[used], ptr, free); + SipHash_CRounds(ctx, rc); + len -= free; + ptr += free; + } else { + memcpy(&ctx->buf[used], ptr, len); + return; + } + } + + while (len >= sizeof(ctx->buf)) { + memcpy(ctx->buf, ptr, sizeof(ctx->buf)); + SipHash_CRounds(ctx, rc); + len -= sizeof(ctx->buf); + ptr += sizeof(ctx->buf); + } + + if (len > 0) + memcpy(&ctx->buf[used], ptr, len); +} + +void +SipHash_Final(void *dst, SIPHASH_CTX *ctx, int rc, int rf) +{ + u_int64_t r; + + r = SipHash_End(ctx, rc, rf); + + *(u_int64_t *)dst = htole64(r); +} + +u_int64_t +SipHash_End(SIPHASH_CTX *ctx, int rc, int rf) +{ + u_int64_t r; + size_t free, used; + + used = ctx->bytes % sizeof(ctx->buf); + free = sizeof(ctx->buf) - used; + memset(&ctx->buf[used], 0, free - 1); + ctx->buf[7] = ctx->bytes; + + SipHash_CRounds(ctx, rc); + ctx->v[2] ^= 0xff; + SipHash_Rounds(ctx, rf); + + r = (ctx->v[0] ^ ctx->v[1]) ^ (ctx->v[2] ^ ctx->v[3]); + explicit_bzero(ctx, sizeof(*ctx)); + return (r); +} + +u_int64_t +SipHash(const SIPHASH_KEY *key, int rc, int rf, const void *src, size_t len) +{ + SIPHASH_CTX ctx; + + SipHash_Init(&ctx, key); + SipHash_Update(&ctx, rc, rf, src, len); + return (SipHash_End(&ctx, rc, rf)); +} + +#define SIP_ROTL(x, b) ((x) << (b)) | ( (x) >> (64 - (b))) + +void +SipHash_Rounds(SIPHASH_CTX *ctx, int rounds) +{ + while (rounds--) { + ctx->v[0] += ctx->v[1]; + ctx->v[2] += ctx->v[3]; + ctx->v[1] = SIP_ROTL(ctx->v[1], 13); + ctx->v[3] = SIP_ROTL(ctx->v[3], 16); + + ctx->v[1] ^= ctx->v[0]; + ctx->v[3] ^= ctx->v[2]; + ctx->v[0] = SIP_ROTL(ctx->v[0], 32); + + ctx->v[2] += ctx->v[1]; + ctx->v[0] += ctx->v[3]; + ctx->v[1] = SIP_ROTL(ctx->v[1], 17); + ctx->v[3] = SIP_ROTL(ctx->v[3], 21); + + ctx->v[1] ^= ctx->v[2]; + ctx->v[3] ^= ctx->v[0]; + ctx->v[2] = SIP_ROTL(ctx->v[2], 32); + } +} + +void +SipHash_CRounds(SIPHASH_CTX *ctx, int rounds) +{ + u_int64_t m = letoh64(*(u_int64_t *)ctx->buf); + + ctx->v[3] ^= m; + SipHash_Rounds(ctx, rounds); + ctx->v[0] ^= m; +}