1 /*
2  * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 /* Based on https://131002.net/siphash C reference implementation */
11 /*
12    SipHash reference C implementation
13 
14    Copyright (c) 2012-2016 Jean-Philippe Aumasson
15    Copyright (c) 2012-2014 Daniel J. Bernstein
16 
17    To the extent possible under law, the author(s) have dedicated all copyright
18    and related and neighboring rights to this software to the public domain
19    worldwide. This software is distributed without any warranty.
20 
21    You should have received a copy of the CC0 Public Domain Dedication along
22    with this software. If not, see
23    <http://creativecommons.org/publicdomain/zero/1.0/>.
24  */
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include <openssl/crypto.h>
29 
30 #include "internal/siphash.h"
31 #include "siphash_local.h"
32 
33 /* default: SipHash-2-4 */
34 #define SIPHASH_C_ROUNDS 2
35 #define SIPHASH_D_ROUNDS 4
36 
37 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
38 
39 #define U32TO8_LE(p, v)                                                        \
40     (p)[0] = (uint8_t)((v));                                                   \
41     (p)[1] = (uint8_t)((v) >> 8);                                              \
42     (p)[2] = (uint8_t)((v) >> 16);                                             \
43     (p)[3] = (uint8_t)((v) >> 24);
44 
45 #define U64TO8_LE(p, v)                                                        \
46     U32TO8_LE((p), (uint32_t)((v)));                                           \
47     U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
48 
49 #define U8TO64_LE(p)                                                           \
50     (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                        \
51      ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                 \
52      ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                 \
53      ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
54 
55 #define SIPROUND                                                               \
56     do {                                                                       \
57         v0 += v1;                                                              \
58         v1 = ROTL(v1, 13);                                                     \
59         v1 ^= v0;                                                              \
60         v0 = ROTL(v0, 32);                                                     \
61         v2 += v3;                                                              \
62         v3 = ROTL(v3, 16);                                                     \
63         v3 ^= v2;                                                              \
64         v0 += v3;                                                              \
65         v3 = ROTL(v3, 21);                                                     \
66         v3 ^= v0;                                                              \
67         v2 += v1;                                                              \
68         v1 = ROTL(v1, 17);                                                     \
69         v1 ^= v2;                                                              \
70         v2 = ROTL(v2, 32);                                                     \
71     } while (0)
72 
73 size_t SipHash_ctx_size(void)
74 {
75     return sizeof(SIPHASH);
76 }
77 
78 size_t SipHash_hash_size(SIPHASH *ctx)
79 {
80     return ctx->hash_size;
81 }
82 
83 static size_t siphash_adjust_hash_size(size_t hash_size)
84 {
85     if (hash_size == 0)
86         hash_size = SIPHASH_MAX_DIGEST_SIZE;
87     return hash_size;
88 }
89 
90 int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
91 {
92     hash_size = siphash_adjust_hash_size(hash_size);
93     if (hash_size != SIPHASH_MIN_DIGEST_SIZE
94         && hash_size != SIPHASH_MAX_DIGEST_SIZE)
95         return 0;
96 
97     /*
98      * It's possible that the key was set first.  If the hash size changes,
99      * we need to adjust v1 (see SipHash_Init().
100      */
101 
102     /* Start by adjusting the stored size, to make things easier */
103     ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
104 
105     /* Now, adjust ctx->v1 if the old and the new size differ */
106     if ((size_t)ctx->hash_size != hash_size) {
107         ctx->v1 ^= 0xee;
108         ctx->hash_size = hash_size;
109     }
110     return 1;
111 }
112 
113 /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
114 int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
115 {
116     uint64_t k0 = U8TO64_LE(k);
117     uint64_t k1 = U8TO64_LE(k + 8);
118 
119     /* If the hash size wasn't set, i.e. is zero */
120     ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
121 
122     if (drounds == 0)
123         drounds = SIPHASH_D_ROUNDS;
124     if (crounds == 0)
125         crounds = SIPHASH_C_ROUNDS;
126 
127     ctx->crounds = crounds;
128     ctx->drounds = drounds;
129 
130     ctx->len = 0;
131     ctx->total_inlen = 0;
132 
133     ctx->v0 = 0x736f6d6570736575ULL ^ k0;
134     ctx->v1 = 0x646f72616e646f6dULL ^ k1;
135     ctx->v2 = 0x6c7967656e657261ULL ^ k0;
136     ctx->v3 = 0x7465646279746573ULL ^ k1;
137 
138     if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
139         ctx->v1 ^= 0xee;
140 
141     return 1;
142 }
143 
144 void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
145 {
146     uint64_t m;
147     const uint8_t *end;
148     int left;
149     int i;
150     uint64_t v0 = ctx->v0;
151     uint64_t v1 = ctx->v1;
152     uint64_t v2 = ctx->v2;
153     uint64_t v3 = ctx->v3;
154 
155     ctx->total_inlen += inlen;
156 
157     if (ctx->len) {
158         /* deal with leavings */
159         size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
160 
161         /* not enough to fill leavings */
162         if (inlen < available) {
163             memcpy(&ctx->leavings[ctx->len], in, inlen);
164             ctx->len += inlen;
165             return;
166         }
167 
168         /* copy data into leavings and reduce input */
169         memcpy(&ctx->leavings[ctx->len], in, available);
170         inlen -= available;
171         in += available;
172 
173         /* process leavings */
174         m = U8TO64_LE(ctx->leavings);
175         v3 ^= m;
176         for (i = 0; i < ctx->crounds; ++i)
177             SIPROUND;
178         v0 ^= m;
179     }
180     left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
181     end = in + inlen - left;
182 
183     for (; in != end; in += 8) {
184         m = U8TO64_LE(in);
185         v3 ^= m;
186         for (i = 0; i < ctx->crounds; ++i)
187             SIPROUND;
188         v0 ^= m;
189     }
190 
191     /* save leavings and other ctx */
192     if (left)
193         memcpy(ctx->leavings, end, left);
194     ctx->len = left;
195 
196     ctx->v0 = v0;
197     ctx->v1 = v1;
198     ctx->v2 = v2;
199     ctx->v3 = v3;
200 }
201 
202 int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
203 {
204     /* finalize hash */
205     int i;
206     uint64_t b = ctx->total_inlen << 56;
207     uint64_t v0 = ctx->v0;
208     uint64_t v1 = ctx->v1;
209     uint64_t v2 = ctx->v2;
210     uint64_t v3 = ctx->v3;
211 
212     if (outlen != (size_t)ctx->hash_size)
213         return 0;
214 
215     switch (ctx->len) {
216     case 7:
217         b |= ((uint64_t)ctx->leavings[6]) << 48;
218         /* fall thru */
219     case 6:
220         b |= ((uint64_t)ctx->leavings[5]) << 40;
221         /* fall thru */
222     case 5:
223         b |= ((uint64_t)ctx->leavings[4]) << 32;
224         /* fall thru */
225     case 4:
226         b |= ((uint64_t)ctx->leavings[3]) << 24;
227         /* fall thru */
228     case 3:
229         b |= ((uint64_t)ctx->leavings[2]) << 16;
230         /* fall thru */
231     case 2:
232         b |= ((uint64_t)ctx->leavings[1]) <<  8;
233         /* fall thru */
234     case 1:
235         b |= ((uint64_t)ctx->leavings[0]);
236     case 0:
237         break;
238     }
239 
240     v3 ^= b;
241     for (i = 0; i < ctx->crounds; ++i)
242         SIPROUND;
243     v0 ^= b;
244     if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
245         v2 ^= 0xee;
246     else
247         v2 ^= 0xff;
248     for (i = 0; i < ctx->drounds; ++i)
249         SIPROUND;
250     b = v0 ^ v1 ^ v2  ^ v3;
251     U64TO8_LE(out, b);
252     if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
253         return 1;
254     v1 ^= 0xdd;
255     for (i = 0; i < ctx->drounds; ++i)
256         SIPROUND;
257     b = v0 ^ v1 ^ v2  ^ v3;
258     U64TO8_LE(out + 8, b);
259     return 1;
260 }
261