Coverage Report

Created: 2025-06-13 06:36

/src/openssl/crypto/sha/sha3.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2017-2024 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
#include <string.h>
11
#if defined(__s390x__) && defined(OPENSSL_CPUID_OBJ)
12
# include "crypto/s390x_arch.h"
13
#endif
14
#include "internal/sha3.h"
15
16
void SHA3_squeeze(uint64_t A[5][5], unsigned char *out, size_t len, size_t r, int next);
17
18
void ossl_sha3_reset(KECCAK1600_CTX *ctx)
19
207
{
20
#if defined(__s390x__) && defined(OPENSSL_CPUID_OBJ)
21
    if (!(OPENSSL_s390xcap_P.stfle[1] & S390X_CAPBIT(S390X_MSA12)))
22
#endif
23
207
        memset(ctx->A, 0, sizeof(ctx->A));
24
207
    ctx->bufsz = 0;
25
207
    ctx->xof_state = XOF_STATE_INIT;
26
207
}
27
28
int ossl_sha3_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen)
29
69
{
30
69
    size_t bsz = SHA3_BLOCKSIZE(bitlen);
31
32
69
    if (bsz <= sizeof(ctx->buf)) {
33
69
        ossl_sha3_reset(ctx);
34
69
        ctx->block_size = bsz;
35
69
        ctx->md_size = bitlen / 8;
36
69
        ctx->pad = pad;
37
69
        return 1;
38
69
    }
39
40
0
    return 0;
41
69
}
42
43
int ossl_keccak_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen, size_t mdlen)
44
0
{
45
0
    int ret = ossl_sha3_init(ctx, pad, bitlen);
46
47
0
    if (ret)
48
0
        ctx->md_size = mdlen / 8;
49
0
    return ret;
50
0
}
51
52
int ossl_sha3_update(KECCAK1600_CTX *ctx, const void *_inp, size_t len)
53
0
{
54
0
    const unsigned char *inp = _inp;
55
0
    size_t bsz = ctx->block_size;
56
0
    size_t num, rem;
57
58
0
    if (len == 0)
59
0
        return 1;
60
61
0
    if (ctx->xof_state == XOF_STATE_SQUEEZE
62
0
        || ctx->xof_state == XOF_STATE_FINAL)
63
0
        return 0;
64
65
0
    if ((num = ctx->bufsz) != 0) {      /* process intermediate buffer? */
66
0
        rem = bsz - num;
67
68
0
        if (len < rem) {
69
0
            memcpy(ctx->buf + num, inp, len);
70
0
            ctx->bufsz += len;
71
0
            return 1;
72
0
        }
73
        /*
74
         * We have enough data to fill or overflow the intermediate
75
         * buffer. So we append |rem| bytes and process the block,
76
         * leaving the rest for later processing...
77
         */
78
0
        memcpy(ctx->buf + num, inp, rem);
79
0
        inp += rem, len -= rem;
80
0
        (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz);
81
0
        ctx->bufsz = 0;
82
        /* ctx->buf is processed, ctx->num is guaranteed to be zero */
83
0
    }
84
85
0
    if (len >= bsz)
86
0
        rem = SHA3_absorb(ctx->A, inp, len, bsz);
87
0
    else
88
0
        rem = len;
89
90
0
    if (rem) {
91
0
        memcpy(ctx->buf, inp + len - rem, rem);
92
0
        ctx->bufsz = rem;
93
0
    }
94
95
0
    return 1;
96
0
}
97
98
/*
99
 * ossl_sha3_final()is a single shot method
100
 * (Use ossl_sha3_squeeze for multiple calls).
101
 * outlen is the variable size output.
102
 */
103
int ossl_sha3_final(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen)
104
69
{
105
69
    size_t bsz = ctx->block_size;
106
69
    size_t num = ctx->bufsz;
107
108
69
    if (outlen == 0)
109
0
        return 1;
110
69
    if (ctx->xof_state == XOF_STATE_SQUEEZE
111
69
        || ctx->xof_state == XOF_STATE_FINAL)
112
0
        return 0;
113
114
    /*
115
     * Pad the data with 10*1. Note that |num| can be |bsz - 1|
116
     * in which case both byte operations below are performed on
117
     * same byte...
118
     */
119
69
    memset(ctx->buf + num, 0, bsz - num);
120
69
    ctx->buf[num] = ctx->pad;
121
69
    ctx->buf[bsz - 1] |= 0x80;
122
123
69
    (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz);
124
125
69
    ctx->xof_state = XOF_STATE_FINAL;
126
69
    SHA3_squeeze(ctx->A, out, outlen, bsz, 0);
127
69
    return 1;
128
69
}
129
130
/*
131
 * This method can be called multiple times.
132
 * Rather than heavily modifying assembler for SHA3_squeeze(),
133
 * we instead just use the limitations of the existing function.
134
 * i.e. Only request multiples of the ctx->block_size when calling
135
 * SHA3_squeeze(). For output length requests smaller than the
136
 * ctx->block_size just request a single ctx->block_size bytes and
137
 * buffer the results. The next request will use the buffer first
138
 * to grab output bytes.
139
 */
140
int ossl_sha3_squeeze(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen)
141
0
{
142
0
    size_t bsz = ctx->block_size;
143
0
    size_t num = ctx->bufsz;
144
0
    size_t len;
145
0
    int next = 1;
146
147
0
    if (outlen == 0)
148
0
        return 1;
149
150
0
    if (ctx->xof_state == XOF_STATE_FINAL)
151
0
        return 0;
152
153
    /*
154
     * On the first squeeze call, finish the absorb process,
155
     * by adding the trailing padding and then doing
156
     * a final absorb.
157
     */
158
0
    if (ctx->xof_state != XOF_STATE_SQUEEZE) {
159
        /*
160
         * Pad the data with 10*1. Note that |num| can be |bsz - 1|
161
         * in which case both byte operations below are performed on
162
         * same byte...
163
         */
164
0
        memset(ctx->buf + num, 0, bsz - num);
165
0
        ctx->buf[num] = ctx->pad;
166
0
        ctx->buf[bsz - 1] |= 0x80;
167
0
        (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz);
168
0
        ctx->xof_state = XOF_STATE_SQUEEZE;
169
0
        num = ctx->bufsz = 0;
170
0
        next = 0;
171
0
    }
172
173
    /*
174
     * Step 1. Consume any bytes left over from a previous squeeze
175
     * (See Step 4 below).
176
     */
177
0
    if (num != 0) {
178
0
        if (outlen > ctx->bufsz)
179
0
            len = ctx->bufsz;
180
0
        else
181
0
            len = outlen;
182
0
        memcpy(out, ctx->buf + bsz - ctx->bufsz, len);
183
0
        out += len;
184
0
        outlen -= len;
185
0
        ctx->bufsz -= len;
186
0
    }
187
0
    if (outlen == 0)
188
0
        return 1;
189
190
    /* Step 2. Copy full sized squeezed blocks to the output buffer directly */
191
0
    if (outlen >= bsz) {
192
0
        len = bsz * (outlen / bsz);
193
0
        SHA3_squeeze(ctx->A, out, len, bsz, next);
194
0
        next = 1;
195
0
        out += len;
196
0
        outlen -= len;
197
0
    }
198
0
    if (outlen > 0) {
199
        /* Step 3. Squeeze one more block into a buffer */
200
0
        SHA3_squeeze(ctx->A, ctx->buf, bsz, bsz, next);
201
0
        memcpy(out, ctx->buf, outlen);
202
        /* Step 4. Remember the leftover part of the squeezed block */
203
0
        ctx->bufsz = bsz - outlen;
204
0
    }
205
206
0
    return 1;
207
0
}