Coverage Report

Created: 2024-07-27 06:39

/src/openssl30/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
68.2k
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
33
34
#define U32TO8_LE(p, v)                                                        \
35
3.20k
    (p)[0] = (uint8_t)((v));                                                   \
36
3.20k
    (p)[1] = (uint8_t)((v) >> 8);                                              \
37
3.20k
    (p)[2] = (uint8_t)((v) >> 16);                                             \
38
3.20k
    (p)[3] = (uint8_t)((v) >> 24);
39
40
#define U64TO8_LE(p, v)                                                        \
41
1.60k
    U32TO8_LE((p), (uint32_t)((v)));                                           \
42
1.60k
    U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
43
44
#define U8TO64_LE(p)                                                           \
45
3.29k
    (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                        \
46
3.29k
     ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                 \
47
3.29k
     ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                 \
48
3.29k
     ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
49
50
#define SIPROUND                                                               \
51
13.8k
    do {                                                                       \
52
11.3k
        v0 += v1;                                                              \
53
11.3k
        v1 = ROTL(v1, 13);                                                     \
54
11.3k
        v1 ^= v0;                                                              \
55
11.3k
        v0 = ROTL(v0, 32);                                                     \
56
11.3k
        v2 += v3;                                                              \
57
11.3k
        v3 = ROTL(v3, 16);                                                     \
58
11.3k
        v3 ^= v2;                                                              \
59
11.3k
        v0 += v3;                                                              \
60
11.3k
        v3 = ROTL(v3, 21);                                                     \
61
11.3k
        v3 ^= v0;                                                              \
62
11.3k
        v2 += v1;                                                              \
63
11.3k
        v1 = ROTL(v1, 17);                                                     \
64
11.3k
        v1 ^= v2;                                                              \
65
11.3k
        v2 = ROTL(v2, 32);                                                     \
66
11.3k
    } 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
868
{
80
868
    if (hash_size == 0)
81
47
        hash_size = SIPHASH_MAX_DIGEST_SIZE;
82
868
    return hash_size;
83
868
}
84
85
int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
86
35
{
87
35
    hash_size = siphash_adjust_hash_size(hash_size);
88
35
    if (hash_size != SIPHASH_MIN_DIGEST_SIZE
89
35
        && hash_size != SIPHASH_MAX_DIGEST_SIZE)
90
11
        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
24
    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
24
    if ((size_t)ctx->hash_size != hash_size) {
102
4
        ctx->v1 ^= 0xee;
103
4
        ctx->hash_size = hash_size;
104
4
    }
105
24
    return 1;
106
35
}
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
809
{
111
809
    uint64_t k0 = U8TO64_LE(k);
112
809
    uint64_t k1 = U8TO64_LE(k + 8);
113
114
    /* If the hash size wasn't set, i.e. is zero */
115
809
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
116
117
809
    if (drounds == 0)
118
0
        drounds = SIPHASH_D_ROUNDS;
119
809
    if (crounds == 0)
120
0
        crounds = SIPHASH_C_ROUNDS;
121
122
809
    ctx->crounds = crounds;
123
809
    ctx->drounds = drounds;
124
125
809
    ctx->len = 0;
126
809
    ctx->total_inlen = 0;
127
128
809
    ctx->v0 = 0x736f6d6570736575ULL ^ k0;
129
809
    ctx->v1 = 0x646f72616e646f6dULL ^ k1;
130
809
    ctx->v2 = 0x6c7967656e657261ULL ^ k0;
131
809
    ctx->v3 = 0x7465646279746573ULL ^ k1;
132
133
809
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
134
808
        ctx->v1 ^= 0xee;
135
136
809
    return 1;
137
809
}
138
139
void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
140
845
{
141
845
    uint64_t m;
142
845
    const uint8_t *end;
143
845
    int left;
144
845
    unsigned int i;
145
845
    uint64_t v0 = ctx->v0;
146
845
    uint64_t v1 = ctx->v1;
147
845
    uint64_t v2 = ctx->v2;
148
845
    uint64_t v3 = ctx->v3;
149
150
845
    ctx->total_inlen += inlen;
151
152
845
    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
845
    left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
176
845
    end = in + inlen - left;
177
178
2.49k
    for (; in != end; in += 8) {
179
1.65k
        m = U8TO64_LE(in);
180
1.65k
        v3 ^= m;
181
4.96k
        for (i = 0; i < ctx->crounds; ++i)
182
3.30k
            SIPROUND;
183
1.65k
        v0 ^= m;
184
1.65k
    }
185
186
    /* save leavings and other ctx */
187
845
    if (left)
188
43
        memcpy(ctx->leavings, end, left);
189
845
    ctx->len = left;
190
191
845
    ctx->v0 = v0;
192
845
    ctx->v1 = v1;
193
845
    ctx->v2 = v2;
194
845
    ctx->v3 = v3;
195
845
}
196
197
int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
198
802
{
199
    /* finalize hash */
200
802
    unsigned int i;
201
802
    uint64_t b = ctx->total_inlen << 56;
202
802
    uint64_t v0 = ctx->v0;
203
802
    uint64_t v1 = ctx->v1;
204
802
    uint64_t v2 = ctx->v2;
205
802
    uint64_t v3 = ctx->v3;
206
207
802
    if (ctx->crounds == 0 || outlen == 0 || outlen != (size_t)ctx->hash_size)
208
0
        return 0;
209
210
802
    switch (ctx->len) {
211
0
    case 7:
212
0
        b |= ((uint64_t)ctx->leavings[6]) << 48;
213
        /* fall thru */
214
6
    case 6:
215
6
        b |= ((uint64_t)ctx->leavings[5]) << 40;
216
        /* fall thru */
217
6
    case 5:
218
6
        b |= ((uint64_t)ctx->leavings[4]) << 32;
219
        /* fall thru */
220
6
    case 4:
221
6
        b |= ((uint64_t)ctx->leavings[3]) << 24;
222
        /* fall thru */
223
6
    case 3:
224
6
        b |= ((uint64_t)ctx->leavings[2]) << 16;
225
        /* fall thru */
226
6
    case 2:
227
6
        b |= ((uint64_t)ctx->leavings[1]) <<  8;
228
        /* fall thru */
229
17
    case 1:
230
17
        b |= ((uint64_t)ctx->leavings[0]);
231
802
    case 0:
232
802
        break;
233
802
    }
234
235
802
    v3 ^= b;
236
2.40k
    for (i = 0; i < ctx->crounds; ++i)
237
1.60k
        SIPROUND;
238
802
    v0 ^= b;
239
802
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
240
802
        v2 ^= 0xee;
241
0
    else
242
0
        v2 ^= 0xff;
243
4.01k
    for (i = 0; i < ctx->drounds; ++i)
244
3.20k
        SIPROUND;
245
802
    b = v0 ^ v1 ^ v2  ^ v3;
246
802
    U64TO8_LE(out, b);
247
802
    if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
248
0
        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
802
}