Coverage Report

Created: 2025-06-13 06:55

/src/openssl/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
41.9M
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
33
34
#define U32TO8_LE(p, v)                                                        \
35
2.33M
    (p)[0] = (uint8_t)((v));                                                   \
36
2.33M
    (p)[1] = (uint8_t)((v) >> 8);                                              \
37
2.33M
    (p)[2] = (uint8_t)((v) >> 16);                                             \
38
2.33M
    (p)[3] = (uint8_t)((v) >> 24);
39
40
#define U64TO8_LE(p, v)                                                        \
41
1.16M
    U32TO8_LE((p), (uint32_t)((v)));                                           \
42
1.16M
    U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
43
44
#define U8TO64_LE(p)                                                           \
45
2.33M
    (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                        \
46
2.33M
     ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                 \
47
2.33M
     ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                 \
48
2.33M
     ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
49
50
#define SIPROUND                                                               \
51
9.32M
    do {                                                                       \
52
6.99M
        v0 += v1;                                                              \
53
6.99M
        v1 = ROTL(v1, 13);                                                     \
54
6.99M
        v1 ^= v0;                                                              \
55
6.99M
        v0 = ROTL(v0, 32);                                                     \
56
6.99M
        v2 += v3;                                                              \
57
6.99M
        v3 = ROTL(v3, 16);                                                     \
58
6.99M
        v3 ^= v2;                                                              \
59
6.99M
        v0 += v3;                                                              \
60
6.99M
        v3 = ROTL(v3, 21);                                                     \
61
6.99M
        v3 ^= v0;                                                              \
62
6.99M
        v2 += v1;                                                              \
63
6.99M
        v1 = ROTL(v1, 17);                                                     \
64
6.99M
        v1 ^= v2;                                                              \
65
6.99M
        v2 = ROTL(v2, 32);                                                     \
66
6.99M
    } 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
0
{
75
0
    return ctx->hash_size;
76
0
}
77
78
static size_t siphash_adjust_hash_size(size_t hash_size)
79
3.49M
{
80
3.49M
    if (hash_size == 0)
81
1.16M
        hash_size = SIPHASH_MAX_DIGEST_SIZE;
82
3.49M
    return hash_size;
83
3.49M
}
84
85
int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
86
1.16M
{
87
1.16M
    hash_size = siphash_adjust_hash_size(hash_size);
88
1.16M
    if (hash_size != SIPHASH_MIN_DIGEST_SIZE
89
1.16M
        && hash_size != SIPHASH_MAX_DIGEST_SIZE)
90
0
        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
1.16M
    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
1.16M
    if ((size_t)ctx->hash_size != hash_size) {
102
1.16M
        ctx->v1 ^= 0xee;
103
1.16M
        ctx->hash_size = hash_size;
104
1.16M
    }
105
1.16M
    return 1;
106
1.16M
}
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
1.16M
{
111
1.16M
    uint64_t k0 = U8TO64_LE(k);
112
1.16M
    uint64_t k1 = U8TO64_LE(k + 8);
113
114
    /* If the hash size wasn't set, i.e. is zero */
115
1.16M
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
116
117
1.16M
    if (drounds == 0)
118
1.16M
        drounds = SIPHASH_D_ROUNDS;
119
1.16M
    if (crounds == 0)
120
1.16M
        crounds = SIPHASH_C_ROUNDS;
121
122
1.16M
    ctx->crounds = crounds;
123
1.16M
    ctx->drounds = drounds;
124
125
1.16M
    ctx->len = 0;
126
1.16M
    ctx->total_inlen = 0;
127
128
1.16M
    ctx->v0 = 0x736f6d6570736575ULL ^ k0;
129
1.16M
    ctx->v1 = 0x646f72616e646f6dULL ^ k1;
130
1.16M
    ctx->v2 = 0x6c7967656e657261ULL ^ k0;
131
1.16M
    ctx->v3 = 0x7465646279746573ULL ^ k1;
132
133
1.16M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
134
0
        ctx->v1 ^= 0xee;
135
136
1.16M
    return 1;
137
1.16M
}
138
139
void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
140
1.16M
{
141
1.16M
    uint64_t m;
142
1.16M
    const uint8_t *end;
143
1.16M
    int left;
144
1.16M
    unsigned int i;
145
1.16M
    uint64_t v0 = ctx->v0;
146
1.16M
    uint64_t v1 = ctx->v1;
147
1.16M
    uint64_t v2 = ctx->v2;
148
1.16M
    uint64_t v3 = ctx->v3;
149
150
1.16M
    ctx->total_inlen += inlen;
151
152
1.16M
    if (ctx->len) {
153
        /* deal with leavings */
154
0
        size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
155
156
        /* not enough to fill leavings */
157
0
        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
0
        memcpy(&ctx->leavings[ctx->len], in, available);
165
0
        inlen -= available;
166
0
        in += available;
167
168
        /* process leavings */
169
0
        m = U8TO64_LE(ctx->leavings);
170
0
        v3 ^= m;
171
0
        for (i = 0; i < ctx->crounds; ++i)
172
0
            SIPROUND;
173
0
        v0 ^= m;
174
0
    }
175
1.16M
    left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
176
1.16M
    end = in + inlen - left;
177
178
1.16M
    for (; in != end; in += 8) {
179
2.46k
        m = U8TO64_LE(in);
180
2.46k
        v3 ^= m;
181
7.38k
        for (i = 0; i < ctx->crounds; ++i)
182
4.92k
            SIPROUND;
183
2.46k
        v0 ^= m;
184
2.46k
    }
185
186
    /* save leavings and other ctx */
187
1.16M
    if (left)
188
3.39k
        memcpy(ctx->leavings, end, left);
189
1.16M
    ctx->len = left;
190
191
1.16M
    ctx->v0 = v0;
192
1.16M
    ctx->v1 = v1;
193
1.16M
    ctx->v2 = v2;
194
1.16M
    ctx->v3 = v3;
195
1.16M
}
196
197
int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
198
1.16M
{
199
    /* finalize hash */
200
1.16M
    unsigned int i;
201
1.16M
    uint64_t b = ctx->total_inlen << 56;
202
1.16M
    uint64_t v0 = ctx->v0;
203
1.16M
    uint64_t v1 = ctx->v1;
204
1.16M
    uint64_t v2 = ctx->v2;
205
1.16M
    uint64_t v3 = ctx->v3;
206
207
1.16M
    if (ctx->crounds == 0 || outlen == 0 || outlen != (size_t)ctx->hash_size)
208
0
        return 0;
209
210
1.16M
    switch (ctx->len) {
211
227
    case 7:
212
227
        b |= ((uint64_t)ctx->leavings[6]) << 48;
213
        /* fall through */
214
305
    case 6:
215
305
        b |= ((uint64_t)ctx->leavings[5]) << 40;
216
        /* fall through */
217
901
    case 5:
218
901
        b |= ((uint64_t)ctx->leavings[4]) << 32;
219
        /* fall through */
220
1.10k
    case 4:
221
1.10k
        b |= ((uint64_t)ctx->leavings[3]) << 24;
222
        /* fall through */
223
1.30k
    case 3:
224
1.30k
        b |= ((uint64_t)ctx->leavings[2]) << 16;
225
        /* fall through */
226
1.50k
    case 2:
227
1.50k
        b |= ((uint64_t)ctx->leavings[1]) <<  8;
228
        /* fall through */
229
3.39k
    case 1:
230
3.39k
        b |= ((uint64_t)ctx->leavings[0]);
231
1.16M
    case 0:
232
1.16M
        break;
233
1.16M
    }
234
235
1.16M
    v3 ^= b;
236
3.49M
    for (i = 0; i < ctx->crounds; ++i)
237
2.33M
        SIPROUND;
238
1.16M
    v0 ^= b;
239
1.16M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
240
0
        v2 ^= 0xee;
241
1.16M
    else
242
1.16M
        v2 ^= 0xff;
243
5.82M
    for (i = 0; i < ctx->drounds; ++i)
244
4.66M
        SIPROUND;
245
1.16M
    b = v0 ^ v1 ^ v2  ^ v3;
246
1.16M
    U64TO8_LE(out, b);
247
1.16M
    if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
248
1.16M
        return 1;
249
0
    v1 ^= 0xdd;
250
0
    for (i = 0; i < ctx->drounds; ++i)
251
0
        SIPROUND;
252
0
    b = v0 ^ v1 ^ v2  ^ v3;
253
0
    U64TO8_LE(out + 8, b);
254
0
    return 1;
255
1.16M
}