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
ossl_sha3_reset(KECCAK1600_CTX * ctx)18 void ossl_sha3_reset(KECCAK1600_CTX *ctx)
19 {
20 #if defined(__s390x__) && defined(OPENSSL_CPUID_OBJ)
21 if (!(OPENSSL_s390xcap_P.stfle[1] & S390X_CAPBIT(S390X_MSA12)))
22 #endif
23 memset(ctx->A, 0, sizeof(ctx->A));
24 ctx->bufsz = 0;
25 ctx->xof_state = XOF_STATE_INIT;
26 }
27
ossl_sha3_init(KECCAK1600_CTX * ctx,unsigned char pad,size_t bitlen)28 int ossl_sha3_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen)
29 {
30 size_t bsz = SHA3_BLOCKSIZE(bitlen);
31
32 if (bsz <= sizeof(ctx->buf)) {
33 ossl_sha3_reset(ctx);
34 ctx->block_size = bsz;
35 ctx->md_size = bitlen / 8;
36 ctx->pad = pad;
37 return 1;
38 }
39
40 return 0;
41 }
42
ossl_keccak_init(KECCAK1600_CTX * ctx,unsigned char pad,size_t bitlen,size_t mdlen)43 int ossl_keccak_init(KECCAK1600_CTX *ctx, unsigned char pad, size_t bitlen, size_t mdlen)
44 {
45 int ret = ossl_sha3_init(ctx, pad, bitlen);
46
47 if (ret)
48 ctx->md_size = mdlen / 8;
49 return ret;
50 }
51
ossl_sha3_update(KECCAK1600_CTX * ctx,const void * _inp,size_t len)52 int ossl_sha3_update(KECCAK1600_CTX *ctx, const void *_inp, size_t len)
53 {
54 const unsigned char *inp = _inp;
55 size_t bsz = ctx->block_size;
56 size_t num, rem;
57
58 if (len == 0)
59 return 1;
60
61 if (ctx->xof_state == XOF_STATE_SQUEEZE
62 || ctx->xof_state == XOF_STATE_FINAL)
63 return 0;
64
65 if ((num = ctx->bufsz) != 0) { /* process intermediate buffer? */
66 rem = bsz - num;
67
68 if (len < rem) {
69 memcpy(ctx->buf + num, inp, len);
70 ctx->bufsz += len;
71 return 1;
72 }
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 memcpy(ctx->buf + num, inp, rem);
79 inp += rem, len -= rem;
80 (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz);
81 ctx->bufsz = 0;
82 /* ctx->buf is processed, ctx->num is guaranteed to be zero */
83 }
84
85 if (len >= bsz)
86 rem = SHA3_absorb(ctx->A, inp, len, bsz);
87 else
88 rem = len;
89
90 if (rem) {
91 memcpy(ctx->buf, inp + len - rem, rem);
92 ctx->bufsz = rem;
93 }
94
95 return 1;
96 }
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 */
ossl_sha3_final(KECCAK1600_CTX * ctx,unsigned char * out,size_t outlen)103 int ossl_sha3_final(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen)
104 {
105 size_t bsz = ctx->block_size;
106 size_t num = ctx->bufsz;
107
108 if (outlen == 0)
109 return 1;
110 if (ctx->xof_state == XOF_STATE_SQUEEZE
111 || ctx->xof_state == XOF_STATE_FINAL)
112 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 memset(ctx->buf + num, 0, bsz - num);
120 ctx->buf[num] = ctx->pad;
121 ctx->buf[bsz - 1] |= 0x80;
122
123 (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz);
124
125 ctx->xof_state = XOF_STATE_FINAL;
126 SHA3_squeeze(ctx->A, out, outlen, bsz, 0);
127 return 1;
128 }
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 */
ossl_sha3_squeeze(KECCAK1600_CTX * ctx,unsigned char * out,size_t outlen)140 int ossl_sha3_squeeze(KECCAK1600_CTX *ctx, unsigned char *out, size_t outlen)
141 {
142 size_t bsz = ctx->block_size;
143 size_t num = ctx->bufsz;
144 size_t len;
145 int next = 1;
146
147 if (outlen == 0)
148 return 1;
149
150 if (ctx->xof_state == XOF_STATE_FINAL)
151 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 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 memset(ctx->buf + num, 0, bsz - num);
165 ctx->buf[num] = ctx->pad;
166 ctx->buf[bsz - 1] |= 0x80;
167 (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz);
168 ctx->xof_state = XOF_STATE_SQUEEZE;
169 num = ctx->bufsz = 0;
170 next = 0;
171 }
172
173 /*
174 * Step 1. Consume any bytes left over from a previous squeeze
175 * (See Step 4 below).
176 */
177 if (num != 0) {
178 if (outlen > ctx->bufsz)
179 len = ctx->bufsz;
180 else
181 len = outlen;
182 memcpy(out, ctx->buf + bsz - ctx->bufsz, len);
183 out += len;
184 outlen -= len;
185 ctx->bufsz -= len;
186 }
187 if (outlen == 0)
188 return 1;
189
190 /* Step 2. Copy full sized squeezed blocks to the output buffer directly */
191 if (outlen >= bsz) {
192 len = bsz * (outlen / bsz);
193 SHA3_squeeze(ctx->A, out, len, bsz, next);
194 next = 1;
195 out += len;
196 outlen -= len;
197 }
198 if (outlen > 0) {
199 /* Step 3. Squeeze one more block into a buffer */
200 SHA3_squeeze(ctx->A, ctx->buf, bsz, bsz, next);
201 memcpy(out, ctx->buf, outlen);
202 /* Step 4. Remember the leftover part of the squeezed block */
203 ctx->bufsz = bsz - outlen;
204 }
205
206 return 1;
207 }
208