1 | // |
2 | // SHA3Engine.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Crypt |
6 | // Module: SHA3Engine |
7 | // |
8 | // Code of class SHA3Engine. |
9 | // |
10 | /// This class implements the SHA-3 message digest algorithm. |
11 | /// (FIPS 202, see http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) |
12 | // |
13 | // Based on the Keccak Code Package (public domain) |
14 | // https://github.com/gvanas/KeccakCodePackage |
15 | // |
16 | // Copyright (c) 2017, Applied Informatics Software Engineering GmbH |
17 | // and Contributors. |
18 | // |
19 | // SPDX-License-Identifier: BSL-1.0 |
20 | // |
21 | |
22 | #include "Poco/SHA3Engine.h" |
23 | #include <string.h> |
24 | #include <assert.h> |
25 | |
26 | namespace Poco { |
27 | |
28 | #ifdef _MSC_VER |
29 | #pragma intrinsic(memcpy) |
30 | #endif |
31 | |
32 | #if defined(__GNUC__) |
33 | #define ALIGN(x) __attribute__ ((aligned(x))) |
34 | #elif defined(_MSC_VER) |
35 | #define ALIGN(x) __declspec(align(x)) |
36 | #elif defined(__ARMCC_VERSION) |
37 | #define ALIGN(x) __align(x) |
38 | #else |
39 | #define ALIGN(x) |
40 | #endif |
41 | |
42 | #ifdef POCO_PTR_IS_64_BIT |
43 | static const UInt64 KeccakRoundConstants[24] = |
44 | { |
45 | 0x0000000000000001, |
46 | 0x0000000000008082, |
47 | 0x800000000000808a, |
48 | 0x8000000080008000, |
49 | 0x000000000000808b, |
50 | 0x0000000080000001, |
51 | 0x8000000080008081, |
52 | 0x8000000000008009, |
53 | 0x000000000000008a, |
54 | 0x0000000000000088, |
55 | 0x0000000080008009, |
56 | 0x000000008000000a, |
57 | 0x000000008000808b, |
58 | 0x800000000000008b, |
59 | 0x8000000000008089, |
60 | 0x8000000000008003, |
61 | 0x8000000000008002, |
62 | 0x8000000000000080, |
63 | 0x000000000000800a, |
64 | 0x800000008000000a, |
65 | 0x8000000080008081, |
66 | 0x8000000000008080, |
67 | 0x0000000080000001, |
68 | 0x8000000080008008, |
69 | }; |
70 | static const unsigned int KeccakRhoOffsets[25] = |
71 | { |
72 | 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 |
73 | }; |
74 | #define KeccakP1600_stateAlignment 8 |
75 | #else |
76 | static const UInt32 KeccakRoundConstants[24][2] = |
77 | { |
78 | 0x00000001, 0x00000000, |
79 | 0x00000000, 0x00000089, |
80 | 0x00000000, 0x8000008B, |
81 | 0x00000000, 0x80008080, |
82 | 0x00000001, 0x0000008B, |
83 | 0x00000001, 0x00008000, |
84 | 0x00000001, 0x80008088, |
85 | 0x00000001, 0x80000082, |
86 | 0x00000000, 0x0000000B, |
87 | 0x00000000, 0x0000000A, |
88 | 0x00000001, 0x00008082, |
89 | 0x00000000, 0x00008003, |
90 | 0x00000001, 0x0000808B, |
91 | 0x00000001, 0x8000000B, |
92 | 0x00000001, 0x8000008A, |
93 | 0x00000001, 0x80000081, |
94 | 0x00000000, 0x80000081, |
95 | 0x00000000, 0x80000008, |
96 | 0x00000000, 0x00000083, |
97 | 0x00000000, 0x80008003, |
98 | 0x00000001, 0x80008088, |
99 | 0x00000000, 0x80000088, |
100 | 0x00000001, 0x00008000, |
101 | 0x00000000, 0x80008082 |
102 | }; |
103 | |
104 | static const unsigned int KeccakRhoOffsets[25] = |
105 | { |
106 | 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 |
107 | }; |
108 | #define KeccakP1600_stateAlignment 4 |
109 | #endif |
110 | |
111 | ALIGN(KeccakP1600_stateAlignment) typedef struct KeccakWidth1600_SpongeInstanceStruct |
112 | { |
113 | unsigned char state[200]; |
114 | unsigned int rate; |
115 | unsigned int byteIOIndex; |
116 | int squeezing; |
117 | } KeccakWidth1600_SpongeInstance; |
118 | |
119 | typedef struct |
120 | { |
121 | KeccakWidth1600_SpongeInstance sponge; |
122 | unsigned int fixedOutputLength; |
123 | unsigned char delimitedSuffix; |
124 | } HASHCONTEXT; |
125 | |
126 | SHA3Engine::SHA3Engine(ALGORITHM algorithm): _context(NULL), |
127 | _algorithm(algorithm) |
128 | { |
129 | _digest.reserve(digestLength()); |
130 | reset(); |
131 | } |
132 | |
133 | SHA3Engine::~SHA3Engine() |
134 | { |
135 | reset(); |
136 | free(_context); |
137 | } |
138 | |
139 | #ifdef POCO_PTR_IS_64_BIT |
140 | void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length) |
141 | { |
142 | assert(offset < 200); |
143 | assert(offset + length <= 200); |
144 | for (unsigned int i = 0; i<length; i++) ((unsigned char *)state)[offset + i] ^= data[i]; |
145 | } |
146 | |
147 | void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset) |
148 | { |
149 | assert(offset < 200); |
150 | ((unsigned char *)state)[offset] ^= byte; |
151 | } |
152 | |
153 | #define ROL64(a, offset) ((offset != 0) ? ((((UInt64)a) << offset) ^ (((UInt64)a) >> (64-offset))) : a) |
154 | #define index(x, y) (((x)%5)+5*((y)%5)) |
155 | |
156 | static void theta(UInt64 *A) |
157 | { |
158 | unsigned int x, y; |
159 | UInt64 C[5], D[5]; |
160 | |
161 | for (x = 0; x<5; x++) { |
162 | C[x] = 0; |
163 | for (y = 0; y<5; y++) |
164 | C[x] ^= A[index(x, y)]; |
165 | } |
166 | for (x = 0; x<5; x++) |
167 | D[x] = ROL64(C[(x + 1) % 5], 1) ^ C[(x + 4) % 5]; |
168 | for (x = 0; x<5; x++) |
169 | for (y = 0; y<5; y++) |
170 | A[index(x, y)] ^= D[x]; |
171 | } |
172 | |
173 | static void rho(UInt64 *A) |
174 | { |
175 | unsigned int x, y; |
176 | |
177 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
178 | A[index(x, y)] = ROL64(A[index(x, y)], KeccakRhoOffsets[index(x, y)]); |
179 | } |
180 | |
181 | static void pi(UInt64 *A) |
182 | { |
183 | unsigned int x, y; |
184 | UInt64 tempA[25]; |
185 | |
186 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
187 | tempA[index(x, y)] = A[index(x, y)]; |
188 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
189 | A[index(0 * x + 1 * y, 2 * x + 3 * y)] = tempA[index(x, y)]; |
190 | } |
191 | |
192 | static void chi(UInt64 *A) |
193 | { |
194 | unsigned int x, y; |
195 | UInt64 C[5]; |
196 | |
197 | for (y = 0; y<5; y++) { |
198 | for (x = 0; x<5; x++) |
199 | C[x] = A[index(x, y)] ^ ((~A[index(x + 1, y)]) & A[index(x + 2, y)]); |
200 | for (x = 0; x<5; x++) |
201 | A[index(x, y)] = C[x]; |
202 | } |
203 | } |
204 | |
205 | static void iota(UInt64 *A, unsigned int indexRound) |
206 | { |
207 | A[index(0, 0)] ^= KeccakRoundConstants[indexRound]; |
208 | } |
209 | |
210 | void KeccakP1600Round(UInt64 *state, unsigned int indexRound) |
211 | { |
212 | theta(state); |
213 | rho(state); |
214 | pi(state); |
215 | chi(state); |
216 | iota(state, indexRound); |
217 | } |
218 | |
219 | static void fromBytesToWords(UInt64 *stateAsWords, const unsigned char *state) |
220 | { |
221 | unsigned int i, j; |
222 | for (i = 0; i < 25; i++) { |
223 | stateAsWords[i] = 0; |
224 | for (j = 0; j < (64 / 8); j++) |
225 | stateAsWords[i] |= (UInt64)(state[i*(64 / 8) + j]) << (8 * j); |
226 | } |
227 | } |
228 | |
229 | void KeccakP1600OnWords(UInt64 *state, unsigned int nrRounds) |
230 | { |
231 | for (unsigned int i = (24 - nrRounds); i < 24; i++) KeccakP1600Round(state, i); |
232 | } |
233 | |
234 | static void fromWordsToBytes(unsigned char *state, const UInt64 *stateAsWords) |
235 | { |
236 | unsigned int i, j; |
237 | for (i = 0; i < 25; i++) |
238 | for (j = 0; j < (64 / 8); j++) |
239 | state[i*(64 / 8) + j] = (unsigned char)((stateAsWords[i] >> (8 * j)) & 0xFF); |
240 | } |
241 | |
242 | void KeccakP1600_Permute_24rounds(void *state) |
243 | { |
244 | #ifndef POCO_ARCH_LITTLE_ENDIAN |
245 | UInt64 stateAsWords[1600 / 64]; |
246 | #endif |
247 | #ifdef POCO_ARCH_LITTLE_ENDIAN |
248 | KeccakP1600OnWords((UInt64*)state, 24); |
249 | #else |
250 | fromBytesToWords(stateAsWords, (const unsigned char *)state); |
251 | KeccakP1600OnWords(stateAsWords, 24); |
252 | fromWordsToBytes((unsigned char *)state, stateAsWords); |
253 | #endif |
254 | } |
255 | |
256 | void (const void *state, unsigned char *data, unsigned int offset, unsigned int length) |
257 | { |
258 | assert(offset < 200); |
259 | assert(offset + length <= 200); |
260 | memcpy(data, (unsigned char*)state + offset, length); |
261 | } |
262 | #else |
263 | void toBitInterleaving(UInt32 low, UInt32 high, UInt32 *even, UInt32 *odd) |
264 | { |
265 | unsigned int i; |
266 | |
267 | *even = 0; |
268 | *odd = 0; |
269 | for (i = 0; i<64; i++) { |
270 | unsigned int inBit; |
271 | if (i < 32) |
272 | inBit = (low >> i) & 1; |
273 | else |
274 | inBit = (high >> (i - 32)) & 1; |
275 | if ((i % 2) == 0) |
276 | *even |= inBit << (i / 2); |
277 | else |
278 | *odd |= inBit << ((i - 1) / 2); |
279 | } |
280 | } |
281 | |
282 | void fromBitInterleaving(UInt32 even, UInt32 odd, UInt32 *low, UInt32 *high) |
283 | { |
284 | unsigned int i; |
285 | |
286 | *low = 0; |
287 | *high = 0; |
288 | for (i = 0; i<64; i++) { |
289 | unsigned int inBit; |
290 | if ((i % 2) == 0) |
291 | inBit = (even >> (i / 2)) & 1; |
292 | else |
293 | inBit = (odd >> ((i - 1) / 2)) & 1; |
294 | if (i < 32) |
295 | *low |= inBit << i; |
296 | else |
297 | *high |= inBit << (i - 32); |
298 | } |
299 | } |
300 | |
301 | void KeccakP1600_AddBytesInLane(void *state, unsigned int lanePosition, const unsigned char *data, unsigned int offset, unsigned int length) |
302 | { |
303 | if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) { |
304 | UInt8 laneAsBytes[8]; |
305 | UInt32 low, high; |
306 | UInt32 lane[2]; |
307 | UInt32 *stateAsHalfLanes; |
308 | |
309 | memset(laneAsBytes, 0, 8); |
310 | memcpy(laneAsBytes + offset, data, length); |
311 | low = laneAsBytes[0] |
312 | | ((UInt32)(laneAsBytes[1]) << 8) |
313 | | ((UInt32)(laneAsBytes[2]) << 16) |
314 | | ((UInt32)(laneAsBytes[3]) << 24); |
315 | high = laneAsBytes[4] |
316 | | ((UInt32)(laneAsBytes[5]) << 8) |
317 | | ((UInt32)(laneAsBytes[6]) << 16) |
318 | | ((UInt32)(laneAsBytes[7]) << 24); |
319 | toBitInterleaving(low, high, lane, lane + 1); |
320 | stateAsHalfLanes = (UInt32*)state; |
321 | stateAsHalfLanes[lanePosition * 2 + 0] ^= lane[0]; |
322 | stateAsHalfLanes[lanePosition * 2 + 1] ^= lane[1]; |
323 | } |
324 | } |
325 | |
326 | void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length) |
327 | { |
328 | unsigned int lanePosition = offset / 8; |
329 | unsigned int offsetInLane = offset % 8; |
330 | |
331 | assert(offset < 200); |
332 | assert(offset + length <= 200); |
333 | while (length > 0) { |
334 | unsigned int bytesInLane = 8 - offsetInLane; |
335 | if (bytesInLane > length) |
336 | bytesInLane = length; |
337 | KeccakP1600_AddBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane); |
338 | length -= bytesInLane; |
339 | lanePosition++; |
340 | offsetInLane = 0; |
341 | data += bytesInLane; |
342 | } |
343 | } |
344 | |
345 | void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset) |
346 | { |
347 | unsigned char data[1]; |
348 | assert(offset < 200); |
349 | data[0] = byte; |
350 | KeccakP1600_AddBytes(state, data, offset, 1); |
351 | } |
352 | |
353 | #define ROL32(a, offset) ((offset != 0) ? ((((UInt32)a) << offset) ^ (((UInt32)a) >> (32-offset))) : a) |
354 | #define index(x, y,z) ((((x)%5)+5*((y)%5))*2 + z) |
355 | void ROL64(UInt32 inEven, UInt32 inOdd, UInt32 *outEven, UInt32 *outOdd, unsigned int offset) |
356 | { |
357 | if ((offset % 2) == 0) { |
358 | *outEven = ROL32(inEven, offset / 2); |
359 | *outOdd = ROL32(inOdd, offset / 2); |
360 | } |
361 | else { |
362 | *outEven = ROL32(inOdd, (offset + 1) / 2); |
363 | *outOdd = ROL32(inEven, (offset - 1) / 2); |
364 | } |
365 | } |
366 | |
367 | static void theta(UInt32 *A) |
368 | { |
369 | unsigned int x, y, z; |
370 | UInt32 C[5][2], D[5][2]; |
371 | for (x = 0; x<5; x++) { |
372 | for (z = 0; z<2; z++) { |
373 | C[x][z] = 0; |
374 | for (y = 0; y<5; y++) |
375 | C[x][z] ^= A[index(x, y, z)]; |
376 | } |
377 | } |
378 | for (x = 0; x<5; x++) { |
379 | ROL64(C[(x + 1) % 5][0], C[(x + 1) % 5][1], &(D[x][0]), &(D[x][1]), 1); |
380 | for (z = 0; z<2; z++) |
381 | D[x][z] ^= C[(x + 4) % 5][z]; |
382 | } |
383 | for (x = 0; x<5; x++) |
384 | for (y = 0; y<5; y++) |
385 | for (z = 0; z<2; z++) |
386 | A[index(x, y, z)] ^= D[x][z]; |
387 | } |
388 | |
389 | static void rho(UInt32 *A) |
390 | { |
391 | unsigned int x, y; |
392 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
393 | ROL64(A[index(x, y, 0)], A[index(x, y, 1)], &(A[index(x, y, 0)]), &(A[index(x, y, 1)]), KeccakRhoOffsets[5 * y + x]); |
394 | } |
395 | |
396 | static void pi(UInt32 *A) |
397 | { |
398 | unsigned int x, y, z; |
399 | UInt32 tempA[50]; |
400 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++) |
401 | tempA[index(x, y, z)] = A[index(x, y, z)]; |
402 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++) |
403 | A[index(0 * x + 1 * y, 2 * x + 3 * y, z)] = tempA[index(x, y, z)]; |
404 | } |
405 | |
406 | static void chi(UInt32 *A) |
407 | { |
408 | unsigned int x, y, z; |
409 | UInt32 C[5][2]; |
410 | for (y = 0; y<5; y++) { |
411 | for (x = 0; x<5; x++) |
412 | for (z = 0; z<2; z++) |
413 | C[x][z] = A[index(x, y, z)] ^ ((~A[index(x + 1, y, z)]) & A[index(x + 2, y, z)]); |
414 | for (x = 0; x<5; x++) |
415 | for (z = 0; z<2; z++) |
416 | A[index(x, y, z)] = C[x][z]; |
417 | } |
418 | } |
419 | |
420 | static void iota(UInt32 *A, unsigned int indexRound) |
421 | { |
422 | A[index(0, 0, 0)] ^= KeccakRoundConstants[indexRound][0]; |
423 | A[index(0, 0, 1)] ^= KeccakRoundConstants[indexRound][1]; |
424 | } |
425 | |
426 | void KeccakP1600_PermutationOnWords(UInt32 *state, unsigned int nrRounds) |
427 | { |
428 | for (unsigned int i = (24 - nrRounds); i < 24; i++) |
429 | { |
430 | theta(state); |
431 | rho(state); |
432 | pi(state); |
433 | chi(state); |
434 | iota(state, i); |
435 | } |
436 | } |
437 | |
438 | void KeccakP1600_ExtractBytesInLane(const void *state, unsigned int lanePosition, unsigned char *data, unsigned int offset, unsigned int length) |
439 | { |
440 | if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) { |
441 | UInt32 *stateAsHalfLanes = (UInt32*)state; |
442 | UInt32 lane[2]; |
443 | UInt8 laneAsBytes[8]; |
444 | fromBitInterleaving(stateAsHalfLanes[lanePosition * 2], stateAsHalfLanes[lanePosition * 2 + 1], lane, lane + 1); |
445 | laneAsBytes[0] = lane[0] & 0xFF; |
446 | laneAsBytes[1] = (lane[0] >> 8) & 0xFF; |
447 | laneAsBytes[2] = (lane[0] >> 16) & 0xFF; |
448 | laneAsBytes[3] = (lane[0] >> 24) & 0xFF; |
449 | laneAsBytes[4] = lane[1] & 0xFF; |
450 | laneAsBytes[5] = (lane[1] >> 8) & 0xFF; |
451 | laneAsBytes[6] = (lane[1] >> 16) & 0xFF; |
452 | laneAsBytes[7] = (lane[1] >> 24) & 0xFF; |
453 | memcpy(data, laneAsBytes + offset, length); |
454 | } |
455 | } |
456 | |
457 | void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length) |
458 | { |
459 | unsigned int lanePosition = offset / 8; |
460 | unsigned int offsetInLane = offset % 8; |
461 | |
462 | assert(offset < 200); |
463 | assert(offset + length <= 200); |
464 | while (length > 0) { |
465 | unsigned int bytesInLane = 8 - offsetInLane; |
466 | if (bytesInLane > length) |
467 | bytesInLane = length; |
468 | KeccakP1600_ExtractBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane); |
469 | length -= bytesInLane; |
470 | lanePosition++; |
471 | offsetInLane = 0; |
472 | data += bytesInLane; |
473 | } |
474 | } |
475 | |
476 | void KeccakP1600_Permute_24rounds(void *state) |
477 | { |
478 | UInt32 *stateAsHalfLanes = (UInt32*)state; |
479 | { |
480 | UInt8 stateAsBytes[1600 / 8]; |
481 | KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8); |
482 | } |
483 | KeccakP1600_PermutationOnWords(stateAsHalfLanes, 24); |
484 | { |
485 | UInt8 stateAsBytes[1600 / 8]; |
486 | KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8); |
487 | } |
488 | } |
489 | #endif |
490 | |
491 | void SHA3Engine::updateImpl(const void* buffer_, std::size_t count) |
492 | { |
493 | if (_context == NULL || buffer_ == NULL || count == 0) return; |
494 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; |
495 | size_t j; |
496 | unsigned int partialBlock; |
497 | unsigned int rateInBytes = (&pContext->sponge)->rate / 8; |
498 | if ((&pContext->sponge)->squeezing) return; |
499 | size_t i = 0; |
500 | const unsigned char *curData = (const unsigned char *)buffer_; |
501 | while (i < count) { |
502 | if (((&pContext->sponge)->byteIOIndex == 0) && (count >= (i + rateInBytes))) { |
503 | for (j = count - i; j >= rateInBytes; j -= rateInBytes) { |
504 | KeccakP1600_AddBytes((&pContext->sponge)->state, curData, 0, rateInBytes); |
505 | KeccakP1600_Permute_24rounds((&pContext->sponge)->state); |
506 | curData += rateInBytes; |
507 | } |
508 | i = count - j; |
509 | } |
510 | else { |
511 | partialBlock = (unsigned int)(count - i); |
512 | if (partialBlock + (&pContext->sponge)->byteIOIndex > rateInBytes) |
513 | partialBlock = rateInBytes - (&pContext->sponge)->byteIOIndex; |
514 | i += partialBlock; |
515 | |
516 | KeccakP1600_AddBytes((&pContext->sponge)->state, curData, (&pContext->sponge)->byteIOIndex, partialBlock); |
517 | curData += partialBlock; |
518 | (&pContext->sponge)->byteIOIndex += partialBlock; |
519 | if ((&pContext->sponge)->byteIOIndex == rateInBytes) { |
520 | KeccakP1600_Permute_24rounds((&pContext->sponge)->state); |
521 | (&pContext->sponge)->byteIOIndex = 0; |
522 | } |
523 | } |
524 | } |
525 | } |
526 | |
527 | std::size_t SHA3Engine::digestLength() const |
528 | { |
529 | return (size_t)((int)_algorithm / 8); |
530 | } |
531 | |
532 | int KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance *instance, unsigned int rate, unsigned int capacity) |
533 | { |
534 | if (rate + capacity != 1600) return 1; |
535 | if ((rate <= 0) || (rate > 1600) || ((rate % 8) != 0)) return 1; |
536 | memset(instance->state, 0, 1600 / 8); |
537 | instance->rate = rate; |
538 | instance->byteIOIndex = 0; |
539 | instance->squeezing = 0; |
540 | return 0; |
541 | } |
542 | |
543 | void SHA3Engine::reset() |
544 | { |
545 | if (_context != NULL) free(_context); |
546 | _context = calloc(1, sizeof(HASHCONTEXT)); |
547 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; |
548 | switch (_algorithm) |
549 | { |
550 | case SHA3_224: |
551 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1152, 448); |
552 | pContext->fixedOutputLength = 224; |
553 | pContext->delimitedSuffix = 0x06; |
554 | break; |
555 | case SHA3_256: |
556 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1088, 512); |
557 | pContext->fixedOutputLength = 256; |
558 | pContext->delimitedSuffix = 0x06; |
559 | break; |
560 | case SHA3_384: |
561 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 832, 768); |
562 | pContext->fixedOutputLength = 384; |
563 | pContext->delimitedSuffix = 0x06; |
564 | break; |
565 | default: |
566 | case SHA3_512: |
567 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 576, 1024); |
568 | pContext->fixedOutputLength = 512; |
569 | pContext->delimitedSuffix = 0x06; |
570 | break; |
571 | } |
572 | } |
573 | |
574 | int KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData) |
575 | { |
576 | unsigned int rateInBytes = instance->rate / 8; |
577 | |
578 | if (delimitedData == 0) |
579 | return 1; |
580 | if (instance->squeezing) |
581 | return 1; /* Too late for additional input */ |
582 | |
583 | /* Last few bits, whose delimiter coincides with first bit of padding */ |
584 | KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex); |
585 | /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ |
586 | if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1))) |
587 | KeccakP1600_Permute_24rounds(instance->state); |
588 | /* Second bit of padding */ |
589 | KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1); |
590 | KeccakP1600_Permute_24rounds(instance->state); |
591 | instance->byteIOIndex = 0; |
592 | instance->squeezing = 1; |
593 | return 0; |
594 | } |
595 | |
596 | int SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData) |
597 | { |
598 | unsigned int rateInBytes = instance->rate / 8; |
599 | if (delimitedData == 0) return 1; |
600 | if (instance->squeezing) return 1; /* Too late for additional input */ |
601 | /* Last few bits, whose delimiter coincides with first bit of padding */ |
602 | KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex); |
603 | /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ |
604 | if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1))) |
605 | KeccakP1600_Permute_24rounds(instance->state); |
606 | /* Second bit of padding */ |
607 | KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1); |
608 | KeccakP1600_Permute_24rounds(instance->state); |
609 | instance->byteIOIndex = 0; |
610 | instance->squeezing = 1; |
611 | return 0; |
612 | } |
613 | |
614 | int KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance *instance, unsigned char *data, size_t dataByteLen) |
615 | { |
616 | size_t i, j; |
617 | unsigned int partialBlock; |
618 | unsigned int rateInBytes = instance->rate / 8; |
619 | unsigned char *curData; |
620 | |
621 | if (!instance->squeezing) |
622 | SpongeAbsorbLastFewBits(instance, 0x01); |
623 | |
624 | i = 0; |
625 | curData = data; |
626 | while (i < dataByteLen) { |
627 | if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { |
628 | for (j = dataByteLen - i; j >= rateInBytes; j -= rateInBytes) { |
629 | KeccakP1600_Permute_24rounds(instance->state); |
630 | KeccakP1600_ExtractBytes(instance->state, curData, 0, rateInBytes); |
631 | curData += rateInBytes; |
632 | } |
633 | i = dataByteLen - j; |
634 | } |
635 | else { |
636 | /* normal lane: using the message queue */ |
637 | if (instance->byteIOIndex == rateInBytes) { |
638 | KeccakP1600_Permute_24rounds(instance->state); |
639 | instance->byteIOIndex = 0; |
640 | } |
641 | partialBlock = (unsigned int)(dataByteLen - i); |
642 | if (partialBlock + instance->byteIOIndex > rateInBytes) |
643 | partialBlock = rateInBytes - instance->byteIOIndex; |
644 | i += partialBlock; |
645 | |
646 | KeccakP1600_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); |
647 | curData += partialBlock; |
648 | instance->byteIOIndex += partialBlock; |
649 | } |
650 | } |
651 | return 0; |
652 | } |
653 | |
654 | const DigestEngine::Digest& SHA3Engine::digest() |
655 | { |
656 | _digest.clear(); |
657 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; |
658 | unsigned char hash[64]; |
659 | memset(hash, 0, 64); |
660 | if (KeccakWidth1600_SpongeAbsorbLastFewBits(&pContext->sponge, pContext->delimitedSuffix) == 0) |
661 | KeccakWidth1600_SpongeSqueeze(&pContext->sponge, hash, pContext->fixedOutputLength / 8); |
662 | _digest.insert(_digest.begin(), hash, hash + digestLength()); |
663 | reset(); |
664 | return _digest; |
665 | } |
666 | |
667 | } // namespace Poco |
668 | |