1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * SipHash (C reference implementation, APR-ized), originating from:
19 *      https://131002.net/siphash/siphash24.c.
20 */
21
22#include "apr_siphash.h"
23
24#define ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
25
26#define U8TO64_LE(p) \
27    (((apr_uint64_t)((p)[0])      ) | \
28     ((apr_uint64_t)((p)[1]) <<  8) | \
29     ((apr_uint64_t)((p)[2]) << 16) | \
30     ((apr_uint64_t)((p)[3]) << 24) | \
31     ((apr_uint64_t)((p)[4]) << 32) | \
32     ((apr_uint64_t)((p)[5]) << 40) | \
33     ((apr_uint64_t)((p)[6]) << 48) | \
34     ((apr_uint64_t)((p)[7]) << 56))
35
36#define U64TO8_LE(p, v) \
37do { \
38    (p)[0] = (unsigned char)((v)      ); \
39    (p)[1] = (unsigned char)((v) >>  8); \
40    (p)[2] = (unsigned char)((v) >> 16); \
41    (p)[3] = (unsigned char)((v) >> 24); \
42    (p)[4] = (unsigned char)((v) >> 32); \
43    (p)[5] = (unsigned char)((v) >> 40); \
44    (p)[6] = (unsigned char)((v) >> 48); \
45    (p)[7] = (unsigned char)((v) >> 56); \
46} while (0)
47
48#define SIPROUND() \
49do { \
50    v0 += v1; v1=ROTL64(v1,13); v1 ^= v0; v0=ROTL64(v0,32); \
51    v2 += v3; v3=ROTL64(v3,16); v3 ^= v2; \
52    v0 += v3; v3=ROTL64(v3,21); v3 ^= v0; \
53    v2 += v1; v1=ROTL64(v1,17); v1 ^= v2; v2=ROTL64(v2,32); \
54} while(0)
55
56#define SIPHASH(r, s, n, k) \
57do { \
58    const unsigned char *ptr, *end; \
59    apr_uint64_t v0, v1, v2, v3, m; \
60    apr_uint64_t k0, k1; \
61    unsigned int rem; \
62    \
63    k0 = U8TO64_LE(k + 0); \
64    k1 = U8TO64_LE(k + 8); \
65    v3 = k1 ^ (apr_uint64_t)0x7465646279746573ULL; \
66    v2 = k0 ^ (apr_uint64_t)0x6c7967656e657261ULL; \
67    v1 = k1 ^ (apr_uint64_t)0x646f72616e646f6dULL; \
68    v0 = k0 ^ (apr_uint64_t)0x736f6d6570736575ULL; \
69    \
70    rem = (unsigned int)(n & 0x7); \
71    for (ptr = s, end = ptr + n - rem; ptr < end; ptr += 8) { \
72        m = U8TO64_LE(ptr); \
73        v3 ^= m; \
74        cROUNDS \
75        v0 ^= m; \
76    } \
77    m = (apr_uint64_t)(n & 0xff) << 56; \
78    switch (rem) { \
79        case 7: m |= (apr_uint64_t)ptr[6] << 48; \
80        case 6: m |= (apr_uint64_t)ptr[5] << 40; \
81        case 5: m |= (apr_uint64_t)ptr[4] << 32; \
82        case 4: m |= (apr_uint64_t)ptr[3] << 24; \
83        case 3: m |= (apr_uint64_t)ptr[2] << 16; \
84        case 2: m |= (apr_uint64_t)ptr[1] << 8; \
85        case 1: m |= (apr_uint64_t)ptr[0]; \
86        case 0: break; \
87    } \
88    v3 ^= m; \
89    cROUNDS \
90    v0 ^= m; \
91    \
92    v2 ^= 0xff; \
93    dROUNDS \
94    \
95    r = v0 ^ v1 ^ v2 ^ v3; \
96} while (0)
97
98APU_DECLARE(apr_uint64_t) apr_siphash(const void *src, apr_size_t len,
99                              const unsigned char key[APR_SIPHASH_KSIZE],
100                                      unsigned int c, unsigned int d)
101{
102    apr_uint64_t h;
103    unsigned int i;
104
105#undef  cROUNDS
106#define cROUNDS \
107        for (i = 0; i < c; ++i) { \
108            SIPROUND(); \
109        }
110
111#undef  dROUNDS
112#define dROUNDS \
113        for (i = 0; i < d; ++i) { \
114            SIPROUND(); \
115        }
116
117    SIPHASH(h, src, len, key);
118    return h;
119}
120
121APU_DECLARE(void) apr_siphash_auth(unsigned char out[APR_SIPHASH_DSIZE],
122                                   const void *src, apr_size_t len,
123                             const unsigned char key[APR_SIPHASH_KSIZE],
124                                   unsigned int c, unsigned int d)
125{
126    apr_uint64_t h;
127    h = apr_siphash(src, len, key, c, d);
128    U64TO8_LE(out, h);
129}
130
131APU_DECLARE(apr_uint64_t) apr_siphash24(const void *src, apr_size_t len,
132                               const unsigned char key[APR_SIPHASH_KSIZE])
133{
134    apr_uint64_t h;
135
136#undef  cROUNDS
137#define cROUNDS \
138        SIPROUND(); \
139        SIPROUND();
140
141#undef  dROUNDS
142#define dROUNDS \
143        SIPROUND(); \
144        SIPROUND(); \
145        SIPROUND(); \
146        SIPROUND();
147
148    SIPHASH(h, src, len, key);
149    return h;
150}
151
152APU_DECLARE(void) apr_siphash24_auth(unsigned char out[APR_SIPHASH_DSIZE],
153                                     const void *src, apr_size_t len,
154                               const unsigned char key[APR_SIPHASH_KSIZE])
155{
156    apr_uint64_t h;
157    h = apr_siphash24(src, len, key);
158    U64TO8_LE(out, h);
159}
160
161APU_DECLARE(apr_uint64_t) apr_siphash48(const void *src, apr_size_t len,
162                               const unsigned char key[APR_SIPHASH_KSIZE])
163{
164    apr_uint64_t h;
165
166#undef  cROUNDS
167#define cROUNDS \
168        SIPROUND(); \
169        SIPROUND(); \
170        SIPROUND(); \
171        SIPROUND();
172
173#undef  dROUNDS
174#define dROUNDS \
175        SIPROUND(); \
176        SIPROUND(); \
177        SIPROUND(); \
178        SIPROUND(); \
179        SIPROUND(); \
180        SIPROUND(); \
181        SIPROUND(); \
182        SIPROUND();
183
184    SIPHASH(h, src, len, key);
185    return h;
186}
187
188APU_DECLARE(void) apr_siphash48_auth(unsigned char out[APR_SIPHASH_DSIZE],
189                                     const void *src, apr_size_t len,
190                               const unsigned char key[APR_SIPHASH_KSIZE])
191{
192    apr_uint64_t h;
193    h = apr_siphash48(src, len, key);
194    U64TO8_LE(out, h);
195}
196
197