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