/src/openssl/crypto/sha/sha3.c
Line | Count | Source |
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 | | #include "internal/sha3.h" |
12 | | #include "internal/common.h" |
13 | | |
14 | | #if defined(__aarch64__) && defined(KECCAK1600_ASM) |
15 | | #include "crypto/arm_arch.h" |
16 | | #endif |
17 | | |
18 | | #if defined(__s390x__) && defined(OPENSSL_CPUID_OBJ) |
19 | | #include "crypto/s390x_arch.h" |
20 | | #if defined(KECCAK1600_ASM) |
21 | | #define S390_SHA3 1 |
22 | | #define S390_SHA3_CAPABLE(name) \ |
23 | | ((OPENSSL_s390xcap_P.kimd[0] & S390X_CAPBIT(name)) && (OPENSSL_s390xcap_P.klmd[0] & S390X_CAPBIT(name))) |
24 | | #endif |
25 | | #endif |
26 | | |
27 | | void SHA3_squeeze(uint64_t A[5][5], unsigned char *out, size_t len, size_t r, int next); |
28 | | |
29 | | void ossl_sha3_reset(KECCAK1600_CTX *ctx) |
30 | 177 | { |
31 | | #if defined(__s390x__) && defined(OPENSSL_CPUID_OBJ) |
32 | | if (!(OPENSSL_s390xcap_P.stfle[1] & S390X_CAPBIT(S390X_MSA12))) |
33 | | #endif |
34 | 177 | memset(ctx->A, 0, sizeof(ctx->A)); |
35 | 177 | ctx->bufsz = 0; |
36 | 177 | ctx->xof_state = XOF_STATE_INIT; |
37 | 177 | } |
38 | | |
39 | | int ossl_sha3_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen) |
40 | 60 | { |
41 | 60 | size_t bsz = SHA3_BLOCKSIZE(bitlen); |
42 | | |
43 | 60 | if (bsz <= sizeof(ctx->buf)) { |
44 | 60 | ossl_sha3_reset(ctx); |
45 | 60 | ctx->block_size = bsz; |
46 | 60 | ctx->md_size = bitlen / 8; |
47 | 60 | ctx->pad = pad; |
48 | 60 | return 1; |
49 | 60 | } |
50 | | |
51 | 0 | return 0; |
52 | 60 | } |
53 | | |
54 | | int ossl_keccak_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen, size_t mdlen) |
55 | 3 | { |
56 | 3 | int ret = ossl_sha3_init(ctx, pad, bitlen); |
57 | | |
58 | 3 | if (ret) |
59 | 3 | ctx->md_size = mdlen / 8; |
60 | 3 | return ret; |
61 | 3 | } |
62 | | |
63 | | /* |
64 | | * A buffered absorb function that calls a platform specific absorb |
65 | | * method. |
66 | | */ |
67 | | int ossl_sha3_absorb(KECCAK1600_CTX *ctx, const unsigned char *inp, size_t len) |
68 | 120 | { |
69 | 120 | const size_t bsz = ctx->block_size; |
70 | 120 | size_t num, rem; |
71 | | |
72 | 120 | if (ossl_unlikely(len == 0)) |
73 | 0 | return 1; |
74 | | |
75 | 120 | if (!(ctx->xof_state == XOF_STATE_INIT || ctx->xof_state == XOF_STATE_ABSORB)) |
76 | 0 | return 0; |
77 | | |
78 | | /* Is there anything in the buffer already ? */ |
79 | 120 | if ((num = ctx->bufsz) != 0) { |
80 | | /* Calculate how much space is left in the buffer */ |
81 | 60 | rem = bsz - num; |
82 | | /* If the new input does not fill the buffer then just add it */ |
83 | 60 | if (len < rem) { |
84 | 0 | memcpy(ctx->buf + num, inp, len); |
85 | 0 | ctx->bufsz += len; |
86 | 0 | return 1; |
87 | 0 | } |
88 | | /* otherwise fill up the buffer and absorb the buffer */ |
89 | 60 | memcpy(ctx->buf + num, inp, rem); |
90 | | /* Update the input pointer */ |
91 | 60 | inp += rem; |
92 | 60 | len -= rem; |
93 | 60 | ctx->meth.absorb(ctx, ctx->buf, bsz); |
94 | 60 | ctx->bufsz = 0; |
95 | 60 | ctx->xof_state = XOF_STATE_ABSORB; |
96 | 60 | } |
97 | | /* Absorb the input - rem = leftover part of the input < blocksize) */ |
98 | 120 | rem = ctx->meth.absorb(ctx, inp, len); |
99 | 120 | if (len >= bsz) |
100 | 120 | ctx->xof_state = XOF_STATE_ABSORB; |
101 | | /* Copy the leftover bit of the input into the buffer */ |
102 | 120 | if (ossl_likely(rem > 0)) { |
103 | 116 | memcpy(ctx->buf, inp + len - rem, rem); |
104 | 116 | ctx->bufsz = rem; |
105 | 116 | } |
106 | 120 | return 1; |
107 | 120 | } |
108 | | |
109 | | /* |
110 | | * Call a platform specific final method. |
111 | | * In most cases outlen should be set to ctx->mdlen. |
112 | | * This function assumes the caller has checked outlen is bounded. |
113 | | */ |
114 | | int ossl_sha3_final(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) |
115 | 60 | { |
116 | 60 | int ret; |
117 | | |
118 | 60 | if (ctx->xof_state == XOF_STATE_SQUEEZE |
119 | 60 | || ctx->xof_state == XOF_STATE_FINAL) |
120 | 0 | return 0; |
121 | 60 | if (outlen == 0) |
122 | 0 | return 1; |
123 | | |
124 | 60 | ret = ctx->meth.final(ctx, out, outlen); |
125 | 60 | ctx->xof_state = XOF_STATE_FINAL; |
126 | 60 | return ret; |
127 | 60 | } |
128 | | |
129 | | /* Calls a platform specific squeeze method */ |
130 | | int ossl_sha3_squeeze(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) |
131 | 0 | { |
132 | 0 | int ret = 0; |
133 | |
|
134 | 0 | if (ctx->xof_state == XOF_STATE_FINAL) |
135 | 0 | return 0; |
136 | 0 | ret = ctx->meth.squeeze(ctx, out, outlen); |
137 | 0 | ctx->xof_state = XOF_STATE_SQUEEZE; |
138 | 0 | return ret; |
139 | 0 | } |
140 | | |
141 | | /* Default version of the absorb() */ |
142 | | size_t ossl_sha3_absorb_default(KECCAK1600_CTX *ctx, const unsigned char *inp, size_t len) |
143 | 180 | { |
144 | 180 | return SHA3_absorb(ctx->A, inp, len, ctx->block_size); |
145 | 180 | } |
146 | | |
147 | | /* |
148 | | * Default version of the final() is a single shot method |
149 | | * (Use ossl_sha3_default_squeeze() for multiple calls). |
150 | | */ |
151 | | int ossl_sha3_final_default(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) |
152 | 60 | { |
153 | 60 | size_t bsz = ctx->block_size; |
154 | 60 | size_t num = ctx->bufsz; |
155 | | |
156 | | /* |
157 | | * Pad the data with 10*1. Note that |num| can be |bsz - 1| |
158 | | * in which case both byte operations below are performed on |
159 | | * same byte... |
160 | | */ |
161 | 60 | memset(ctx->buf + num, 0, bsz - num); |
162 | 60 | ctx->buf[num] = ctx->pad; |
163 | 60 | ctx->buf[bsz - 1] |= 0x80; |
164 | | |
165 | 60 | (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz); |
166 | | |
167 | 60 | SHA3_squeeze(ctx->A, out, outlen, bsz, 0); |
168 | 60 | return 1; |
169 | 60 | } |
170 | | |
171 | | /* |
172 | | * This method can be called multiple times. |
173 | | * Rather than heavily modifying assembler for SHA3_squeeze(), |
174 | | * we instead just use the limitations of the existing function. |
175 | | * i.e. Only request multiples of the ctx->block_size when calling |
176 | | * SHA3_squeeze(). For output length requests smaller than the |
177 | | * ctx->block_size just request a single ctx->block_size bytes and |
178 | | * buffer the results. The next request will use the buffer first |
179 | | * to grab output bytes. |
180 | | */ |
181 | | int ossl_shake_squeeze_default(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) |
182 | 0 | { |
183 | 0 | size_t bsz = ctx->block_size; |
184 | 0 | size_t num = ctx->bufsz; |
185 | 0 | size_t len; |
186 | 0 | int next = 1; |
187 | | |
188 | | /* |
189 | | * On the first squeeze call, finish the absorb process, |
190 | | * by adding the trailing padding and then doing |
191 | | * a final absorb. |
192 | | */ |
193 | 0 | if (ctx->xof_state != XOF_STATE_SQUEEZE) { |
194 | | /* |
195 | | * Pad the data with 10*1. Note that |num| can be |bsz - 1| |
196 | | * in which case both byte operations below are performed on |
197 | | * same byte... |
198 | | */ |
199 | 0 | memset(ctx->buf + num, 0, bsz - num); |
200 | 0 | ctx->buf[num] = ctx->pad; |
201 | 0 | ctx->buf[bsz - 1] |= 0x80; |
202 | 0 | (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz); |
203 | 0 | num = ctx->bufsz = 0; |
204 | 0 | next = 0; |
205 | 0 | } |
206 | | |
207 | | /* |
208 | | * Step 1. Consume any bytes left over from a previous squeeze |
209 | | * (See Step 4 below). |
210 | | */ |
211 | 0 | if (num != 0) { |
212 | 0 | if (outlen > ctx->bufsz) |
213 | 0 | len = ctx->bufsz; |
214 | 0 | else |
215 | 0 | len = outlen; |
216 | 0 | memcpy(out, ctx->buf + bsz - ctx->bufsz, len); |
217 | 0 | out += len; |
218 | 0 | outlen -= len; |
219 | 0 | ctx->bufsz -= len; |
220 | 0 | } |
221 | 0 | if (outlen == 0) |
222 | 0 | return 1; |
223 | | |
224 | | /* Step 2. Copy full sized squeezed blocks to the output buffer directly */ |
225 | 0 | if (outlen >= bsz) { |
226 | 0 | len = bsz * (outlen / bsz); |
227 | 0 | SHA3_squeeze(ctx->A, out, len, bsz, next); |
228 | 0 | next = 1; |
229 | 0 | out += len; |
230 | 0 | outlen -= len; |
231 | 0 | } |
232 | 0 | if (outlen > 0) { |
233 | | /* Step 3. Squeeze one more block into a buffer */ |
234 | 0 | SHA3_squeeze(ctx->A, ctx->buf, bsz, bsz, next); |
235 | 0 | memcpy(out, ctx->buf, outlen); |
236 | | /* Step 4. Remember the leftover part of the squeezed block */ |
237 | 0 | ctx->bufsz = bsz - outlen; |
238 | 0 | } |
239 | 0 | return 1; |
240 | 0 | } |
241 | | |
242 | | static PROV_SHA3_METHOD shake_generic_meth = { |
243 | | ossl_sha3_absorb_default, |
244 | | ossl_sha3_final_default, |
245 | | ossl_shake_squeeze_default |
246 | | }; |
247 | | |
248 | | #if defined(S390_SHA3) |
249 | | |
250 | | /*- |
251 | | * The platform specific parts of the absorb() and final() for S390X. |
252 | | */ |
253 | | static size_t sha3_absorb_s390x(KECCAK1600_CTX *ctx, const unsigned char *inp, size_t len) |
254 | | { |
255 | | size_t rem = len % ctx->block_size; |
256 | | unsigned int fc; |
257 | | |
258 | | if (len - rem > 0) { |
259 | | fc = ctx->pad; |
260 | | fc |= ctx->xof_state == XOF_STATE_INIT ? S390X_KIMD_NIP : 0; |
261 | | s390x_kimd(inp, len - rem, fc, ctx->A); |
262 | | } |
263 | | return rem; |
264 | | } |
265 | | |
266 | | static int shake_final_s390x(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) |
267 | | { |
268 | | unsigned int fc; |
269 | | |
270 | | fc = ctx->pad | S390X_KLMD_DUFOP; |
271 | | fc |= ctx->xof_state == XOF_STATE_INIT ? S390X_KLMD_NIP : 0; |
272 | | s390x_klmd(ctx->buf, ctx->bufsz, out, outlen, fc, ctx->A); |
273 | | return 1; |
274 | | } |
275 | | |
276 | | static int shake_squeeze_s390x(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen) |
277 | | { |
278 | | unsigned int fc; |
279 | | size_t len; |
280 | | |
281 | | /* |
282 | | * On the first squeeze call, finish the absorb process (incl. padding). |
283 | | */ |
284 | | if (ctx->xof_state != XOF_STATE_SQUEEZE) { |
285 | | fc = ctx->pad; |
286 | | fc |= ctx->xof_state == XOF_STATE_INIT ? S390X_KLMD_NIP : 0; |
287 | | s390x_klmd(ctx->buf, ctx->bufsz, out, outlen, fc, ctx->A); |
288 | | ctx->bufsz = outlen % ctx->block_size; |
289 | | /* reuse ctx->bufsz to count bytes squeezed from current sponge */ |
290 | | return 1; |
291 | | } |
292 | | if (ctx->bufsz != 0) { |
293 | | len = ctx->block_size - ctx->bufsz; |
294 | | if (outlen < len) |
295 | | len = outlen; |
296 | | memcpy(out, (char *)ctx->A + ctx->bufsz, len); |
297 | | out += len; |
298 | | outlen -= len; |
299 | | ctx->bufsz += len; |
300 | | if (ctx->bufsz == ctx->block_size) |
301 | | ctx->bufsz = 0; |
302 | | } |
303 | | if (outlen == 0) |
304 | | return 1; |
305 | | s390x_klmd(NULL, 0, out, outlen, ctx->pad | S390X_KLMD_PS, ctx->A); |
306 | | ctx->bufsz = outlen % ctx->block_size; |
307 | | |
308 | | return 1; |
309 | | } |
310 | | |
311 | | static PROV_SHA3_METHOD shake_s390x_meth = { |
312 | | sha3_absorb_s390x, |
313 | | shake_final_s390x, |
314 | | shake_squeeze_s390x |
315 | | }; |
316 | | #elif defined(__aarch64__) && defined(KECCAK1600_ASM) |
317 | | |
318 | | size_t SHA3_absorb_cext(uint64_t A[5][5], const unsigned char *inp, size_t len, |
319 | | size_t r); |
320 | | /*- |
321 | | * Hardware-assisted ARMv8.2 SHA3 extension version of the absorb() |
322 | | */ |
323 | | static size_t sha3_absorb_arm(KECCAK1600_CTX *ctx, const unsigned char *inp, size_t len) |
324 | | { |
325 | | return SHA3_absorb_cext(ctx->A, inp, len, ctx->block_size); |
326 | | } |
327 | | |
328 | | static PROV_SHA3_METHOD shake_ARMSHA3_meth = { |
329 | | sha3_absorb_arm, |
330 | | ossl_sha3_final_default, |
331 | | ossl_shake_squeeze_default |
332 | | }; |
333 | | #endif |
334 | | |
335 | | KECCAK1600_CTX *ossl_shake256_new(void) |
336 | 0 | { |
337 | 0 | KECCAK1600_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); |
338 | |
|
339 | 0 | if (ctx == NULL) |
340 | 0 | return NULL; |
341 | 0 | ossl_keccak_init(ctx, '\x1f', 256, 0); |
342 | 0 | ctx->md_size = SIZE_MAX; |
343 | 0 | ctx->meth = shake_generic_meth; |
344 | | #if defined(S390_SHA3) |
345 | | if (S390_SHA3_CAPABLE(S390X_SHAKE_256)) { |
346 | | ctx->pad = S390X_SHAKE_256; |
347 | | ctx->meth = shake_s390x_meth; |
348 | | } |
349 | | #elif defined(__aarch64__) && defined(KECCAK1600_ASM) |
350 | | if (OPENSSL_armcap_P & ARMV8_HAVE_SHA3_AND_WORTH_USING) |
351 | | ctx->meth = shake_ARMSHA3_meth; |
352 | | #endif |
353 | 0 | return ctx; |
354 | 0 | } |