/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 | 0 | { |
20 | | #if defined(__s390x__) && defined(OPENSSL_CPUID_OBJ) |
21 | | if (!(OPENSSL_s390xcap_P.stfle[1] & S390X_CAPBIT(S390X_MSA12))) |
22 | | #endif |
23 | 0 | memset(ctx->A, 0, sizeof(ctx->A)); |
24 | 0 | ctx->bufsz = 0; |
25 | 0 | ctx->xof_state = XOF_STATE_INIT; |
26 | 0 | } |
27 | | |
28 | | int ossl_sha3_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen) |
29 | 0 | { |
30 | 0 | size_t bsz = SHA3_BLOCKSIZE(bitlen); |
31 | |
|
32 | 0 | if (bsz <= sizeof(ctx->buf)) { |
33 | 0 | ossl_sha3_reset(ctx); |
34 | 0 | ctx->block_size = bsz; |
35 | 0 | ctx->md_size = bitlen / 8; |
36 | 0 | ctx->pad = pad; |
37 | 0 | return 1; |
38 | 0 | } |
39 | | |
40 | 0 | return 0; |
41 | 0 | } |
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 | 0 | { |
105 | 0 | size_t bsz = ctx->block_size; |
106 | 0 | size_t num = ctx->bufsz; |
107 | |
|
108 | 0 | if (outlen == 0) |
109 | 0 | return 1; |
110 | 0 | if (ctx->xof_state == XOF_STATE_SQUEEZE |
111 | 0 | || 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 | 0 | memset(ctx->buf + num, 0, bsz - num); |
120 | 0 | ctx->buf[num] = ctx->pad; |
121 | 0 | ctx->buf[bsz - 1] |= 0x80; |
122 | |
|
123 | 0 | (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz); |
124 | |
|
125 | 0 | ctx->xof_state = XOF_STATE_FINAL; |
126 | 0 | SHA3_squeeze(ctx->A, out, outlen, bsz, 0); |
127 | 0 | return 1; |
128 | 0 | } |
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 | } |