Line data Source code
1 : /* $OpenBSD: siphash.c,v 1.5 2018/01/05 19:05:09 mikeb Exp $ */
2 :
3 : /*-
4 : * Copyright (c) 2013 Andre Oppermann <andre@FreeBSD.org>
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : * 3. The name of the author may not be used to endorse or promote
16 : * products derived from this software without specific prior written
17 : * permission.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 : * SUCH DAMAGE.
30 : */
31 :
32 : /*
33 : * SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d
34 : * are the number of compression rounds and the number of finalization rounds.
35 : * A compression round is identical to a finalization round and this round
36 : * function is called SipRound. Given a 128-bit key k and a (possibly empty)
37 : * byte string m, SipHash-c-d returns a 64-bit value SipHash-c-d(k; m).
38 : *
39 : * Implemented from the paper "SipHash: a fast short-input PRF", 2012.09.18,
40 : * by Jean-Philippe Aumasson and Daniel J. Bernstein,
41 : * Permanent Document ID b9a943a805fbfc6fde808af9fc0ecdfa
42 : * https://131002.net/siphash/siphash.pdf
43 : * https://131002.net/siphash/
44 : */
45 :
46 : #include <sys/param.h>
47 : #include <sys/systm.h>
48 :
49 : #include <crypto/siphash.h>
50 :
51 : static void SipHash_CRounds(SIPHASH_CTX *, int);
52 : static void SipHash_Rounds(SIPHASH_CTX *, int);
53 :
54 : void
55 0 : SipHash_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key)
56 : {
57 : uint64_t k0, k1;
58 :
59 0 : k0 = lemtoh64(&key->k0);
60 0 : k1 = lemtoh64(&key->k1);
61 :
62 0 : ctx->v[0] = 0x736f6d6570736575ULL ^ k0;
63 0 : ctx->v[1] = 0x646f72616e646f6dULL ^ k1;
64 0 : ctx->v[2] = 0x6c7967656e657261ULL ^ k0;
65 0 : ctx->v[3] = 0x7465646279746573ULL ^ k1;
66 :
67 0 : memset(ctx->buf, 0, sizeof(ctx->buf));
68 0 : ctx->bytes = 0;
69 0 : }
70 :
71 : void
72 0 : SipHash_Update(SIPHASH_CTX *ctx, int rc, int rf, const void *src, size_t len)
73 : {
74 : const uint8_t *ptr = src;
75 : size_t left, used;
76 :
77 0 : if (len == 0)
78 0 : return;
79 :
80 0 : used = ctx->bytes % sizeof(ctx->buf);
81 0 : ctx->bytes += len;
82 :
83 0 : if (used > 0) {
84 0 : left = sizeof(ctx->buf) - used;
85 :
86 0 : if (len >= left) {
87 0 : memcpy(&ctx->buf[used], ptr, left);
88 0 : SipHash_CRounds(ctx, rc);
89 0 : len -= left;
90 0 : ptr += left;
91 : } else {
92 0 : memcpy(&ctx->buf[used], ptr, len);
93 0 : return;
94 : }
95 0 : }
96 :
97 0 : while (len >= sizeof(ctx->buf)) {
98 0 : memcpy(ctx->buf, ptr, sizeof(ctx->buf));
99 0 : SipHash_CRounds(ctx, rc);
100 0 : len -= sizeof(ctx->buf);
101 0 : ptr += sizeof(ctx->buf);
102 : }
103 :
104 0 : if (len > 0)
105 0 : memcpy(ctx->buf, ptr, len);
106 0 : }
107 :
108 : void
109 0 : SipHash_Final(void *dst, SIPHASH_CTX *ctx, int rc, int rf)
110 : {
111 : uint64_t r;
112 :
113 0 : htolem64(&r, SipHash_End(ctx, rc, rf));
114 0 : memcpy(dst, &r, sizeof r);
115 0 : }
116 :
117 : uint64_t
118 0 : SipHash_End(SIPHASH_CTX *ctx, int rc, int rf)
119 : {
120 : uint64_t r;
121 : size_t left, used;
122 :
123 0 : used = ctx->bytes % sizeof(ctx->buf);
124 0 : left = sizeof(ctx->buf) - used;
125 0 : memset(&ctx->buf[used], 0, left - 1);
126 0 : ctx->buf[7] = ctx->bytes;
127 :
128 0 : SipHash_CRounds(ctx, rc);
129 0 : ctx->v[2] ^= 0xff;
130 0 : SipHash_Rounds(ctx, rf);
131 :
132 0 : r = (ctx->v[0] ^ ctx->v[1]) ^ (ctx->v[2] ^ ctx->v[3]);
133 0 : explicit_bzero(ctx, sizeof(*ctx));
134 0 : return (r);
135 : }
136 :
137 : uint64_t
138 0 : SipHash(const SIPHASH_KEY *key, int rc, int rf, const void *src, size_t len)
139 : {
140 0 : SIPHASH_CTX ctx;
141 :
142 0 : SipHash_Init(&ctx, key);
143 0 : SipHash_Update(&ctx, rc, rf, src, len);
144 0 : return (SipHash_End(&ctx, rc, rf));
145 0 : }
146 :
147 : #define SIP_ROTL(x, b) ((x) << (b)) | ( (x) >> (64 - (b)))
148 :
149 : static void
150 0 : SipHash_Rounds(SIPHASH_CTX *ctx, int rounds)
151 : {
152 0 : while (rounds--) {
153 0 : ctx->v[0] += ctx->v[1];
154 0 : ctx->v[2] += ctx->v[3];
155 0 : ctx->v[1] = SIP_ROTL(ctx->v[1], 13);
156 0 : ctx->v[3] = SIP_ROTL(ctx->v[3], 16);
157 :
158 0 : ctx->v[1] ^= ctx->v[0];
159 0 : ctx->v[3] ^= ctx->v[2];
160 0 : ctx->v[0] = SIP_ROTL(ctx->v[0], 32);
161 :
162 0 : ctx->v[2] += ctx->v[1];
163 0 : ctx->v[0] += ctx->v[3];
164 0 : ctx->v[1] = SIP_ROTL(ctx->v[1], 17);
165 0 : ctx->v[3] = SIP_ROTL(ctx->v[3], 21);
166 :
167 0 : ctx->v[1] ^= ctx->v[2];
168 0 : ctx->v[3] ^= ctx->v[0];
169 0 : ctx->v[2] = SIP_ROTL(ctx->v[2], 32);
170 : }
171 0 : }
172 :
173 : static void
174 0 : SipHash_CRounds(SIPHASH_CTX *ctx, int rounds)
175 : {
176 0 : uint64_t m = lemtoh64((uint64_t *)ctx->buf);
177 :
178 0 : ctx->v[3] ^= m;
179 0 : SipHash_Rounds(ctx, rounds);
180 0 : ctx->v[0] ^= m;
181 0 : }
|