Coverage Report

Created: 2025-08-11 07:04

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