Commit | Line | Data |
---|---|---|
a1a6042e MW |
1 | /* -*-c-*- |
2 | * | |
3 | * The SHA3 algorithm family | |
4 | * | |
5 | * (c) 2017 Straylight/Edgeware | |
6 | */ | |
7 | ||
8 | /*----- Licensing notice --------------------------------------------------* | |
9 | * | |
10 | * This file is part of secnet. | |
11 | * See README for full list of copyright holders. | |
12 | * | |
13 | * secnet is free software; you can redistribute it and/or modify it | |
14 | * under the terms of the GNU General Public License as published by | |
15 | * the Free Software Foundation; either version d of the License, or | |
16 | * (at your option) any later version. | |
17 | * | |
18 | * secnet is distributed in the hope that it will be useful, but | |
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
21 | * General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * version 3 along with secnet; if not, see | |
25 | * https://www.gnu.org/licenses/gpl.html. | |
26 | * | |
27 | * This file was originally part of Catacomb, but has been automatically | |
28 | * modified for incorporation into secnet: see `import-catacomb-crypto' | |
29 | * for details. | |
30 | * | |
31 | * Catacomb is free software; you can redistribute it and/or modify | |
32 | * it under the terms of the GNU Library General Public License as | |
33 | * published by the Free Software Foundation; either version 2 of the | |
34 | * License, or (at your option) any later version. | |
35 | * | |
36 | * Catacomb is distributed in the hope that it will be useful, | |
37 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
38 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
39 | * GNU Library General Public License for more details. | |
40 | * | |
41 | * You should have received a copy of the GNU Library General Public | |
42 | * License along with Catacomb; if not, write to the Free | |
43 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
44 | * MA 02111-1307, USA. | |
45 | */ | |
46 | ||
47 | /*----- Header files ------------------------------------------------------*/ | |
48 | ||
49 | #include <assert.h> | |
50 | #include <stdarg.h> | |
51 | #include <string.h> | |
52 | ||
53 | #include "sha3.h" | |
54 | ||
55 | /*----- General utilities -------------------------------------------------*/ | |
56 | ||
57 | static void absorb(sha3_ctx *ctx, const octet *p, unsigned r) | |
58 | { | |
59 | kludge64 t[25]; | |
60 | unsigned i; | |
61 | ||
62 | /* memdump("absorb", p, 8*r, 0); */ | |
63 | for (i = 0; i < r; i++) { LOAD64_L_(t[i], p); p += 8; } | |
64 | keccak1600_mix(&ctx->s, t, r); | |
65 | } | |
66 | ||
67 | static void step(sha3_ctx *ctx) { keccak1600_p(&ctx->s, &ctx->s, 24); } | |
68 | ||
69 | static void pad(sha3_ctx *ctx, unsigned lo, unsigned hi) | |
70 | { | |
71 | size_t spare = ctx->r - ctx->n; | |
72 | ||
73 | if (spare == 1) | |
74 | ctx->buf[ctx->n] = lo | hi; | |
75 | else { | |
76 | ctx->buf[ctx->n] = lo; | |
77 | ctx->buf[ctx->r - 1] = hi; | |
78 | memset(ctx->buf + ctx->n + 1, 0, spare - 2); | |
79 | } | |
80 | absorb(ctx, ctx->buf, ctx->r/8); | |
81 | } | |
82 | ||
83 | static void squeeze(sha3_ctx *ctx, octet *p, unsigned r) | |
84 | { | |
85 | kludge64 t[25]; | |
86 | unsigned i; | |
87 | ||
88 | keccak1600_extract(&ctx->s, t, r); | |
89 | for (i = 0; i < r; i++) { STORE64_L_(p, t[i]); p += 8; } | |
90 | /* memdump("squeeze", p - 8*r, 8*r, 0); */ | |
91 | } | |
92 | ||
93 | enum { | |
94 | OP_CSHAKE = 0x04, | |
95 | OP_SHA3 = 0x06, | |
96 | OP_SHAKE = 0x1f | |
97 | }; | |
98 | ||
99 | enum { ST_ABSORB, ST_SQUEEZE, ST_DEAD }; | |
100 | ||
101 | /*----- The SHA3 algorithms -----------------------------------------------*/ | |
102 | ||
103 | /* --- @sha3_{224,256,384,512}_init@ --- * | |
104 | * | |
105 | * Arguments: @sha3_ctx *ctx@ = pointer to context block to initialize | |
106 | * | |
107 | * Returns: --- | |
108 | * | |
109 | * Use: Initializes a SHA3 hashing context for use. | |
110 | */ | |
111 | ||
112 | static void init_sha3(sha3_ctx *ctx, unsigned w) | |
113 | { | |
114 | keccak1600_init(&ctx->s); | |
115 | ctx->w = w/8; ctx->r = (1600 - 2*w)/8; ctx->n = 0; | |
116 | } | |
117 | ||
118 | void sha3_224_init(sha3_ctx *ctx) { init_sha3(ctx, 224); } | |
119 | void sha3_256_init(sha3_ctx *ctx) { init_sha3(ctx, 256); } | |
120 | void sha3_384_init(sha3_ctx *ctx) { init_sha3(ctx, 384); } | |
121 | void sha3_512_init(sha3_ctx *ctx) { init_sha3(ctx, 512); } | |
122 | ||
123 | /* --- @sha3_hash@ --- * | |
124 | * | |
125 | * Arguments: @sha3_ctx *ctx@ = pointer to context bock | |
126 | * @const void *p@ = pointer to data to hash | |
127 | * @size_t sz@ = size of buffer to hash | |
128 | * | |
129 | * Returns: --- | |
130 | * | |
131 | * Use: Hashes a buffer of data. The buffer may be of any size and | |
132 | * alignment. | |
133 | */ | |
134 | ||
135 | void sha3_hash(sha3_ctx *ctx, const void *p, size_t sz) | |
136 | { | |
137 | const octet *q = p; | |
138 | size_t spare = ctx->r - ctx->n; | |
139 | ||
140 | if (sz < spare) { | |
141 | memcpy(ctx->buf + ctx->n, q, sz); | |
142 | ctx->n += sz; | |
143 | return; | |
144 | } | |
145 | if (ctx->n) { | |
146 | memcpy(ctx->buf + ctx->n, q, spare); | |
147 | absorb(ctx, ctx->buf, ctx->r/8); | |
148 | step(ctx); | |
149 | q += spare; sz -= spare; | |
150 | } | |
151 | while (sz >= ctx->r) { | |
152 | absorb(ctx, q, ctx->r/8); | |
153 | step(ctx); | |
154 | q += ctx->r; sz -= ctx->r; | |
155 | } | |
156 | if (sz) memcpy(ctx->buf, q, sz); | |
157 | ctx->n = sz; | |
158 | } | |
159 | ||
160 | /* --- @sha3_done@ --- * | |
161 | * | |
162 | * Arguments: @sha3_ctx *ctx@ = pointer to context block | |
163 | * @void *hash@ = pointer to output buffer | |
164 | * | |
165 | * Returns: --- | |
166 | * | |
167 | * Use: Returns the hash of the data read so far. | |
168 | */ | |
169 | ||
170 | void sha3_done(sha3_ctx *ctx, void *hash) | |
171 | { | |
172 | pad(ctx, OP_SHA3, 0x80); | |
173 | step(ctx); | |
174 | ||
175 | if (ctx->w%8 == 0) | |
176 | squeeze(ctx, hash, ctx->w/8); | |
177 | else { | |
178 | squeeze(ctx, ctx->buf, (ctx->w + 7)/8); | |
179 | memcpy(hash, ctx->buf, ctx->w); | |
180 | } | |
181 | } | |
182 | ||
183 | /*----- The cSHAKE XOF algorithm ------------------------------------------*/ | |
184 | ||
185 | static void leftenc_sz(shake_ctx *ctx, size_t n) | |
186 | { | |
187 | kludge64 t; | |
188 | octet b[9]; | |
189 | unsigned i; | |
190 | ||
191 | SET64(t, ((n&~(size_t)MASK32) >> 16) >> 16, n&MASK32); | |
192 | STORE64_B_(b + 1, t); | |
193 | for (i = 1; i < 8 && !b[i]; i++); | |
194 | i--; b[i] = 8 - i; | |
195 | shake_hash(ctx, b + i, 9 - i); | |
196 | } | |
197 | ||
a1a6042e MW |
198 | static void stringenc(shake_ctx *ctx, const void *p, size_t sz) |
199 | { leftenc_sz(ctx, 8*sz); if (sz) shake_hash(ctx, p, sz); } | |
200 | ||
201 | static void bytepad_before(shake_ctx *ctx) | |
202 | { leftenc_sz(ctx, ctx->h.r); } | |
203 | ||
204 | static void bytepad_after(shake_ctx *ctx) | |
205 | { | |
206 | unsigned pad; | |
207 | ||
208 | if (ctx->h.n%8) { | |
209 | pad = 8 - ctx->h.n%8; | |
210 | memset(ctx->h.buf + ctx->h.n, 0, pad); | |
211 | ctx->h.n += pad; | |
212 | } | |
213 | if (ctx->h.n) { | |
214 | absorb(&ctx->h, ctx->h.buf, ctx->h.n/8); | |
215 | step(&ctx->h); ctx->h.n = 0; | |
216 | } | |
217 | } | |
218 | ||
219 | /* --- @cshake{128,256}_init@ --- * | |
220 | * | |
221 | * Arguments: @shake_ctx *ctx@ = pointer to context to initialize | |
222 | * @const void *func@ = NIST-allocated function name | |
223 | * @size_t fsz@ = length of function name | |
224 | * @const void *perso@ = user personalization string | |
225 | * @size_t psz@ = length of personalization string | |
226 | * | |
227 | * Returns: --- | |
228 | * | |
229 | * Use: Initializes a cSHAKE context. The context is initially in | |
230 | * the `absorbing' state: feed it data with @shake_hash@. | |
231 | */ | |
232 | ||
233 | static void init_shake(shake_ctx *ctx, unsigned c0, | |
234 | const void *func, size_t fsz, | |
235 | const void *perso, size_t psz) | |
236 | { | |
237 | keccak1600_init(&ctx->h.s); ctx->st = ST_ABSORB; | |
238 | ctx->h.r = (1600 - 2*c0)/8; ctx->h.w = 0; ctx->h.n = 0; | |
239 | if (!fsz && !psz) | |
240 | ctx->op = OP_SHAKE; | |
241 | else { | |
242 | bytepad_before(ctx); | |
243 | stringenc(ctx, func, fsz); | |
244 | stringenc(ctx, perso, psz); | |
245 | bytepad_after(ctx); | |
246 | ctx->op = OP_CSHAKE; | |
247 | } | |
248 | } | |
249 | ||
250 | void cshake128_init(shake_ctx *ctx, | |
251 | const void *func, size_t fsz, | |
252 | const void *perso, size_t psz) | |
253 | { init_shake(ctx, 128, func, fsz, perso, psz); } | |
254 | ||
255 | void cshake256_init(shake_ctx *ctx, | |
256 | const void *func, size_t fsz, | |
257 | const void *perso, size_t psz) | |
258 | { init_shake(ctx, 256, func, fsz, perso, psz); } | |
259 | ||
260 | /* --- @shake{128,256}_init@ --- * | |
261 | * | |
262 | * Arguments: @sha3_ctx *ctx@ = pointer to context to initialize | |
263 | * | |
264 | * Returns: --- | |
265 | * | |
266 | * Use: Initializes a SHAKE context. The context is initially in | |
267 | * the `absorbing' state: feed it data with @shake_hash@. | |
268 | */ | |
269 | ||
270 | void shake128_init(shake_ctx *ctx) { init_shake(ctx, 128, 0, 0, 0, 0); } | |
271 | void shake256_init(shake_ctx *ctx) { init_shake(ctx, 256, 0, 0, 0, 0); } | |
272 | ||
273 | /* --- @shake_hash@ --- * | |
274 | * | |
275 | * Arguments: @shake_ctx *ctx@ = context to update | |
276 | * @const void *p@ = input buffer | |
277 | * @size_t sz@ = size of input | |
278 | * | |
279 | * Returns: --- | |
280 | * | |
281 | * Use: Feeds input data into a SHAKE context. The context must be | |
282 | * in `absorbing' state. | |
283 | */ | |
284 | ||
285 | void shake_hash(shake_ctx *ctx, const void *p, size_t sz) | |
286 | { assert(ctx->st == ST_ABSORB); sha3_hash(&ctx->h, p, sz); } | |
287 | ||
288 | /* --- @shake_xof@ --- * | |
289 | * | |
290 | * Arguments: @shake_ctx *ctx@ = context to update | |
291 | * | |
292 | * Returns: --- | |
293 | * | |
294 | * Use: Switches the context into `squeezing' state. Use @shake_get@ | |
295 | * or @shake_mask@ to extract data. | |
296 | */ | |
297 | ||
298 | void shake_xof(shake_ctx *ctx) | |
299 | { | |
300 | assert(ctx->st == ST_ABSORB); | |
301 | pad(&ctx->h, ctx->op, 0x80); | |
302 | ctx->st = ST_SQUEEZE; | |
303 | ctx->h.n = ctx->h.r; | |
304 | } | |
305 | ||
306 | /* --- @shake_get@ --- * | |
307 | * | |
308 | * Arguments: @shake_ctx *ctx@ = context to update | |
309 | * @void *p@ = output buffer | |
310 | * @size_t sz@ = size of output | |
311 | * | |
312 | * Returns: --- | |
313 | * | |
314 | * Use: Extracts output from a SHAKE context. The context must be | |
315 | * in `squeezing' state. | |
316 | */ | |
317 | ||
318 | void shake_get(shake_ctx *ctx, void *p, size_t sz) | |
319 | { | |
320 | octet *q = p; | |
321 | size_t left = ctx->h.r - ctx->h.n; | |
322 | ||
323 | assert(ctx->st == ST_SQUEEZE); | |
324 | if (left >= sz) { | |
325 | memcpy(q, ctx->h.buf + ctx->h.n, sz); | |
326 | ctx->h.n += sz; | |
327 | return; | |
328 | } | |
329 | if (left) { | |
330 | memcpy(q, ctx->h.buf + ctx->h.n, left); | |
331 | q += left; sz -= left; | |
332 | } | |
333 | while (sz >= ctx->h.r) { | |
334 | step(&ctx->h); | |
335 | squeeze(&ctx->h, q, ctx->h.r/8); | |
336 | q += ctx->h.r; sz -= ctx->h.r; | |
337 | } | |
338 | if (!sz) | |
339 | ctx->h.n = ctx->h.r; | |
340 | else { | |
341 | step(&ctx->h); | |
342 | squeeze(&ctx->h, ctx->h.buf, ctx->h.r/8); | |
343 | memcpy(q, ctx->h.buf, sz); | |
344 | ctx->h.n = sz; | |
345 | } | |
346 | } | |
347 | ||
348 | /* --- @shake_done@ --- * | |
349 | * | |
350 | * Arguments: @shake_ctx *ctx@ = context to update | |
351 | * @void *h@ = where to write the hash | |
352 | * @size_t hsz@ = size of the hash to make | |
353 | * | |
354 | * Returns: --- | |
355 | * | |
356 | * Use: Switches the context into `squeezing' state. Use @shake_get@ | |
357 | * or @shake_mask@ to extract data. | |
358 | */ | |
359 | ||
360 | void shake_done(shake_ctx *ctx, void *h, size_t hsz) | |
361 | { shake_xof(ctx); shake_get(ctx, h, hsz); ctx->st = ST_DEAD; } | |
362 | ||
363 | /*----- That's all, folks -------------------------------------------------*/ |