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 | ||
198 | static void rightenc_sz(shake_ctx *ctx, size_t n) | |
199 | { | |
200 | kludge64 t; | |
201 | octet b[9]; | |
202 | unsigned i; | |
203 | ||
204 | SET64(t, ((n&~(size_t)MASK32) >> 16) >> 16, n&MASK32); | |
205 | STORE64_B_(b, t); | |
206 | for (i = 0; i < 7 && !b[i]; i++); | |
207 | b[8] = 8 - i; | |
208 | shake_hash(ctx, b + i, 9 - i); | |
209 | } | |
210 | ||
211 | static void stringenc(shake_ctx *ctx, const void *p, size_t sz) | |
212 | { leftenc_sz(ctx, 8*sz); if (sz) shake_hash(ctx, p, sz); } | |
213 | ||
214 | static void bytepad_before(shake_ctx *ctx) | |
215 | { leftenc_sz(ctx, ctx->h.r); } | |
216 | ||
217 | static void bytepad_after(shake_ctx *ctx) | |
218 | { | |
219 | unsigned pad; | |
220 | ||
221 | if (ctx->h.n%8) { | |
222 | pad = 8 - ctx->h.n%8; | |
223 | memset(ctx->h.buf + ctx->h.n, 0, pad); | |
224 | ctx->h.n += pad; | |
225 | } | |
226 | if (ctx->h.n) { | |
227 | absorb(&ctx->h, ctx->h.buf, ctx->h.n/8); | |
228 | step(&ctx->h); ctx->h.n = 0; | |
229 | } | |
230 | } | |
231 | ||
232 | /* --- @cshake{128,256}_init@ --- * | |
233 | * | |
234 | * Arguments: @shake_ctx *ctx@ = pointer to context to initialize | |
235 | * @const void *func@ = NIST-allocated function name | |
236 | * @size_t fsz@ = length of function name | |
237 | * @const void *perso@ = user personalization string | |
238 | * @size_t psz@ = length of personalization string | |
239 | * | |
240 | * Returns: --- | |
241 | * | |
242 | * Use: Initializes a cSHAKE context. The context is initially in | |
243 | * the `absorbing' state: feed it data with @shake_hash@. | |
244 | */ | |
245 | ||
246 | static void init_shake(shake_ctx *ctx, unsigned c0, | |
247 | const void *func, size_t fsz, | |
248 | const void *perso, size_t psz) | |
249 | { | |
250 | keccak1600_init(&ctx->h.s); ctx->st = ST_ABSORB; | |
251 | ctx->h.r = (1600 - 2*c0)/8; ctx->h.w = 0; ctx->h.n = 0; | |
252 | if (!fsz && !psz) | |
253 | ctx->op = OP_SHAKE; | |
254 | else { | |
255 | bytepad_before(ctx); | |
256 | stringenc(ctx, func, fsz); | |
257 | stringenc(ctx, perso, psz); | |
258 | bytepad_after(ctx); | |
259 | ctx->op = OP_CSHAKE; | |
260 | } | |
261 | } | |
262 | ||
263 | void cshake128_init(shake_ctx *ctx, | |
264 | const void *func, size_t fsz, | |
265 | const void *perso, size_t psz) | |
266 | { init_shake(ctx, 128, func, fsz, perso, psz); } | |
267 | ||
268 | void cshake256_init(shake_ctx *ctx, | |
269 | const void *func, size_t fsz, | |
270 | const void *perso, size_t psz) | |
271 | { init_shake(ctx, 256, func, fsz, perso, psz); } | |
272 | ||
273 | /* --- @shake{128,256}_init@ --- * | |
274 | * | |
275 | * Arguments: @sha3_ctx *ctx@ = pointer to context to initialize | |
276 | * | |
277 | * Returns: --- | |
278 | * | |
279 | * Use: Initializes a SHAKE context. The context is initially in | |
280 | * the `absorbing' state: feed it data with @shake_hash@. | |
281 | */ | |
282 | ||
283 | void shake128_init(shake_ctx *ctx) { init_shake(ctx, 128, 0, 0, 0, 0); } | |
284 | void shake256_init(shake_ctx *ctx) { init_shake(ctx, 256, 0, 0, 0, 0); } | |
285 | ||
286 | /* --- @shake_hash@ --- * | |
287 | * | |
288 | * Arguments: @shake_ctx *ctx@ = context to update | |
289 | * @const void *p@ = input buffer | |
290 | * @size_t sz@ = size of input | |
291 | * | |
292 | * Returns: --- | |
293 | * | |
294 | * Use: Feeds input data into a SHAKE context. The context must be | |
295 | * in `absorbing' state. | |
296 | */ | |
297 | ||
298 | void shake_hash(shake_ctx *ctx, const void *p, size_t sz) | |
299 | { assert(ctx->st == ST_ABSORB); sha3_hash(&ctx->h, p, sz); } | |
300 | ||
301 | /* --- @shake_xof@ --- * | |
302 | * | |
303 | * Arguments: @shake_ctx *ctx@ = context to update | |
304 | * | |
305 | * Returns: --- | |
306 | * | |
307 | * Use: Switches the context into `squeezing' state. Use @shake_get@ | |
308 | * or @shake_mask@ to extract data. | |
309 | */ | |
310 | ||
311 | void shake_xof(shake_ctx *ctx) | |
312 | { | |
313 | assert(ctx->st == ST_ABSORB); | |
314 | pad(&ctx->h, ctx->op, 0x80); | |
315 | ctx->st = ST_SQUEEZE; | |
316 | ctx->h.n = ctx->h.r; | |
317 | } | |
318 | ||
319 | /* --- @shake_get@ --- * | |
320 | * | |
321 | * Arguments: @shake_ctx *ctx@ = context to update | |
322 | * @void *p@ = output buffer | |
323 | * @size_t sz@ = size of output | |
324 | * | |
325 | * Returns: --- | |
326 | * | |
327 | * Use: Extracts output from a SHAKE context. The context must be | |
328 | * in `squeezing' state. | |
329 | */ | |
330 | ||
331 | void shake_get(shake_ctx *ctx, void *p, size_t sz) | |
332 | { | |
333 | octet *q = p; | |
334 | size_t left = ctx->h.r - ctx->h.n; | |
335 | ||
336 | assert(ctx->st == ST_SQUEEZE); | |
337 | if (left >= sz) { | |
338 | memcpy(q, ctx->h.buf + ctx->h.n, sz); | |
339 | ctx->h.n += sz; | |
340 | return; | |
341 | } | |
342 | if (left) { | |
343 | memcpy(q, ctx->h.buf + ctx->h.n, left); | |
344 | q += left; sz -= left; | |
345 | } | |
346 | while (sz >= ctx->h.r) { | |
347 | step(&ctx->h); | |
348 | squeeze(&ctx->h, q, ctx->h.r/8); | |
349 | q += ctx->h.r; sz -= ctx->h.r; | |
350 | } | |
351 | if (!sz) | |
352 | ctx->h.n = ctx->h.r; | |
353 | else { | |
354 | step(&ctx->h); | |
355 | squeeze(&ctx->h, ctx->h.buf, ctx->h.r/8); | |
356 | memcpy(q, ctx->h.buf, sz); | |
357 | ctx->h.n = sz; | |
358 | } | |
359 | } | |
360 | ||
361 | /* --- @shake_done@ --- * | |
362 | * | |
363 | * Arguments: @shake_ctx *ctx@ = context to update | |
364 | * @void *h@ = where to write the hash | |
365 | * @size_t hsz@ = size of the hash to make | |
366 | * | |
367 | * Returns: --- | |
368 | * | |
369 | * Use: Switches the context into `squeezing' state. Use @shake_get@ | |
370 | * or @shake_mask@ to extract data. | |
371 | */ | |
372 | ||
373 | void shake_done(shake_ctx *ctx, void *h, size_t hsz) | |
374 | { shake_xof(ctx); shake_get(ctx, h, hsz); ctx->st = ST_DEAD; } | |
375 | ||
376 | /*----- That's all, folks -------------------------------------------------*/ |