Coverage Report

Created: 2025-06-13 06:58

/src/openssl32/crypto/siphash/siphash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (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 "crypto/siphash.h"
31
32
160M
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
33
34
#define U32TO8_LE(p, v)                                                        \
35
8.18M
    (p)[0] = (uint8_t)((v));                                                   \
36
8.18M
    (p)[1] = (uint8_t)((v) >> 8);                                              \
37
8.18M
    (p)[2] = (uint8_t)((v) >> 16);                                             \
38
8.18M
    (p)[3] = (uint8_t)((v) >> 24);
39
40
#define U64TO8_LE(p, v)                                                        \
41
4.09M
    U32TO8_LE((p), (uint32_t)((v)));                                           \
42
4.09M
    U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
43
44
#define U8TO64_LE(p)                                                           \
45
9.31M
    (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                        \
46
9.31M
     ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                 \
47
9.31M
     ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                 \
48
9.31M
     ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
49
50
#define SIPROUND                                                               \
51
35.0M
    do {                                                                       \
52
26.8M
        v0 += v1;                                                              \
53
26.8M
        v1 = ROTL(v1, 13);                                                     \
54
26.8M
        v1 ^= v0;                                                              \
55
26.8M
        v0 = ROTL(v0, 32);                                                     \
56
26.8M
        v2 += v3;                                                              \
57
26.8M
        v3 = ROTL(v3, 16);                                                     \
58
26.8M
        v3 ^= v2;                                                              \
59
26.8M
        v0 += v3;                                                              \
60
26.8M
        v3 = ROTL(v3, 21);                                                     \
61
26.8M
        v3 ^= v0;                                                              \
62
26.8M
        v2 += v1;                                                              \
63
26.8M
        v1 = ROTL(v1, 17);                                                     \
64
26.8M
        v1 ^= v2;                                                              \
65
26.8M
        v2 = ROTL(v2, 32);                                                     \
66
26.8M
    } while (0)
67
68
size_t SipHash_ctx_size(void)
69
0
{
70
0
    return sizeof(SIPHASH);
71
0
}
72
73
size_t SipHash_hash_size(SIPHASH *ctx)
74
1.60k
{
75
1.60k
    return ctx->hash_size;
76
1.60k
}
77
78
static size_t siphash_adjust_hash_size(size_t hash_size)
79
12.2M
{
80
12.2M
    if (hash_size == 0)
81
4.09M
        hash_size = SIPHASH_MAX_DIGEST_SIZE;
82
12.2M
    return hash_size;
83
12.2M
}
84
85
int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
86
4.09M
{
87
4.09M
    hash_size = siphash_adjust_hash_size(hash_size);
88
4.09M
    if (hash_size != SIPHASH_MIN_DIGEST_SIZE
89
4.09M
        && hash_size != SIPHASH_MAX_DIGEST_SIZE)
90
7
        return 0;
91
92
    /*
93
     * It's possible that the key was set first.  If the hash size changes,
94
     * we need to adjust v1 (see SipHash_Init().
95
     */
96
97
    /* Start by adjusting the stored size, to make things easier */
98
4.09M
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
99
100
    /* Now, adjust ctx->v1 if the old and the new size differ */
101
4.09M
    if ((size_t)ctx->hash_size != hash_size) {
102
4.09M
        ctx->v1 ^= 0xee;
103
4.09M
        ctx->hash_size = hash_size;
104
4.09M
    }
105
4.09M
    return 1;
106
4.09M
}
107
108
/* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
109
int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
110
4.09M
{
111
4.09M
    uint64_t k0 = U8TO64_LE(k);
112
4.09M
    uint64_t k1 = U8TO64_LE(k + 8);
113
114
    /* If the hash size wasn't set, i.e. is zero */
115
4.09M
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
116
117
4.09M
    if (drounds == 0)
118
4.09M
        drounds = SIPHASH_D_ROUNDS;
119
4.09M
    if (crounds == 0)
120
4.09M
        crounds = SIPHASH_C_ROUNDS;
121
122
4.09M
    ctx->crounds = crounds;
123
4.09M
    ctx->drounds = drounds;
124
125
4.09M
    ctx->len = 0;
126
4.09M
    ctx->total_inlen = 0;
127
128
4.09M
    ctx->v0 = 0x736f6d6570736575ULL ^ k0;
129
4.09M
    ctx->v1 = 0x646f72616e646f6dULL ^ k1;
130
4.09M
    ctx->v2 = 0x6c7967656e657261ULL ^ k0;
131
4.09M
    ctx->v3 = 0x7465646279746573ULL ^ k1;
132
133
4.09M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
134
810
        ctx->v1 ^= 0xee;
135
136
4.09M
    return 1;
137
4.09M
}
138
139
void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
140
4.09M
{
141
4.09M
    uint64_t m;
142
4.09M
    const uint8_t *end;
143
4.09M
    int left;
144
4.09M
    unsigned int i;
145
4.09M
    uint64_t v0 = ctx->v0;
146
4.09M
    uint64_t v1 = ctx->v1;
147
4.09M
    uint64_t v2 = ctx->v2;
148
4.09M
    uint64_t v3 = ctx->v3;
149
150
4.09M
    ctx->total_inlen += inlen;
151
152
4.09M
    if (ctx->len) {
153
        /* deal with leavings */
154
26
        size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
155
156
        /* not enough to fill leavings */
157
26
        if (inlen < available) {
158
0
            memcpy(&ctx->leavings[ctx->len], in, inlen);
159
0
            ctx->len += inlen;
160
0
            return;
161
0
        }
162
163
        /* copy data into leavings and reduce input */
164
26
        memcpy(&ctx->leavings[ctx->len], in, available);
165
26
        inlen -= available;
166
26
        in += available;
167
168
        /* process leavings */
169
26
        m = U8TO64_LE(ctx->leavings);
170
26
        v3 ^= m;
171
78
        for (i = 0; i < ctx->crounds; ++i)
172
52
            SIPROUND;
173
26
        v0 ^= m;
174
26
    }
175
4.09M
    left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
176
4.09M
    end = in + inlen - left;
177
178
5.21M
    for (; in != end; in += 8) {
179
1.12M
        m = U8TO64_LE(in);
180
1.12M
        v3 ^= m;
181
3.37M
        for (i = 0; i < ctx->crounds; ++i)
182
2.24M
            SIPROUND;
183
1.12M
        v0 ^= m;
184
1.12M
    }
185
186
    /* save leavings and other ctx */
187
4.09M
    if (left)
188
2.02M
        memcpy(ctx->leavings, end, left);
189
4.09M
    ctx->len = left;
190
191
4.09M
    ctx->v0 = v0;
192
4.09M
    ctx->v1 = v1;
193
4.09M
    ctx->v2 = v2;
194
4.09M
    ctx->v3 = v3;
195
4.09M
}
196
197
int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
198
4.09M
{
199
    /* finalize hash */
200
4.09M
    unsigned int i;
201
4.09M
    uint64_t b = ctx->total_inlen << 56;
202
4.09M
    uint64_t v0 = ctx->v0;
203
4.09M
    uint64_t v1 = ctx->v1;
204
4.09M
    uint64_t v2 = ctx->v2;
205
4.09M
    uint64_t v3 = ctx->v3;
206
207
4.09M
    if (ctx->crounds == 0 || outlen == 0 || outlen != (size_t)ctx->hash_size)
208
0
        return 0;
209
210
4.09M
    switch (ctx->len) {
211
29.9k
    case 7:
212
29.9k
        b |= ((uint64_t)ctx->leavings[6]) << 48;
213
        /* fall through */
214
86.7k
    case 6:
215
86.7k
        b |= ((uint64_t)ctx->leavings[5]) << 40;
216
        /* fall through */
217
174k
    case 5:
218
174k
        b |= ((uint64_t)ctx->leavings[4]) << 32;
219
        /* fall through */
220
259k
    case 4:
221
259k
        b |= ((uint64_t)ctx->leavings[3]) << 24;
222
        /* fall through */
223
1.42M
    case 3:
224
1.42M
        b |= ((uint64_t)ctx->leavings[2]) << 16;
225
        /* fall through */
226
1.63M
    case 2:
227
1.63M
        b |= ((uint64_t)ctx->leavings[1]) <<  8;
228
        /* fall through */
229
2.02M
    case 1:
230
2.02M
        b |= ((uint64_t)ctx->leavings[0]);
231
4.09M
    case 0:
232
4.09M
        break;
233
4.09M
    }
234
235
4.09M
    v3 ^= b;
236
12.2M
    for (i = 0; i < ctx->crounds; ++i)
237
8.18M
        SIPROUND;
238
4.09M
    v0 ^= b;
239
4.09M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
240
802
        v2 ^= 0xee;
241
4.09M
    else
242
4.09M
        v2 ^= 0xff;
243
20.4M
    for (i = 0; i < ctx->drounds; ++i)
244
16.3M
        SIPROUND;
245
4.09M
    b = v0 ^ v1 ^ v2  ^ v3;
246
4.09M
    U64TO8_LE(out, b);
247
4.09M
    if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
248
4.09M
        return 1;
249
802
    v1 ^= 0xdd;
250
4.01k
    for (i = 0; i < ctx->drounds; ++i)
251
3.20k
        SIPROUND;
252
802
    b = v0 ^ v1 ^ v2  ^ v3;
253
802
    U64TO8_LE(out + 8, b);
254
802
    return 1;
255
4.09M
}